#include <afsconfig.h>
#include <afs/param.h>
-RCSID
- ("$Header$");
#include <afs/sysincludes.h> /* Standard vendor system headers */
#include <afsincludes.h> /* Afs-based standard headers */
#include <sys/malloc.h>
#include <sys/namei.h>
#include <sys/ubc.h>
-#if defined(AFS_DARWIN70_ENV)
#include <vfs/vfs_support.h>
-#endif /* defined(AFS_DARWIN70_ENV) */
#ifdef AFS_DARWIN80_ENV
#include <sys/vnode_if.h>
#include <sys/kauth.h>
int afs_vop_symlink(struct VOPPROT(symlink_args) *);
int afs_vop_readdir(struct VOPPROT(readdir_args) *);
int afs_vop_readlink(struct VOPPROT(readlink_args) *);
-#if !defined(AFS_DARWIN70_ENV)
-extern int ufs_abortop(struct vop_abortop_args *);
-#endif /* !defined(AFS_DARWIN70_ENV) */
int afs_vop_inactive(struct VOPPROT(inactive_args) *);
int afs_vop_reclaim(struct VOPPROT(reclaim_args) *);
int afs_vop_strategy(struct VOPPROT(strategy_args) *);
{VOPPREF(readdir_desc), (VOPFUNC)afs_vop_readdir}, /* readdir */
{VOPPREF(readlink_desc), (VOPFUNC)afs_vop_readlink}, /* readlink */
#ifndef AFS_DARWIN80_ENV
-#if defined(AFS_DARWIN70_ENV)
{VOPPREF(abortop_desc), (VOPFUNC)nop_abortop }, /* abortop */
-#else /* ! defined(AFS_DARWIN70_ENV) */
- /* Yes, we use the ufs_abortop call. It just releases the namei
- * buffer stuff */
- {VOPPREF(abortop_desc), (VOPFUNC)ufs_abortop}, /* abortop */
-#endif /* defined(AFS_DARWIN70_ENV) */
#endif
{VOPPREF(inactive_desc), (VOPFUNC)afs_vop_inactive}, /* inactive */
{VOPPREF(reclaim_desc), (VOPFUNC)afs_vop_reclaim}, /* reclaim */
struct vcache *tvc = VTOAFS(vp);
#ifndef AFS_DARWIN80_ENV
- tvc->states |= CUBCinit;
+ tvc->f.states |= CUBCinit;
#endif
#ifdef AFS_DARWIN80_ENV
- if (tvc->states & CDeadVnode)
+ osi_Assert((tvc->f.states & CVInit) == 0);
+ if (tvc->f.states & CDeadVnode)
osi_Assert(!vnode_isinuse(vp, 1));
- osi_Assert((tvc->states & CVInit) == 0);
#endif
if (haveGlock) AFS_GUNLOCK();
if (vnode_get(vp)) {
/* being terminated. kernel won't give us a ref. Now what? our
callers don't expect us to fail */
-#if 1
- panic("vn_hold on terminating vnode");
-#else
if (haveGlock) AFS_GLOCK();
return;
-#endif
}
- vnode_ref(vp);
+ if (vnode_ref(vp)) {
+ vnode_put(vp);
+ if (haveGlock) AFS_GLOCK();
+ return;
+ }
vnode_put(vp);
#else
/* vget needed for 0 ref'd vnode in GetVCache to not panic in vref.
if (haveGlock) AFS_GLOCK();
#ifndef AFS_DARWIN80_ENV
- tvc->states &= ~CUBCinit;
+ tvc->f.states &= ~CUBCinit;
#endif
}
int
int error;
struct vcache *vcp;
struct vnode *vp, *dvp;
- register int flags = ap->a_cnp->cn_flags;
+ int flags = ap->a_cnp->cn_flags;
int lockparent; /* 1 => lockparent flag is set */
int wantparent; /* 1 => wantparent or lockparent flag */
struct proc *p;
#ifdef AFS_DARWIN80_ENV
vcp = VTOAFS(ap->a_dvp);
+ /*
+ * ._ file attribute mirroring touches this.
+ * we can't flag the vcache as there is none, so fail here.
+ * needed for fsevents support.
+ */
+ if (ap->a_context == afs_osi_ctxtp)
+ return ENOENT;
if (vcp->mvstat != 1) {
error = cache_lookup(ap->a_dvp, ap->a_vpp, ap->a_cnp);
if (error == -1)
return (error);
}
#ifdef AFS_DARWIN80_ENV
- if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
+ if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
+ DROPNAME();
*ap->a_vpp = 0;
return error;
}
{
int error = 0;
struct vcache *vcp;
- register struct vnode *dvp = ap->a_dvp;
+ struct vnode *dvp = ap->a_dvp;
struct proc *p;
GETNAME();
p = vop_cn_proc;
if (vcp) {
#ifdef AFS_DARWIN80_ENV
- if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0))) {
- *ap->a_vpp=0;
- return error;
+ if ((error=afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0))) {
+ DROPNAME();
+ *ap->a_vpp=0;
+ return error;
}
#endif
*ap->a_vpp = AFSTOV(vcp);
(*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
vn_lock(*ap->a_vpp, LK_EXCLUSIVE | LK_RETRY, p);
if (UBCINFOMISSING(*ap->a_vpp) || UBCINFORECLAIMED(*ap->a_vpp)) {
- vcp->states |= CUBCinit;
+ vcp->f.states |= CUBCinit;
ubc_info_init(*ap->a_vpp);
- vcp->states &= ~CUBCinit;
+ vcp->f.states &= ~CUBCinit;
}
#endif
} else
int error;
struct vnode *vp = ap->a_vp;
struct vcache *vc = VTOAFS(vp);
-#if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
+#if !defined(AFS_DARWIN80_ENV)
int didhold = 0;
/*----------------------------------------------------------------
* osi_VM_TryReclaim() removes the ubcinfo of a vnode, but that vnode
if (vp->v_type == VREG && !(vp->v_flag & VSYSTEM)
&& vp->v_ubcinfo->ui_refcount < 2)
didhold = ubc_hold(vp);
-#endif /* AFS_DARWIN14_ENV */
+#endif /* !AFS_DARWIN80_ENV */
AFS_GLOCK();
error = afs_open(&vc, ap->a_mode, vop_cred);
#ifdef DIAGNOSTIC
#endif
osi_FlushPages(vc, vop_cred);
AFS_GUNLOCK();
-#if defined(AFS_DARWIN14_ENV) && !defined(AFS_DARWIN80_ENV)
+#if !defined(AFS_DARWIN80_ENV)
if (error && didhold)
ubc_rele(vp);
-#endif /* AFS_DARWIN14_ENV */
+#endif /* !AFS_DARWIN80_ENV */
return error;
}
int code;
struct vnode *vp = ap->a_vp;
struct vcache *avc = VTOAFS(vp);
+ /* allows faking FSE_CONTENT_MODIFIED */
+ if (afs_osi_ctxtp == ap->a_context)
+ return 0;
AFS_GLOCK();
if (vop_cred)
- code = afs_close(avc, ap->a_fflag, vop_cred, vop_proc);
+ code = afs_close(avc, ap->a_fflag, vop_cred);
else
- code = afs_close(avc, ap->a_fflag, &afs_osi_cred, vop_proc);
+ code = afs_close(avc, ap->a_fflag, &afs_osi_cred);
osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
+ /* This is legit; it just forces the fstrace event to happen */
+ code = afs_CheckCode(code, NULL, 60);
AFS_GUNLOCK();
return code;
struct afs_fakestat_state fakestate;
struct vcache * tvc = VTOAFS(ap->a_vp);
int bits=0;
+ int cmb = CHECK_MODE_BITS;
+#ifdef AFS_DARWIN80_ENV
+ /*
+ * needed for fsevents. ._ file attribute mirroring touches this.
+ * we can't flag the vcache, as there is none, so fail here.
+ */
+ if (ap->a_context == afs_osi_ctxtp)
+ return ENOENT;
+#endif
AFS_GLOCK();
afs_InitFakeStat(&fakestate);
if ((code = afs_InitReq(&treq, vop_cred)))
code = afs_CheckCode(code, &treq, 56);
goto out;
}
- if (afs_fakestat_enable && tvc->mvstat && !(tvc->states & CStatd)) {
+ if (afs_fakestat_enable && tvc->mvstat && !(tvc->f.states & CStatd)) {
code = 0;
goto out;
}
bits |= PRSFS_LOOKUP;
if (ap->a_action & KAUTH_VNODE_READ_SECURITY) /* mode bits/gid, not afs acl */
bits |= PRSFS_LOOKUP;
+ if ((ap->a_action & ((1 << 25) - 1)) == KAUTH_VNODE_EXECUTE)
+ /* if only exec, don't check for read mode bit */
+ /* high bits of ap->a_action are not for 'generic rights bits', and
+ so should not be checked (KAUTH_VNODE_ACCESS is often present
+ and needs to be masked off) */
+ cmb |= CMB_ALLOW_EXEC_AS_READ;
}
if (ap->a_action & KAUTH_VNODE_WRITE_ATTRIBUTES)
bits |= PRSFS_WRITE;
bits |= PRSFS_WRITE;
/* we can't check for KAUTH_VNODE_TAKE_OWNERSHIP, so we always permit it */
- code = afs_AccessOK(tvc, bits, &treq, CHECK_MODE_BITS);
+ code = afs_AccessOK(tvc, bits, &treq, cmb);
+ /*
+ * Special cased dropbox handling:
+ * cp on 10.4 behaves badly, looping on EACCES
+ * Finder may reopen the file. Let it.
+ */
+ if (code == 0 && ((bits &~(PRSFS_READ|PRSFS_WRITE)) == 0))
+ code = afs_AccessOK(tvc, PRSFS_ADMINISTER|PRSFS_INSERT|bits, &treq, cmb);
+ /* Finder also treats dropboxes as insert+delete. fake it out. */
+ if (code == 0 && (bits == (PRSFS_INSERT|PRSFS_DELETE)))
+ code = afs_AccessOK(tvc, PRSFS_INSERT, &treq, cmb);
if (code == 1 && vnode_vtype(ap->a_vp) == VREG &&
ap->a_action & KAUTH_VNODE_EXECUTE &&
- (tvc->m.Mode & 0100) != 0100) {
+ (tvc->f.m.Mode & 0100) != 0100) {
code = 0;
- }
+ }
if (code) {
code= 0; /* if access is ok */
} else {
- code = afs_CheckCode(EACCES, &treq, 57); /* failure code */
+ code = afs_CheckCode(EACCES, &treq, 57); /* failure code */
}
out:
afs_PutFakeStat(&fakestate);
{
int code;
- AFS_GLOCK();
- code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
- AFS_GUNLOCK();
+#ifdef AFS_DARWIN80_ENV
+ /* CEvent excludes the fsevent. our context excludes the ._ */
+ if ((VTOAFS(ap->a_vp)->f.states & CEvent) ||
+ (ap->a_context == afs_osi_ctxtp)){
+ struct vcache *avc = VTOAFS(ap->a_vp);
+ int isglock = ISAFS_GLOCK();
+
+ /* this is needed because of how and when we re-enter */
+ if (!isglock)
+ AFS_GLOCK();
+ /* do minimal work to return fake result for fsevents */
+ if (afs_fakestat_enable && VTOAFS(ap->a_vp)->mvstat == 1) {
+ struct afs_fakestat_state fakestat;
+ struct vrequest treq;
+
+ code = afs_InitReq(&treq, vop_cred);
+ if (code) {
+ if (!isglock)
+ AFS_GUNLOCK();
+ return code;
+ }
+ afs_InitFakeStat(&fakestat);
+ /* expects GLOCK */
+ code = afs_TryEvalFakeStat(&avc, &fakestat, &treq);
+ if (code) {
+ if (!isglock)
+ AFS_GUNLOCK();
+ afs_PutFakeStat(&fakestat);
+ return code;
+ }
+ }
+ code = afs_CopyOutAttrs(avc, ap->a_vap);
+ if (!isglock)
+ AFS_GUNLOCK();
+ if (0 && !code) {
+ /* tweak things so finder will recheck */
+ (ap->a_vap)->va_gid = ((ap->a_vap)->va_gid == 1) ? 2 : 1;
+ (ap->a_vap)->va_mode &= ~(VSGID);
+ }
+ } else
+#endif
+ {
+ AFS_GLOCK();
+ code = afs_getattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
+ /* This is legit; it just forces the fstrace event to happen */
+ code = afs_CheckCode(code, NULL, 58);
+ AFS_GUNLOCK();
+ }
#ifdef AFS_DARWIN80_ENV
VATTR_SET_SUPPORTED(ap->a_vap, va_type);
VATTR_SET_SUPPORTED(ap->a_vap, va_mode);
VATTR_SET_SUPPORTED(ap->a_vap, va_uid);
VATTR_SET_SUPPORTED(ap->a_vap, va_gid);
+ VATTR_SET_SUPPORTED(ap->a_vap, va_fsid);
VATTR_SET_SUPPORTED(ap->a_vap, va_fileid);
VATTR_SET_SUPPORTED(ap->a_vap, va_nlink);
VATTR_SET_SUPPORTED(ap->a_vap, va_data_size);
* struct proc *a_p;
* } */ *ap;
{
- int code;
+ int code, pass = 0;
+ struct vcache *avc = VTOAFS(ap->a_vp);
+#ifdef AFS_DARWIN80_ENV
+ /* fsevents tries to set attributes. drop it. */
+ if (ap->a_context == afs_osi_ctxtp)
+ return 0;
+#endif
AFS_GLOCK();
- code = afs_setattr(VTOAFS(ap->a_vp), ap->a_vap, vop_cred);
+retry:
+ code = afs_setattr(avc, ap->a_vap, vop_cred);
+ /* This is legit; it just forces the fstrace event to happen */
+ code = afs_CheckCode(code, NULL, 59);
+ if (!pass && code == EINVAL && (VATTR_IS_ACTIVE(ap->a_vap, va_mode) &&
+ (vType(avc) == VLNK))) {
+ VATTR_CLEAR_ACTIVE(ap->a_vap, va_mode);
+ pass++;
+ goto retry;
+ }
AFS_GUNLOCK();
return code;
}
int code;
struct vnode *vp = ap->a_vp;
struct vcache *avc = VTOAFS(vp);
+
+ if (vnode_isdir(ap->a_vp))
+ return EISDIR;
#ifdef AFS_DARWIN80_ENV
- ubc_sync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_PUSHDIRTY);
+ ubc_msync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_PUSHDIRTY);
#else
if (UBCINFOEXISTS(ap->a_vp)) {
ubc_clean(ap->a_vp, 0);
#endif
AFS_GLOCK();
osi_FlushPages(avc, vop_cred); /* hold bozon lock, but not basic vnode lock */
- code = afs_read(avc, ap->a_uio, vop_cred, 0, 0, 0);
+ code = afs_read(avc, ap->a_uio, vop_cred, 0);
AFS_GUNLOCK();
return code;
}
* int a_flags;
* } */ *ap;
{
- register struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp;
upl_t pl = ap->a_pl;
size_t size = ap->a_size;
off_t f_offset = ap->a_f_offset;
#endif
AFS_GLOCK();
osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
- code = afs_read(tvc, uio, cred, 0, 0, 0);
+ code = afs_read(tvc, uio, cred, 0);
if (code == 0) {
ObtainWriteLock(&tvc->lock, 2);
- tvc->states |= CMAPPED;
+ tvc->f.states |= CMAPPED;
ReleaseWriteLock(&tvc->lock);
}
AFS_GUNLOCK();
struct vcache *avc = VTOAFS(ap->a_vp);
void *object;
#ifdef AFS_DARWIN80_ENV
- ubc_sync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_INVALIDATE);
+ ubc_msync_range(ap->a_vp, AFS_UIO_OFFSET(ap->a_uio), AFS_UIO_OFFSET(ap->a_uio) + AFS_UIO_RESID(ap->a_uio), UBC_INVALIDATE);
#else
if (UBCINFOEXISTS(ap->a_vp)) {
ubc_clean(ap->a_vp, 1);
* int a_flags
* } */ *ap;
{
- register struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp;
upl_t pl = ap->a_pl;
size_t size = ap->a_size;
off_t f_offset = ap->a_f_offset;
UPL_ABORT_FREE_ON_EMPTY);
return (EINVAL);
}
- if (f_offset >= tvc->m.Length) {
+ if (f_offset >= tvc->f.m.Length) {
if (!nocommit)
OSI_UPL_ABORT_RANGE(pl, pl_offset, size,
UPL_ABORT_FREE_ON_EMPTY);
/* size will always be a multiple of PAGE_SIZE */
/* pageout isn't supposed to extend files */
- if (f_offset + size > tvc->m.Length)
- iosize = tvc->m.Length - f_offset;
+ if (f_offset + size > tvc->f.m.Length)
+ iosize = tvc->f.m.Length - f_offset;
else
iosize = size;
auio.uio_resid = aiov.iov_len = iosize;
aiov.iov_base = (caddr_t) ioaddr;
#endif
-#if 1 /* USV [ */
{
- /*
+ /* USV?
* check for partial page and clear the
* contents past end of the file before
* releasing it in the VM page cache
*/
- if ((f_offset < tvc->m.Length) && (f_offset + size) > tvc->m.Length) {
- size_t io = tvc->m.Length - f_offset;
+ if ((f_offset < tvc->f.m.Length) && (f_offset + size) > tvc->f.m.Length) {
+ size_t io = tvc->f.m.Length - f_offset;
memset((caddr_t) (ioaddr + pl_offset + io), 0, size - io);
}
}
-#endif /* ] USV */
AFS_GLOCK();
osi_FlushPages(tvc, vop_cred); /* hold bozon lock, but not basic vnode lock */
if (((ap->a_command >> 8) & 0xff) == 'V') {
/* This is a VICEIOCTL call */
AFS_GLOCK();
- error = HandleIoctl(tvc, (struct file *)0 /*Not used */ ,
- ap->a_command, ap->a_data);
+ error = HandleIoctl(tvc, ap->a_command, ap->a_data);
AFS_GUNLOCK();
return (error);
} else {
{
int wait = ap->a_waitfor == MNT_WAIT;
int error;
- register struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp;
int haveGlock = ISAFS_GLOCK();
+ /* in order to recycle faked vnodes for bulkstat */
+ if (VTOAFS(vp) == NULL)
+ return ENOTSUP;
+
/* afs_vop_lookup glocks, can call us through vinvalbuf from GetVCache */
if (!haveGlock) AFS_GLOCK();
if (vop_cred)
* } */ *ap;
{
int error = 0;
- register struct vnode *vp = ap->a_vp;
- register struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
#ifdef AFS_DARWIN80_ENV
if (ap->a_flags & VNODE_REMOVE_NODELETEBUSY) {
GETNAME();
AFS_GLOCK();
error = afs_remove(VTOAFS(dvp), name, vop_cn_cred);
+ error = afs_CheckCode(error, NULL, 61);
AFS_GUNLOCK();
cache_purge(vp);
if (!error) {
#ifdef AFS_DARWIN80_ENV
- ubc_setsize(vp, (off_t)0);
- vnode_recycle(vp);
+ struct vcache *tvc = VTOAFS(vp);
+
+ if (!(tvc->f.states & CUnlinked)) {
+ ubc_setsize(vp, (off_t)0);
+ vnode_recycle(vp);
+ }
#else
/* necessary so we don't deadlock ourselves in vclean */
VOP_UNLOCK(vp, 0, cnp->cn_proc);
/* If crashes continue in ubc_hold, comment this out */
(void)ubc_uncache(vp);
#endif
+ } else {
+ /* should check for PRSFS_INSERT and not PRSFS_DELETE, but the
+ goal here is to deal with Finder's unhappiness with resource
+ forks that have no resources in a dropbox setting */
+ if (name[0] == '.' && name[1] == '_' && error == EACCES)
+ error = 0;
}
#ifndef AFS_DARWIN80_ENV
* } */ *ap;
{
int error = 0;
- register struct vnode *dvp = ap->a_tdvp;
- register struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_tdvp;
+ struct vnode *vp = ap->a_vp;
struct proc *p;
GETNAME();
struct componentname *tcnp = ap->a_tcnp;
char *tname;
struct vnode *tvp = ap->a_tvp;
- register struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *tdvp = ap->a_tdvp;
struct vnode *fvp = ap->a_fvp;
- register struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *fdvp = ap->a_fdvp;
struct proc *p;
p = cn_proc(fcnp);
#ifdef AFS_DARWIN80_ENV
-/* generic code tests for v_mount equality, so we don't have to, but we don't
- get the multiple-mount "benefits" of the old behavior
-*/
+ /*
+ * generic code tests for v_mount equality, so we don't have to, but we
+ * don't get the multiple-mount "benefits" of the old behavior
+ * the generic code doesn't do this, so we really should, but all the
+ * vrele's are wrong...
+ */
#else
/* Check for cross-device rename.
* For AFS, this means anything not in AFS-space
error = EXDEV;
goto abortit;
}
-#endif
-#ifdef AFS_DARWIN80_ENV
- /* the generic code doesn't do this, so we really should, but all the
- vrele's are wrong... */
-#else
/*
* if fvp == tvp, we're just removing one name of a pair of
* directory entries for the same element. convert call into rename.
vput(tdvp);
vput(tvp);
/* Delete source. */
-#if defined(AFS_DARWIN80_ENV)
-
- MALLOC(fname, char *, fcnp->cn_namelen + 1, M_TEMP, M_WAITOK);
- memcpy(fname, fcnp->cn_nameptr, fcnp->cn_namelen);
- fname[fcnp->cn_namelen] = '\0';
- AFS_GLOCK();
- error = afs_remove(VTOAFS(fdvp), fname, vop_cn_cred);
- AFS_GUNLOCK();
- FREE(fname, M_TEMP);
- cache_purge(fvp);
-#else
vrele(fdvp);
vrele(fvp);
fcnp->cn_flags &= ~MODMASK;
return (ENOENT);
}
error=VOP_REMOVE(fdvp, fvp, fcnp);
-#endif
if (fdvp == fvp)
vrele(fdvp);
vput(fvp);
return (error);
}
-#endif
-#if !defined(AFS_DARWIN80_ENV)
if (error = vn_lock(fvp, LK_EXCLUSIVE, p))
goto abortit;
#endif
/* XXX use "from" or "to" creds? NFS uses "to" creds */
error =
afs_rename(VTOAFS(fdvp), fname, VTOAFS(tdvp), tname, cn_cred(tcnp));
- AFS_GUNLOCK();
#if !defined(AFS_DARWIN80_ENV)
+ AFS_GUNLOCK();
VOP_UNLOCK(fvp, 0, p);
-#endif
- FREE(fname, M_TEMP);
- FREE(tname, M_TEMP);
-#ifdef AFS_DARWIN80_ENV
- cache_purge(fdvp);
- cache_purge(fvp);
- cache_purge(tdvp);
- if (tvp) {
- cache_purge(tvp);
- if (!error) {
- vnode_recycle(tvp);
- }
- }
- if (!error)
- cache_enter(tdvp, fvp, tcnp);
-#else
if (error)
goto abortit; /* XXX */
if (tdvp == tvp)
vput(tvp);
vrele(fdvp);
vrele(fvp);
+#else
+ if (error == EXDEV) {
+ struct brequest *tb;
+ struct afs_uspc_param mvReq;
+ struct vcache *tvc;
+ struct vcache *fvc = VTOAFS(fdvp);
+ int code = 0;
+ struct afs_fakestat_state fakestate;
+ int fakestatdone = 0;
+
+ tvc = VTOAFS(tdvp);
+
+ /* unrewritten mount point? */
+ if (tvc->mvstat == 1) {
+ if (tvc->mvid && (tvc->f.states & CMValid)) {
+ struct vrequest treq;
+
+ afs_InitFakeStat(&fakestate);
+ code = afs_InitReq(&treq, vop_cred);
+ if (!code) {
+ fakestatdone = 1;
+ code = afs_EvalFakeStat(&tvc, &fakestate, &treq);
+ } else
+ afs_PutFakeStat(&fakestate);
+ }
+ }
+
+ if (!code) {
+ /* at some point in the future we should allow other types */
+ mvReq.reqtype = AFS_USPC_UMV;
+ mvReq.req.umv.id = afs_cr_uid(cn_cred(tcnp));
+ mvReq.req.umv.idtype = IDTYPE_UID;
+ mvReq.req.umv.sCell = fvc->f.fid.Cell;
+ mvReq.req.umv.sVolume = fvc->f.fid.Fid.Volume;
+ mvReq.req.umv.sVnode = fvc->f.fid.Fid.Vnode;
+ mvReq.req.umv.sUnique = fvc->f.fid.Fid.Unique;
+ mvReq.req.umv.dCell = tvc->f.fid.Cell;
+ mvReq.req.umv.dVolume = tvc->f.fid.Fid.Volume;
+ mvReq.req.umv.dVnode = tvc->f.fid.Fid.Vnode;
+ mvReq.req.umv.dUnique = tvc->f.fid.Fid.Unique;
+
+ /*
+ * su %d -c mv /afs/.:mount/%d:%d:%d:%d/%s
+ * /afs/.:mount/%d:%d:%d:%d/%s where:
+ * mvReq.req.umv.id, fvc->f.fid.Cell, fvc->f.fid.Fid.Volume,
+ * fvc->f.fid.Fid.Vnode, fvc->f.fid.Fid.Unique, fname,
+ * tvc->f.fid.Cell, tvc->f.fid.Fid.Volume, tvc->f.fid.Fid.Vnode,
+ * tvc->f.fid.Fid.Unique, tname
+ */
+
+ tb = afs_BQueue(BOP_MOVE, NULL, 0, 1, cn_cred(tcnp),
+ 0L, 0L, &mvReq, fname, tname);
+ /* wait to collect result */
+ while ((tb->flags & BUVALID) == 0) {
+ tb->flags |= BUWAIT;
+ afs_osi_Sleep(tb);
+ }
+ /* if we succeeded, clear the error. otherwise, EXDEV */
+ if (mvReq.retval == 0)
+ error = 0;
+
+ afs_BRelease(tb);
+ }
+
+ if (fakestatdone)
+ afs_PutFakeStat(&fakestate);
+ }
+ AFS_GUNLOCK();
+
+ cache_purge(fdvp);
+ cache_purge(fvp);
+ cache_purge(tdvp);
+ if (tvp) {
+ cache_purge(tvp);
+ if (!error) {
+ vnode_recycle(tvp);
+ }
+ }
+ if (!error)
+ cache_enter(tdvp, fvp, tcnp);
#endif
+ FREE(fname, M_TEMP);
+ FREE(tname, M_TEMP);
return error;
}
* struct vattr *a_vap;
* } */ *ap;
{
- register struct vnode *dvp = ap->a_dvp;
- register struct vattr *vap = ap->a_vap;
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
int error = 0;
struct vcache *vcp;
struct proc *p;
error = afs_mkdir(VTOAFS(dvp), name, vap, &vcp, vop_cn_cred);
AFS_GUNLOCK();
if (error) {
+#ifndef AFS_DARWIN80_ENV
VOP_ABORTOP(dvp, cnp);
vput(dvp);
+#endif
DROPNAME();
return (error);
}
if (vcp) {
#ifdef AFS_DARWIN80_ENV
- afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0);
+ afs_darwin_finalizevnode(vcp, ap->a_dvp, ap->a_cnp, 0, 0);
#endif
*ap->a_vpp = AFSTOV(vcp);
#ifndef AFS_DARWIN80_ENV /* XXX needed for multi-mount thing, but can't have it yet */
* } */ *ap;
{
int error = 0;
- register struct vnode *vp = ap->a_vp;
- register struct vnode *dvp = ap->a_dvp;
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
GETNAME();
if (dvp == vp) {
* char *a_target;
* } */ *ap;
{
- register struct vnode *dvp = ap->a_dvp;
+ struct vnode *dvp = ap->a_dvp;
int error = 0;
/* NFS ignores a_vpp; so do we. */
* struct proc *a_p;
* } */ *ap;
{
- register struct vnode *vp = ap->a_vp;
+ struct vnode *vp = ap->a_vp;
struct vcache *tvc = VTOAFS(vp);
#ifndef AFS_DARWIN80_ENV
if (prtactive && vp->v_usecount != 0)
vprint("afs_vop_inactive(): pushing active", vp);
#endif
if (tvc) {
- AFS_GLOCK();
- afs_InactiveVCache(tvc, 0); /* decrs ref counts */
- AFS_GUNLOCK();
+#ifdef AFS_DARWIN80_ENV
+ int unlinked = tvc->f.states & CUnlinked;
+#endif
+ AFS_GLOCK();
+ afs_InactiveVCache(tvc, 0); /* decrs ref counts */
+ AFS_GUNLOCK();
+#ifdef AFS_DARWIN80_ENV
+ if (unlinked) {
+ vnode_recycle(vp);
+ cache_purge(vp);
+ }
+#endif
}
#ifndef AFS_DARWIN80_ENV
VOP_UNLOCK(vp, 0, ap->a_p);
* } */ *ap;
{
int error = 0;
- int sl;
- register struct vnode *vp = ap->a_vp;
+ int sl, writelocked;
+ struct vnode *vp = ap->a_vp;
struct vcache *tvc = VTOAFS(vp);
osi_Assert(!ISAFS_GLOCK());
cache_purge(vp); /* just in case... */
if (tvc) {
AFS_GLOCK();
- ObtainWriteLock(&afs_xvcache, 335);
- error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */
- if (tvc->states & (CVInit
+ writelocked = (0 == NBObtainWriteLock(&afs_xvcache, 335));
+ if (!writelocked) {
+ ObtainWriteLock(&afs_xvreclaim, 176);
#ifdef AFS_DARWIN80_ENV
- | CDeadVnode
-#endif
- )) {
- tvc->states &= ~(CVInit
+ vnode_clearfsnode(AFSTOV(tvc));
+ vnode_removefsref(AFSTOV(tvc));
+#else
+ tvc->v->v_data = NULL; /* remove from vnode */
+#endif
+ AFSTOV(tvc) = NULL; /* also drop the ptr to vnode */
+ tvc->f.states |= CVInit; /* also CDeadVnode? */
+ tvc->nextfree = ReclaimedVCList;
+ ReclaimedVCList = tvc;
+ ReleaseWriteLock(&afs_xvreclaim);
+ } else {
+ error = afs_FlushVCache(tvc, &sl); /* toss our stuff from vnode */
+ if (tvc->f.states & (CVInit
#ifdef AFS_DARWIN80_ENV
- | CDeadVnode
+ | CDeadVnode
#endif
- );
- afs_osi_Wakeup(&tvc->states);
+ )) {
+ tvc->f.states &= ~(CVInit
+#ifdef AFS_DARWIN80_ENV
+ | CDeadVnode
+#endif
+ );
+ afs_osi_Wakeup(&tvc->f.states);
+ }
+ if (!error && vnode_fsnode(vp))
+ panic("afs_reclaim: vnode not cleaned");
+ if (!error && (tvc->v != NULL))
+ panic("afs_reclaim: vcache not cleaned");
+ ReleaseWriteLock(&afs_xvcache);
}
- if (!error && vnode_fsnode(vp))
- panic("afs_reclaim: vnode not cleaned");
- if (!error && (tvc->v != NULL))
- panic("afs_reclaim: vcache not cleaned");
- ReleaseWriteLock(&afs_xvcache);
AFS_GUNLOCK();
}
return error;
case _PC_PIPE_BUF:
return EINVAL;
break;
-#if defined(AFS_DARWIN70_ENV)
case _PC_NAME_CHARS_MAX:
*ap->a_retval = NAME_MAX;
break;
case _PC_CASE_PRESERVING:
*ap->a_retval = 1;
break;
-#endif /* defined(AFS_DARWIN70_ENV) */
default:
return EINVAL;
}
{
int error;
struct ucred *tcr;
+ int clid;
+ int op;
#ifdef AFS_DARWIN80_ENV
+ proc_t p;
tcr=vop_cred;
#else
struct proc *p = current_proc();
pcred_unlock(p);
tcr=&cr;
#endif
+ if (ap->a_flags & F_POSIX) {
+#ifdef AFS_DARWIN80_ENV
+ p = (proc_t) ap->a_id;
+ clid = proc_pid(p);
+#else
+ p = (struct proc *) ap->a_id;
+ clid = p->p_pid;
+#endif
+ } else {
+ clid = (int)ap->a_id;
+ }
+ if (ap->a_op == F_UNLCK) {
+ op = F_SETLK;
+ } else if (ap->a_op == F_SETLK && ap->a_flags & F_WAIT) {
+ op = F_SETLKW;
+ } else {
+ op = ap->a_op;
+ }
AFS_GLOCK();
- error =
- afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl,
- ap->a_op == F_UNLCK ? F_SETLK : ap->a_op, tcr,
- (int)ap->a_id);
+ error = afs_lockctl(VTOAFS(ap->a_vp), ap->a_fl, op, tcr, clid);
AFS_GUNLOCK();
return error;
}
* struct vnode *a_vp;
* } */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct vcache *avc = VTOAFS(vp);
+ struct vnode *vp = ap->a_vp;
+ struct vcache *avc = VTOAFS(vp);
if (vp->v_tag == VT_NON)
return (ENOENT);
* struct proc *a_p;
* } */ *ap;
{
- printf("stray afs_vop_truncate\n");
- return EOPNOTSUPP;
+ /* printf("stray afs_vop_truncate\n"); */
+ return ENOTSUP;
}
int
* int a_waitfor;
* } */ *ap;
{
- printf("stray afs_vop_update\n");
- return EOPNOTSUPP;
+ /* printf("stray afs_vop_update\n"); */
+ return ENOTSUP;
}
int
* struct vnode *a_vp;
* } */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct vcache *vc = VTOAFS(ap->a_vp);
- int s = vc->states;
+ struct vnode *vp = ap->a_vp;
+ struct vcache *vc = VTOAFS(ap->a_vp);
+ int s = vc->f.states;
printf("tag %d, fid: %ld.%x.%x.%x, opens %d, writers %d", vp->v_tag,
- vc->fid.Cell, vc->fid.Fid.Volume, vc->fid.Fid.Vnode,
- vc->fid.Fid.Unique, vc->opens, vc->execsOrWriters);
+ vc->f.fid.Cell, vc->f.fid.Fid.Volume, vc->f.fid.Fid.Vnode,
+ vc->f.fid.Fid.Unique, vc->opens, vc->execsOrWriters);
printf("\n states%s%s%s%s%s", (s & CStatd) ? " statd" : "",
(s & CRO) ? " readonly" : "", (s & CDirty) ? " dirty" : "",
(s & CMAPPED) ? " mapped" : "",
printf("\n UBC: ");
if (UBCINFOEXISTS(vp)) {
printf("exists, ");
-#ifdef AFS_DARWIN14_ENV
printf("refs %d%s%s", vp->v_ubcinfo->ui_refcount,
ubc_issetflags(vp, UI_HASOBJREF) ? " HASOBJREF" : "",
ubc_issetflags(vp, UI_WASMAPPED) ? " WASMAPPED" : "");
-#else
- printf("holdcnt %d", vp->v_ubcinfo->ui_holdcnt);
-#endif
} else
printf("does not exist");
}
struct vnode_fsparam par;
memset(&par, 0, sizeof(struct vnode_fsparam));
-#if 0
- AFS_GLOCK();
- ObtainWriteLock(&avc->lock,342);
- if (avc->states & CStatd) {
- par.vnfs_vtype = avc->m.Type;
- par.vnfs_vops = afs_vnodeop_p;
- par.vnfs_filesize = avc->m.Length;
- if (!ac->cnp)
- par.vnfs_flags = VNFS_NOCACHE;
- dead = 0;
- } else {
- par.vnfs_vtype = VNON;
- par.vnfs_vops = afs_dead_vnodeop_p;
- par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
- dead = 1;
- }
- ReleaseWriteLock(&avc->lock);
- AFS_GUNLOCK();
- par.vnfs_dvp = ac->dvp;
- par.vnfs_cnp = ac->cnp;
- par.vnfs_markroot = ac->markroot;
-#else
par.vnfs_vtype = VNON;
par.vnfs_vops = afs_dead_vnodeop_p;
par.vnfs_flags = VNFS_NOCACHE|VNFS_CANTCACHE;
-#endif
par.vnfs_mp = afs_globalVFS;
par.vnfs_fsnode = avc;
vnode_addfsref(vp);
vnode_ref(vp);
avc->v = vp;
-#if 0
- if (dead) {
- vnode_recycle(vp); /* terminate as soon as iocount drops */
- avc->states |= CDeadVnode;
- } else if (!ac->markroot && !ac->cnp) {
- /* the caller doesn't know anything about this vnode. if markroot
- should have been set and wasn't, bad things may happen, so encourage
- it to recycle */
- vnode_recycle(vp);
- }
-#else
vnode_recycle(vp); /* terminate as soon as iocount drops */
- avc->states |= CDeadVnode;
-#endif
+ avc->f.states |= CDeadVnode;
}
return error;
#else
#ifdef AFS_DARWIN80_ENV
/* if this fails, then tvc has been unrefed and may have been freed.
Don't touch! */
-int
-afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct componentname *cnp, int isroot) {
- vnode_t ovp = AFSTOV(avc);
- vnode_t nvp;
- int error;
- struct vnode_fsparam par;
- AFS_GLOCK();
- ObtainWriteLock(&avc->lock,325);
- if (!(avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
- ReleaseWriteLock(&avc->lock);
- AFS_GUNLOCK();
+int
+afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp,
+ struct componentname *cnp, int isroot, int locked)
+{
+ vnode_t ovp;
+ vnode_t nvp;
+ int error;
+ struct vnode_fsparam par;
+
+ if (!locked) {
+ AFS_GLOCK();
+ ObtainWriteLock(&avc->lock,325);
+ }
+ ovp = AFSTOV(avc);
+
+ if (!(avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON) {
+ AFS_GUNLOCK();
#if 0 /* unsupported */
if (dvp && cnp)
- vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
- cnp->cn_hash,
- VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
-#endif
- vnode_rele(ovp);
- return 0;
- }
- if ((avc->states & CDeadVnode) && vnode_vtype(ovp) != VNON)
- panic("vcache %p should not be CDeadVnode", avc);
- AFS_GUNLOCK();
- memset(&par, 0, sizeof(struct vnode_fsparam));
- par.vnfs_mp = afs_globalVFS;
- par.vnfs_vtype = avc->m.Type;
- par.vnfs_vops = afs_vnodeop_p;
- par.vnfs_filesize = avc->m.Length;
- par.vnfs_fsnode = avc;
- par.vnfs_dvp = dvp;
- par.vnfs_cnp = cnp;
- if (isroot)
- par.vnfs_markroot = 1;
- error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
- if (!error) {
- vnode_addfsref(nvp);
- avc->v = nvp;
- avc->states &=~ CDeadVnode;
- vnode_clearfsnode(ovp);
- vnode_removefsref(ovp);
- }
- AFS_GLOCK();
- ReleaseWriteLock(&avc->lock);
- if (!error)
- afs_osi_Wakeup(&avc->states);
- AFS_GUNLOCK();
- vnode_put(ovp);
- vnode_rele(ovp);
- return error;
+ vnode_update_identity(ovp, dvp, cnp->cn_nameptr, cnp->cn_namelen,
+ cnp->cn_hash,
+ VNODE_UPDATE_PARENT|VNODE_UPDATE_NAME);
+#endif
+ /* Can end up in reclaim... drop GLOCK */
+ vnode_rele(ovp);
+ AFS_GLOCK();
+ if (!locked) {
+ ReleaseWriteLock(&avc->lock);
+ AFS_GUNLOCK();
+ }
+ return 0;
+ }
+
+ if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
+ panic("vcache %p should not be CDeadVnode", avc);
+ AFS_GUNLOCK();
+ memset(&par, 0, sizeof(struct vnode_fsparam));
+ par.vnfs_mp = afs_globalVFS;
+ par.vnfs_vtype = avc->f.m.Type;
+ par.vnfs_vops = afs_vnodeop_p;
+ par.vnfs_filesize = avc->f.m.Length;
+ par.vnfs_fsnode = avc;
+ par.vnfs_dvp = dvp;
+ if (cnp && (cnp->cn_flags & ISDOTDOT) == 0)
+ par.vnfs_cnp = cnp;
+ if (!dvp || !cnp || (cnp->cn_flags & MAKEENTRY) == 0)
+ par.vnfs_flags = VNFS_NOCACHE;
+ if (isroot)
+ par.vnfs_markroot = 1;
+ error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &par, &nvp);
+ if (!error) {
+ vnode_addfsref(nvp);
+ if ((avc->f.states & CDeadVnode) && vnode_vtype(ovp) != VNON)
+ printf("vcache %p should not be CDeadVnode", avc);
+ if (avc->v == ovp) {
+ if (!(avc->f.states & CVInit)) {
+ vnode_clearfsnode(ovp);
+ vnode_removefsref(ovp);
+ }
+ /* we're discarding on a fixup. mark for recycle */
+ if (!(avc->f.states & CDeadVnode))
+ vnode_recycle(ovp);
+ }
+ avc->v = nvp;
+ avc->f.states &=~ CDeadVnode;
+ /* If we were carrying an extra ref for dirty, hold/push it. */
+ if (avc->f.ddirty_flags) {
+ vnode_get(nvp);
+ vnode_ref(nvp);
+ }
+ /* If we were carrying an extra ref for shadow, hold/push it. */
+ if (avc->f.shadow.vnode) {
+ vnode_get(nvp);
+ vnode_ref(nvp);
+ }
+ }
+ /* Drop any extra dirty ref on the old vnode */
+ if (avc->f.ddirty_flags) {
+ vnode_put(ovp);
+ vnode_rele(ovp);
+ }
+ /* Drop any extra shadow ref on the old vnode */
+ if (avc->f.shadow.vnode) {
+ vnode_put(ovp);
+ vnode_rele(ovp);
+ }
+ /* If it's ref'd still, unmark stat'd to force new lookup */
+ if ((vnode_vtype(ovp) != avc->f.m.Type) && VREFCOUNT_GT(avc, 1))
+ avc->f.states &= ~CStatd;
+
+ vnode_put(ovp);
+ vnode_rele(ovp);
+ AFS_GLOCK();
+ if (!locked)
+ ReleaseWriteLock(&avc->lock);
+ if (!error)
+ afs_osi_Wakeup(&avc->f.states);
+ if (!locked)
+ AFS_GUNLOCK();
+ return error;
}
#endif