2 * A large chunk of this file appears to be copied directly from
3 * sys/nfsclient/nfs_bio.c, which has the following license:
6 * Copyright (c) 1989, 1993
7 * The Regents of the University of California. All rights reserved.
9 * This code is derived from software contributed to Berkeley by
10 * Rick Macklem at The University of Guelph.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * @(#)nfs_bio.c 8.9 (Berkeley) 3/30/95
43 * Pursuant to a statement of U.C. Berkeley dated 1999-07-22, this license
44 * is amended to drop clause (3) above.
47 #include <afsconfig.h>
48 #include <afs/param.h>
51 #include <afs/sysincludes.h> /* Standard vendor system headers */
52 #include <afsincludes.h> /* Afs-based standard headers */
53 #include <afs/afs_stats.h> /* statistics */
54 #include <sys/malloc.h>
55 #include <sys/namei.h>
56 #include <sys/unistd.h>
57 #if __FreeBSD_version >= 1000030
58 #include <sys/rwlock.h>
60 #include <vm/vm_page.h>
61 #include <vm/vm_object.h>
62 #include <vm/vm_pager.h>
63 #include <vm/vnode_pager.h>
64 #include <sys/vmmeter.h>
65 extern int afs_pbuf_freecnt;
68 struct componentname *cnp = ap->a_cnp; \
70 name = malloc(cnp->cn_namelen+1, M_TEMP, M_WAITOK); \
71 memcpy(name, cnp->cn_nameptr, cnp->cn_namelen); \
72 name[cnp->cn_namelen] = '\0'
74 #define DROPNAME() free(name, M_TEMP)
77 # define AFS_LINK_MAX LINK_MAX
79 # define AFS_LINK_MAX (32767)
83 * Here we define compatibility functions/macros for interfaces that
84 * have changed between different FreeBSD versions.
86 static __inline void ma_vm_page_lock_queues(void) {};
87 static __inline void ma_vm_page_unlock_queues(void) {};
88 static __inline void ma_vm_page_lock(vm_page_t m) { vm_page_lock(m); };
89 static __inline void ma_vm_page_unlock(vm_page_t m) { vm_page_unlock(m); };
91 #if __FreeBSD_version >= 1000030
92 #define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_WLOCK(o)
93 #define AFS_VM_OBJECT_WUNLOCK(o) VM_OBJECT_WUNLOCK(o)
95 #define AFS_VM_OBJECT_WLOCK(o) VM_OBJECT_LOCK(o)
96 #define AFS_VM_OBJECT_WUNLOCK(o) VM_OBJECT_UNLOCK(o)
100 # define AFS_VM_CNT_ADD(var, x) VM_CNT_ADD(var, x)
101 # define AFS_VM_CNT_INC(var) VM_CNT_INC(var)
103 # define AFS_VM_CNT_ADD(var, x) PCPU_ADD(cnt.var, x)
104 # define AFS_VM_CNT_INC(var) PCPU_INC(cnt.var)
108 * Mosty copied from sys/ufs/ufs/ufs_vnops.c:ufs_pathconf().
109 * We should know the correct answers to these questions with
110 * respect to the AFS protocol (which may differ from the UFS
111 * values) but for the moment this will do.
114 afs_vop_pathconf(struct vop_pathconf_args *ap)
119 switch (ap->a_name) {
121 *ap->a_retval = AFS_LINK_MAX;
124 *ap->a_retval = NAME_MAX;
127 *ap->a_retval = PATH_MAX;
130 *ap->a_retval = PIPE_BUF;
132 case _PC_CHOWN_RESTRICTED:
138 #ifdef _PC_ACL_EXTENDED
139 case _PC_ACL_EXTENDED:
142 case _PC_ACL_PATH_MAX:
146 #ifdef _PC_MAC_PRESENT
147 case _PC_MAC_PRESENT:
153 /* _PC_ASYNC_IO should have been handled by upper layers. */
154 KASSERT(0, ("_PC_ASYNC_IO should not get here"));
164 #ifdef _PC_ALLOC_SIZE_MIN
165 case _PC_ALLOC_SIZE_MIN:
166 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_bsize;
169 #ifdef _PC_FILESIZEBITS
170 case _PC_FILESIZEBITS:
171 *ap->a_retval = 32; /* XXX */
174 #ifdef _PC_REC_INCR_XFER_SIZE
175 case _PC_REC_INCR_XFER_SIZE:
176 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
178 case _PC_REC_MAX_XFER_SIZE:
179 *ap->a_retval = -1; /* means ``unlimited'' */
181 case _PC_REC_MIN_XFER_SIZE:
182 *ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_iosize;
184 case _PC_REC_XFER_ALIGN:
185 *ap->a_retval = PAGE_SIZE;
188 #ifdef _PC_SYMLINK_MAX
189 case _PC_SYMLINK_MAX:
190 *ap->a_retval = MAXPATHLEN;
202 struct vop_lookup_args /* {
203 * struct vnodeop_desc * a_desc;
204 * struct vnode *a_dvp;
205 * struct vnode **a_vpp;
206 * struct componentname *a_cnp;
211 struct vnode *vp, *dvp;
212 int flags = ap->a_cnp->cn_flags;
215 if (dvp->v_type != VDIR) {
219 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
224 #if __FreeBSD_version < 1000021
225 cnp->cn_flags |= MPSAFE; /* steel */
231 * - 'dvp' is locked by our caller. We must return it locked, whether we
232 * return success or error.
234 * - If the lookup succeeds, 'vp' must be locked before we return.
236 * - If we lock multiple vnodes, parent vnodes must be locked before
239 * As a result, looking up the parent directory (if 'flags' has ISDOTDOT
240 * set) is a bit of a special case. In that case, we must unlock 'dvp'
241 * before performing the lookup, since the lookup operation may lock the
242 * target vnode, and the target vnode is the parent of 'dvp' (so we must
243 * lock 'dvp' after locking the target vnode).
246 if (flags & ISDOTDOT)
250 error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
254 if (flags & ISDOTDOT)
255 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
256 if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME)
257 && (flags & ISLASTCN) && error == ENOENT)
259 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
260 cnp->cn_flags |= SAVENAME;
265 vp = AFSTOV(vcp); /* always get a node if no error */
267 if (flags & ISDOTDOT) {
268 /* Must lock 'vp' before 'dvp', since 'vp' is the parent vnode. */
269 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
270 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
271 } else if (vp == dvp) {
272 /* they're the same; afs_lookup() already ref'ed the leaf.
273 * It came in locked, so we don't need to ref OR lock it */
275 vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE | LK_RETRY);
279 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
280 cnp->cn_flags |= SAVENAME;
288 struct vop_create_args /* {
289 * struct vnode *a_dvp;
290 * struct vnode **a_vpp;
291 * struct componentname *a_cnp;
292 * struct vattr *a_vap;
297 struct vnode *dvp = ap->a_dvp;
302 afs_create(VTOAFS(dvp), name, ap->a_vap,
303 ap->a_vap->va_vaflags & VA_EXCLUSIVE ? EXCL : NONEXCL,
304 ap->a_vap->va_mode, &vcp, cnp->cn_cred);
312 *ap->a_vpp = AFSTOV(vcp);
313 vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY);
323 struct vop_mknod_args /* {
324 * struct vnode *a_dvp;
325 * struct vnode **a_vpp;
326 * struct componentname *a_cnp;
327 * struct vattr *a_vap;
335 struct vop_open_args /* {
336 * struct vnode *a_vp;
338 * struct ucred *a_cred;
339 * struct thread *a_td;
344 struct vcache *vc = VTOAFS(ap->a_vp);
347 error = afs_open(&vc, ap->a_mode, ap->a_cred);
349 if (AFSTOV(vc) != ap->a_vp)
350 panic("AFS open changed vnode!");
353 vnode_create_vobject(ap->a_vp, vc->f.m.Length, ap->a_td);
354 osi_FlushPages(vc, ap->a_cred);
360 struct vop_close_args /* {
361 * struct vnode *a_vp;
363 * struct ucred *a_cred;
364 * struct thread *a_td;
368 struct vnode *vp = ap->a_vp;
369 struct vcache *avc = VTOAFS(vp);
372 iflag = vp->v_iflag & VI_DOOMED;
374 if (iflag & VI_DOOMED) {
375 /* osi_FlushVCache (correctly) calls vgone() on recycled vnodes, we don't
376 * have an afs_close to process, in that case */
378 panic("afs_vop_close: doomed vnode %p has vcache %p with non-zero opens %d\n",
379 vp, avc, avc->opens);
385 code = afs_close(avc, ap->a_fflag, ap->a_cred);
387 code = afs_close(avc, ap->a_fflag, afs_osi_credp);
388 osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */
390 ObtainWriteLock(&avc->lock, 808);
391 if (avc->cred != NULL) {
395 ReleaseWriteLock(&avc->lock);
403 struct vop_access_args /* {
404 * struct vnode *a_vp;
405 * accmode_t a_accmode;
406 * struct ucred *a_cred;
407 * struct thread *a_td;
412 code = afs_access(VTOAFS(ap->a_vp), ap->a_accmode, ap->a_cred);
419 struct vop_getattr_args /* {
420 * struct vnode *a_vp;
421 * struct vattr *a_vap;
422 * struct ucred *a_cred;
428 code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
436 struct vop_setattr_args /* {
437 * struct vnode *a_vp;
438 * struct vattr *a_vap;
439 * struct ucred *a_cred;
444 code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, ap->a_cred);
451 struct vop_read_args /* {
452 * struct vnode *a_vp;
455 * struct ucred *a_cred;
460 struct vcache *avc = VTOAFS(ap->a_vp);
462 osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */
463 code = afs_read(avc, ap->a_uio, ap->a_cred, 0);
468 /* struct vop_getpages_args {
469 * struct vnode *a_vp;
477 afs_vop_getpages(struct vop_getpages_args *ap)
480 int i, nextoff, size, toff, npages, count;
490 memset(&uio, 0, sizeof(uio));
491 memset(&iov, 0, sizeof(iov));
496 #ifdef FBSD_VOP_GETPAGES_BUSIED
497 npages = ap->a_count;
503 npages = btoc(ap->a_count);
506 if ((object = vp->v_object) == NULL) {
507 printf("afs_getpages: called with non-merged cache vnode??\n");
508 return VM_PAGER_ERROR;
512 * If the requested page is partially valid, just return it and
513 * allow the pager to zero-out the blanks. Partially valid pages
514 * can only occur at the file EOF.
517 #ifdef FBSD_VOP_GETPAGES_BUSIED
518 AFS_VM_OBJECT_WLOCK(object);
519 ma_vm_page_lock_queues();
520 if(pages[npages - 1]->valid != 0) {
522 ma_vm_page_unlock_queues();
523 AFS_VM_OBJECT_WUNLOCK(object);
524 return (VM_PAGER_OK);
528 vm_page_t m = pages[ap->a_reqpage];
529 AFS_VM_OBJECT_WLOCK(object);
530 ma_vm_page_lock_queues();
532 /* handled by vm_fault now */
533 /* vm_page_zero_invalid(m, TRUE); */
534 for (i = 0; i < npages; ++i) {
535 if (i != ap->a_reqpage) {
536 ma_vm_page_lock(pages[i]);
537 vm_page_free(pages[i]);
538 ma_vm_page_unlock(pages[i]);
541 ma_vm_page_unlock_queues();
542 AFS_VM_OBJECT_WUNLOCK(object);
546 ma_vm_page_unlock_queues();
547 AFS_VM_OBJECT_WUNLOCK(object);
549 bp = getpbuf(&afs_pbuf_freecnt);
551 kva = (vm_offset_t) bp->b_data;
552 pmap_qenter(kva, pages, npages);
553 AFS_VM_CNT_INC(v_vnodein);
554 AFS_VM_CNT_ADD(v_vnodepgsin, npages);
556 #ifdef FBSD_VOP_GETPAGES_BUSIED
557 count = ctob(npages);
561 iov.iov_base = (caddr_t) kva;
565 uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
566 uio.uio_resid = count;
567 uio.uio_segflg = UIO_SYSSPACE;
568 uio.uio_rw = UIO_READ;
569 uio.uio_td = curthread;
572 osi_FlushPages(avc, osi_curcred()); /* hold GLOCK, but not basic vnode lock */
573 code = afs_read(avc, &uio, osi_curcred(), 0);
575 pmap_qremove(kva, npages);
577 relpbuf(bp, &afs_pbuf_freecnt);
579 if (code && (uio.uio_resid == count)) {
580 #ifndef FBSD_VOP_GETPAGES_BUSIED
581 AFS_VM_OBJECT_WLOCK(object);
582 ma_vm_page_lock_queues();
583 for (i = 0; i < npages; ++i) {
584 if (i != ap->a_reqpage)
585 vm_page_free(pages[i]);
587 ma_vm_page_unlock_queues();
588 AFS_VM_OBJECT_WUNLOCK(object);
590 return VM_PAGER_ERROR;
593 size = count - uio.uio_resid;
594 AFS_VM_OBJECT_WLOCK(object);
595 ma_vm_page_lock_queues();
596 for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
598 nextoff = toff + PAGE_SIZE;
601 /* XXX not in nfsclient? */
602 m->flags &= ~PG_ZERO;
604 if (nextoff <= size) {
606 * Read operation filled an entire page
608 m->valid = VM_PAGE_BITS_ALL;
609 KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m));
610 } else if (size > toff) {
612 * Read operation filled a partial page.
615 vm_page_set_validclean(m, 0, size - toff);
616 KASSERT(m->dirty == 0, ("afs_getpages: page %p is dirty", m));
619 #ifndef FBSD_VOP_GETPAGES_BUSIED
620 if (i != ap->a_reqpage) {
621 #if __FreeBSD_version >= 1000042
622 vm_page_readahead_finish(m);
625 * Whether or not to leave the page activated is up in
626 * the air, but we should put the page on a page queue
627 * somewhere (it already is in the object). Result:
628 * It appears that emperical results show that
629 * deactivating pages is best.
633 * Just in case someone was asking for this page we
634 * now tell them that it is ok to use.
637 if (m->oflags & VPO_WANTED) {
640 ma_vm_page_unlock(m);
644 vm_page_deactivate(m);
645 ma_vm_page_unlock(m);
651 ma_vm_page_unlock(m);
653 #endif /* __FreeBSD_version 1000042 */
655 #endif /* ndef FBSD_VOP_GETPAGES_BUSIED */
657 ma_vm_page_unlock_queues();
658 AFS_VM_OBJECT_WUNLOCK(object);
664 struct vop_write_args /* {
665 * struct vnode *a_vp;
668 * struct ucred *a_cred;
672 struct vcache *avc = VTOAFS(ap->a_vp);
674 start = AFS_UIO_OFFSET(ap->a_uio);
675 end = start + AFS_UIO_RESID(ap->a_uio);
678 osi_FlushPages(avc, ap->a_cred); /* hold GLOCK, but not basic vnode lock */
680 afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
683 /* Invalidate any pages in the written area. */
684 vn_pages_remove(ap->a_vp, OFF_TO_IDX(start), OFF_TO_IDX(end));
690 * struct vop_putpages_args {
691 * struct vnode *a_vp;
696 * vm_oofset_t a_offset;
700 * All of the pages passed to us in ap->a_m[] are already marked as busy,
701 * so there is no additional locking required to set their flags. -GAW
704 afs_vop_putpages(struct vop_putpages_args *ap)
707 int i, size, npages, sync;
716 memset(&uio, 0, sizeof(uio));
717 memset(&iov, 0, sizeof(iov));
721 /* Perhaps these two checks should just be KASSERTs instead... */
722 if (vp->v_object == NULL) {
723 printf("afs_putpages: called with non-merged cache vnode??\n");
724 return VM_PAGER_ERROR; /* XXX I think this is insufficient */
726 if (vType(avc) != VREG) {
727 printf("afs_putpages: not VREG");
728 return VM_PAGER_ERROR; /* XXX I think this is insufficient */
730 npages = btoc(ap->a_count);
731 for (i = 0; i < npages; i++)
732 ap->a_rtvals[i] = VM_PAGER_AGAIN;
733 bp = getpbuf(&afs_pbuf_freecnt);
735 kva = (vm_offset_t) bp->b_data;
736 pmap_qenter(kva, ap->a_m, npages);
737 AFS_VM_CNT_INC(v_vnodeout);
738 AFS_VM_CNT_ADD(v_vnodepgsout, ap->a_count);
740 iov.iov_base = (caddr_t) kva;
741 iov.iov_len = ap->a_count;
744 uio.uio_offset = IDX_TO_OFF(ap->a_m[0]->pindex);
745 uio.uio_resid = ap->a_count;
746 uio.uio_segflg = UIO_SYSSPACE;
747 uio.uio_rw = UIO_WRITE;
748 uio.uio_td = curthread;
750 if (ap->a_sync & VM_PAGER_PUT_SYNC)
752 /*if (ap->a_sync & VM_PAGER_PUT_INVAL)
753 * sync |= IO_INVAL; */
757 ObtainReadLock(&avc->lock);
758 if (avc->cred != NULL) {
760 * Use the creds from the process that opened this file for writing; if
761 * any. Otherwise, if we use the current process's creds, we may use
762 * the creds for uid 0 if we are writing back pages from the syncer(4)
765 cred = crhold(avc->cred);
767 cred = crhold(curthread->td_ucred);
769 ReleaseReadLock(&avc->lock);
771 code = afs_write(avc, &uio, sync, cred, 0);
774 pmap_qremove(kva, npages);
775 relpbuf(bp, &afs_pbuf_freecnt);
778 AFS_VM_OBJECT_WLOCK(vp->v_object);
779 size = ap->a_count - uio.uio_resid;
780 for (i = 0; i < round_page(size) / PAGE_SIZE; i++) {
781 ap->a_rtvals[i] = VM_PAGER_OK;
782 vm_page_undirty(ap->a_m[i]);
784 AFS_VM_OBJECT_WUNLOCK(vp->v_object);
787 return ap->a_rtvals[0];
792 struct vop_ioctl_args /* {
793 * struct vnode *a_vp;
797 * struct ucred *a_cred;
798 * struct thread *a_td;
801 struct vcache *tvc = VTOAFS(ap->a_vp);
804 /* in case we ever get in here... */
806 AFS_STATCNT(afs_ioctl);
807 if (((ap->a_command >> 8) & 0xff) == 'V') {
808 /* This is a VICEIOCTL call */
810 error = HandleIoctl(tvc, ap->a_command, ap->a_data);
814 /* No-op call; just return. */
821 struct vop_fsync_args /* {
822 * struct vnode *a_vp;
828 struct vnode *vp = ap->a_vp;
831 /*vflushbuf(vp, wait); */
832 error = afs_fsync(VTOAFS(vp), ap->a_td->td_ucred);
839 struct vop_remove_args /* {
840 * struct vnode *a_dvp;
841 * struct vnode *a_vp;
842 * struct componentname *a_cnp;
846 struct vnode *vp = ap->a_vp;
847 struct vnode *dvp = ap->a_dvp;
851 error = afs_remove(VTOAFS(dvp), name, cnp->cn_cred);
860 struct vop_link_args /* {
861 * struct vnode *a_vp;
862 * struct vnode *a_tdvp;
863 * struct componentname *a_cnp;
867 struct vnode *dvp = ap->a_tdvp;
868 struct vnode *vp = ap->a_vp;
871 if (dvp->v_mount != vp->v_mount) {
875 if (vp->v_type == VDIR) {
879 if ((error = vn_lock(vp, LK_CANRECURSE | LK_EXCLUSIVE)) != 0) {
883 error = afs_link(VTOAFS(vp), VTOAFS(dvp), name, cnp->cn_cred);
894 struct vop_rename_args /* {
895 * struct vnode *a_fdvp;
896 * struct vnode *a_fvp;
897 * struct componentname *a_fcnp;
898 * struct vnode *a_tdvp;
899 * struct vnode *a_tvp;
900 * struct componentname *a_tcnp;
904 struct componentname *fcnp = ap->a_fcnp;
906 struct componentname *tcnp = ap->a_tcnp;
908 struct vnode *tvp = ap->a_tvp;
909 struct vnode *tdvp = ap->a_tdvp;
910 struct vnode *fvp = ap->a_fvp;
911 struct vnode *fdvp = ap->a_fdvp;
914 * Check for cross-device rename.
916 if ((fvp->v_mount != tdvp->v_mount)
917 || (tvp && (fvp->v_mount != tvp->v_mount))) {
931 * if fvp == tvp, we're just removing one name of a pair of
932 * directory entries for the same element. convert call into rename.
933 ( (pinched from FreeBSD 4.4's ufs_rename())
937 if (fvp->v_type == VDIR) {
942 /* Release destination completely. */
949 fcnp->cn_flags &= ~MODMASK;
950 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
951 if ((fcnp->cn_flags & SAVESTART) == 0)
952 panic("afs_rename: lost from startdir");
953 fcnp->cn_nameiop = DELETE;
955 error = relookup(fdvp, &fvp, fcnp);
962 error = VOP_REMOVE(fdvp, fvp, fcnp);
970 if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
973 fname = malloc(fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
974 memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
975 fname[fcnp->cn_namelen] = '\0';
976 tname = malloc(tcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
977 memcpy(tname, tcnp->cn_nameptr, tcnp->cn_namelen);
978 tname[tcnp->cn_namelen] = '\0';
982 /* XXX use "from" or "to" creds? NFS uses "to" creds */
984 afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, tcnp->cn_cred);
1002 struct vop_mkdir_args /* {
1003 * struct vnode *a_dvp;
1004 * struct vnode **a_vpp;
1005 * struct componentname *a_cnp;
1006 * struct vattr *a_vap;
1009 struct vnode *dvp = ap->a_dvp;
1010 struct vattr *vap = ap->a_vap;
1016 if ((cnp->cn_flags & HASBUF) == 0)
1017 panic("afs_vop_mkdir: no name");
1020 error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, cnp->cn_cred);
1027 *ap->a_vpp = AFSTOV(vcp);
1028 vn_lock(AFSTOV(vcp), LK_EXCLUSIVE | LK_RETRY);
1037 struct vop_rmdir_args /* {
1038 * struct vnode *a_dvp;
1039 * struct vnode *a_vp;
1040 * struct componentname *a_cnp;
1044 struct vnode *dvp = ap->a_dvp;
1048 error = afs_rmdir(VTOAFS(dvp), name, cnp->cn_cred);
1054 /* struct vop_symlink_args {
1055 * struct vnode *a_dvp;
1056 * struct vnode **a_vpp;
1057 * struct componentname *a_cnp;
1058 * struct vattr *a_vap;
1063 afs_vop_symlink(struct vop_symlink_args *ap)
1066 struct vnode *newvp;
1077 afs_symlink(VTOAFS(dvp), name, ap->a_vap, ap->a_target, NULL,
1080 error = afs_lookup(VTOAFS(dvp), name, &vcp, cnp->cn_cred);
1082 newvp = AFSTOV(vcp);
1083 vn_lock(newvp, LK_EXCLUSIVE | LK_RETRY);
1088 *(ap->a_vpp) = newvp;
1094 struct vop_readdir_args /* {
1095 * struct vnode *a_vp;
1096 * struct uio *a_uio;
1097 * struct ucred *a_cred;
1099 * u_long *a_cookies;
1105 /* printf("readdir %x cookies %x ncookies %d\n", ap->a_vp, ap->a_cookies,
1107 off = ap->a_uio->uio_offset;
1110 afs_readdir(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred, ap->a_eofflag);
1112 if (!error && ap->a_ncookies != NULL) {
1113 struct uio *uio = ap->a_uio;
1114 const struct dirent *dp, *dp_start, *dp_end;
1116 u_long *cookies, *cookiep;
1118 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1119 panic("afs_readdir: burned cookies");
1120 dp = (const struct dirent *)
1121 ((const char *)uio->uio_iov->iov_base - (uio->uio_offset - off));
1123 dp_end = (const struct dirent *)uio->uio_iov->iov_base;
1124 for (dp_start = dp, ncookies = 0; dp < dp_end;
1125 dp = (const struct dirent *)((const char *)dp + dp->d_reclen))
1128 cookies = malloc(ncookies * sizeof(u_long), M_TEMP,
1130 for (dp = dp_start, cookiep = cookies; dp < dp_end;
1131 dp = (const struct dirent *)((const char *)dp + dp->d_reclen)) {
1132 off += dp->d_reclen;
1135 *ap->a_cookies = cookies;
1136 *ap->a_ncookies = ncookies;
1143 afs_vop_readlink(ap)
1144 struct vop_readlink_args /* {
1145 * struct vnode *a_vp;
1146 * struct uio *a_uio;
1147 * struct ucred *a_cred;
1151 /* printf("readlink %x\n", ap->a_vp);*/
1153 error = afs_readlink(VTOAFS(ap->a_vp), ap->a_uio, ap->a_cred);
1159 afs_vop_inactive(ap)
1160 struct vop_inactive_args /* {
1161 * struct vnode *a_vp;
1162 * struct thread *td;
1165 struct vnode *vp = ap->a_vp;
1168 afs_InactiveVCache(VTOAFS(vp), 0); /* decrs ref counts */
1174 * struct vop_reclaim_args {
1175 * struct vnode *a_vp;
1179 afs_vop_reclaim(struct vop_reclaim_args *ap)
1182 struct vnode *vp = ap->a_vp;
1183 struct vcache *avc = VTOAFS(vp);
1184 int haveGlock = ISAFS_GLOCK();
1187 * In other code paths, we acquire the vnode lock while afs_xvcache is
1188 * already held (e.g. afs_PutVCache() -> vrele()). Here, we already have
1189 * the vnode lock, and we need afs_xvcache. So drop the vnode lock in order
1190 * to hold afs_xvcache.
1196 ObtainWriteLock(&afs_xvcache, 901);
1199 * Note that we deliberately call VOP_LOCK() instead of vn_lock() here.
1200 * vn_lock() will return an error for VI_DOOMED vnodes, but we know this
1201 * vnode is already VI_DOOMED. We just want to lock it again, and skip the
1204 VOP_LOCK(vp, LK_EXCLUSIVE);
1206 code = afs_FlushVCache(avc, &slept);
1208 if (avc->f.states & CVInit) {
1209 avc->f.states &= ~CVInit;
1210 afs_osi_Wakeup(&avc->f.states);
1213 ReleaseWriteLock(&afs_xvcache);
1218 afs_warn("afs_vop_reclaim: afs_FlushVCache failed code %d vnode\n", code);
1220 panic("afs: afs_FlushVCache failed during reclaim");
1223 vnode_destroy_vobject(vp);
1230 afs_vop_strategy(ap)
1231 struct vop_strategy_args /* {
1237 error = afs_ustrategy(ap->a_bp, osi_curcred());
1244 struct vop_print_args /* {
1245 * struct vnode *a_vp;
1248 struct vnode *vp = ap->a_vp;
1249 struct vcache *vc = VTOAFS(ap->a_vp);
1250 int s = vc->f.states;
1252 printf("vc %p vp %p tag %s, fid: %d.%d.%d.%d, opens %d, writers %d", vc, vp, vp->v_tag,
1253 (int)vc->f.fid.Cell, (u_int) vc->f.fid.Fid.Volume,
1254 (u_int) vc->f.fid.Fid.Vnode, (u_int) vc->f.fid.Fid.Unique, vc->opens,
1255 vc->execsOrWriters);
1256 printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
1257 (s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
1258 (s & CMAPPED) ? " mapped" : "",
1259 (s & CVFlushed) ? " flush in progress" : "");
1265 * Advisory record locking support (fcntl() POSIX style)
1269 struct vop_advlock_args /* {
1270 * struct vnode *a_vp;
1273 * struct flock *a_fl;
1278 struct ucred cr = *osi_curcred();
1281 if (a_op == F_UNLCK) {
1283 * When a_fl->type is F_UNLCK, FreeBSD passes in an a_op of F_UNLCK.
1284 * This is (confusingly) different than how you actually release a lock
1285 * with fcntl(), which is done with an a_op of F_SETLK and an l_type of
1286 * F_UNLCK. Pretend we were given an a_op of F_SETLK in this case,
1287 * since this is what afs_lockctl expects.
1294 afs_lockctl(VTOAFS(ap->a_vp),
1297 (int)(intptr_t)ap->a_id); /* XXX: no longer unique! */
1302 struct vop_vector afs_vnodeops = {
1303 .vop_default = &default_vnodeops,
1304 .vop_access = afs_vop_access,
1305 .vop_advlock = afs_vop_advlock,
1306 .vop_close = afs_vop_close,
1307 .vop_create = afs_vop_create,
1308 .vop_fsync = afs_vop_fsync,
1309 .vop_getattr = afs_vop_getattr,
1310 .vop_getpages = afs_vop_getpages,
1311 .vop_inactive = afs_vop_inactive,
1312 .vop_ioctl = afs_vop_ioctl,
1313 .vop_link = afs_vop_link,
1314 .vop_lookup = afs_vop_lookup,
1315 .vop_mkdir = afs_vop_mkdir,
1316 .vop_mknod = afs_vop_mknod,
1317 .vop_open = afs_vop_open,
1318 .vop_pathconf = afs_vop_pathconf,
1319 .vop_print = afs_vop_print,
1320 .vop_putpages = afs_vop_putpages,
1321 .vop_read = afs_vop_read,
1322 .vop_readdir = afs_vop_readdir,
1323 .vop_readlink = afs_vop_readlink,
1324 .vop_reclaim = afs_vop_reclaim,
1325 .vop_remove = afs_vop_remove,
1326 .vop_rename = afs_vop_rename,
1327 .vop_rmdir = afs_vop_rmdir,
1328 .vop_setattr = afs_vop_setattr,
1329 .vop_strategy = afs_vop_strategy,
1330 .vop_symlink = afs_vop_symlink,
1331 .vop_write = afs_vop_write,