add support for faking it. no exported interface exists, sadly.
currently does only authentication events, and is best-effort only,
however for people who get tokens after viewing directories in finder,
this is a drastic improvement.
also adds needed setting to afssettings plist
FIXES 23781
Change-Id: I46d5a6cf103c30a2134decccc929e1ef85a26726
Reviewed-on: http://gerrit.openafs.org/451
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>
extern vfs_context_t afs_osi_ctxtp;
extern int afs_osi_ctxtp_initialized;
#endif
+extern u_int32_t afs_darwin_realmodes;
+extern u_int32_t afs_darwin_fsevents;
/*
* Time related macros
#endif
#ifdef AFS_DARWIN80_ENV
+/* works like PFlushVolumeData */
+void
+darwin_notify_perms(struct unixuser *auser, int event)
+{
+ int i;
+ struct afs_q *tq, *uq = NULL;
+ struct vcache *tvc, *hnext;
+ int isglock = ISAFS_GLOCK();
+ struct vnode *vp;
+ struct vnode_attr va;
+
+ if (!afs_darwin_fsevents)
+ return;
+
+ VATTR_INIT(&va);
+ VATTR_SET(&va, va_mode, 0777);
+ if (event & UTokensObtained)
+ VATTR_SET(&va, va_uid, auser->uid);
+ else
+ VATTR_SET(&va, va_uid, -2); /* nobody */
+
+ get_vfs_context();
+ if (!isglock)
+ AFS_GLOCK();
+loop:
+ ObtainReadLock(&afs_xvcache);
+ for (i = 0; i < VCSIZE; i++) {
+ for (tq = afs_vhashTV[i].prev; tq != &afs_vhashTV[i]; tq = uq) {
+ uq = QPrev(tq);
+ tvc = QTOVH(tq);
+ if (tvc->f.states & CDeadVnode) {
+ /* we can afford to be best-effort */
+ continue;
+ }
+ /* no per-file acls, so only notify on directories */
+ if (!(vp = AFSTOV(tvc)) || !vnode_isdir(AFSTOV(tvc)))
+ continue;
+ /* dynroot object. no callbacks. anonymous ACL. just no. */
+ if (afs_IsDynrootFid(tvc))
+ continue;
+ /* no fake fsevents on mount point sources. leaks refs */
+ if (tvc->mvstat == 1)
+ continue;
+ /* if it's being reclaimed, just pass */
+ if (vnode_get(vp))
+ continue;
+ if (vnode_ref(vp)) {
+ AFS_GUNLOCK();
+ vnode_put(vp);
+ AFS_GLOCK();
+ continue;
+ }
+ ReleaseReadLock(&afs_xvcache);
+ ObtainWriteLock(&tvc->lock, 234);
+ tvc->f.states |= CEvent;
+ AFS_GUNLOCK();
+ vnode_setattr(vp, &va, afs_osi_ctxtp);
+ tvc->f.states &= ~CEvent;
+ vnode_put(vp);
+ AFS_GLOCK();
+ ReleaseWriteLock(&tvc->lock);
+ ObtainReadLock(&afs_xvcache);
+ /* our tvc ptr is still good until now */
+ AFS_FAST_RELE(tvc);
+ }
+ }
+ ReleaseReadLock(&afs_xvcache);
+ if (!isglock)
+ AFS_GUNLOCK();
+ put_vfs_context();
+}
+
int
osi_lookupname_user(user_addr_t aname, enum uio_seg seg, int followlink,
struct vnode **vpp) {
extern afs_rwlock_t afs_xosi;
/* osi_misc.c */
+extern void darwin_notify_perms(struct unixuser *auser, int event);
extern int osi_lookupname(char *aname, enum uio_seg seg, int followlink,
struct vnode **vpp);
extern int osi_lookupname_user(user_addr_t aname, enum uio_seg seg,
}
u_int32_t afs_darwin_realmodes = 0;
+u_int32_t afs_darwin_fsevents = 0;
+
+int
+afs_sysctl_int(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
+ user_addr_t newp, size_t newlen, u_int32_t *object)
+{
+#ifdef AFS_DARWIN80_ENV
+ int error;
+
+ if (oldp != USER_ADDR_NULL && oldlenp == NULL)
+ return (EFAULT);
+ if (oldp && *oldlenp < sizeof(u_int32_t))
+ return (ENOMEM);
+ if (newp && newlen != sizeof(u_int32_t))
+ return (EINVAL);
+ *oldlenp = sizeof(u_int32_t);
+ if (oldp) {
+ if ((error = copyout(object,
+ oldp, sizeof(u_int32_t)))) {
+ return error;
+ }
+ }
+ if (newp)
+ return copyin(newp, object, sizeof(u_int32_t));
+ return 0;
+#else
+ return sysctl_int(oldp, oldlenp, newp, newlen,
+ object);
+#endif
+}
#ifdef AFS_DARWIN80_ENV
-int afs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
+int
+afs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
user_addr_t newp, size_t newlen, vfs_context_t context)
#else
-int afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+int
+afs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen, struct proc *p)
#endif
{
- int error;
-
switch (name[0]) {
case AFS_SC_ALL:
/* nothing defined */
case AFS_SC_DARWIN_ALL:
switch (name[2]) {
case AFS_SC_DARWIN_ALL_REALMODES:
-#ifdef AFS_DARWIN80_ENV
- if (oldp != USER_ADDR_NULL && oldlenp == NULL)
- return (EFAULT);
- if (oldp && *oldlenp < sizeof(u_int32_t))
- return (ENOMEM);
- if (newp && newlen != sizeof(u_int32_t))
- return (EINVAL);
- *oldlenp = sizeof(u_int32_t);
- if (oldp) {
- if ((error = copyout(&afs_darwin_realmodes,
- oldp, sizeof(u_int32_t)))) {
- return error;
- }
- }
- if (newp)
- return copyin(newp, &afs_darwin_realmodes,
- sizeof(u_int32_t));
- return 0;
-#else
- return sysctl_int(oldp, oldlenp, newp, newlen,
- &afs_darwin_realmodes);
-#endif
+ return afs_sysctl_int(name, namelen, oldp, oldlenp,
+ newp, newlen, &afs_darwin_realmodes);
+ case AFS_SC_DARWIN_ALL_FSEVENTS:
+ return afs_sysctl_int(name, namelen, oldp, oldlenp,
+ newp, newlen, &afs_darwin_fsevents);
}
break;
/* darwin version specific sysctl's goes here */
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)
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);
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)))
{
int code;
- 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
+ /* 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);
* } */ *ap;
{
int code;
+#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);
/* This is legit; it just forces the fstrace event to happen */
}
#if defined(AFS_DARWIN_ENV)
{
- extern u_int32_t afs_darwin_realmodes;
if (!afs_darwin_realmodes) {
/* Mac OS X uses the mode bits to determine whether a file or
* directory is accessible, and believes them, even though under
*/
#define TMP_UPAGNotReferenced 128
+/* unixuser notify events */
+#define UTokensObtained 1
+#define UTokensDropped 2
+
/* values for afs_gcpags */
enum { AFS_GCPAGS_NOTCOMPILED = 0, AFS_GCPAGS_OK =
1, AFS_GCPAGS_USERDISABLED, AFS_GCPAGS_EPROC0, AFS_GCPAGS_EPROCN,
#define CVFlushed 0x00080000
#ifdef AFS_LINUX22_ENV
#define CPageWrite 0x00200000 /* to detect vm deadlock - linux */
-#else
+#elif defined(AFS_SGI_ENV)
#define CWritingUFS 0x00200000 /* to detect vm deadlock - used by sgi */
+#elif defined(AFS_DARWIN80_ENV)
+#define CEvent 0x00200000 /* to preclude deadlock when sending events */
#endif
#define CCreating 0x00400000 /* avoid needless store after open truncate */
#define CPageHog 0x00800000 /* AIX - dumping large cores is a page hog. */
} else if (acode == RXKADEXPIRED) {
aconn->forceConnectFS = 0; /* don't check until new tokens set */
aconn->user->states |= UTokensBad;
+ afs_NotifyUser(tu, UTokensDropped);
afs_warnuser
("afs: Tokens for user of AFS id %d for cell %s have expired\n",
tu->vid, aconn->srvr->server->cell->cellName);
areq->tokenError = 0;
aconn->forceConnectFS = 0; /* don't check until new tokens set */
aconn->user->states |= UTokensBad;
+ afs_NotifyUser(tu, UTokensDropped);
afs_warnuser
("afs: Tokens for user of AFS id %d for cell %s are discarded (rxkad error=%d)\n",
tu->vid, aconn->srvr->server->cell->cellName, acode);
} else if (acode == RXKADEXPIRED) {
aconn->forceConnectFS = 0; /* don't check until new tokens set */
aconn->user->states |= UTokensBad;
+ afs_NotifyUser(tu, UTokensDropped);
afs_warnuser
("afs: Tokens for user %d for cell %s have expired\n",
areq->uid, aconn->srvr->server->cell->cellName);
} else {
aconn->forceConnectFS = 0; /* don't check until new tokens set */
aconn->user->states |= UTokensBad;
+ afs_NotifyUser(tu, UTokensDropped);
afs_warnuser
("afs: Tokens for user %d for cell %s are discarded (rxkad error = %d)\n",
areq->uid, aconn->srvr->server->cell->cellName, acode);
afs_SetPrimary(tu, flag);
tu->tokenTime = osi_Time();
afs_ResetUserConns(tu);
+ afs_NotifyUser(tu, UTokensObtained);
afs_PutUser(tu, WRITE_LOCK);
return 0;
if (((tu->states & UHasTokens) == 0)
|| (tu->ct.EndTimestamp < osi_Time())) {
tu->states |= (UTokensBad | UNeedsReset);
+ afs_NotifyUser(tu, UTokensDropped);
afs_PutUser(tu, READ_LOCK);
return ENOTCONN;
}
memset(&tu->ct, 0, sizeof(struct ClearToken));
tu->refCount++;
ReleaseWriteLock(&afs_xuser);
+ afs_NotifyUser(tu, UTokensDropped);
/* We have to drop the lock over the call to afs_ResetUserConns,
* since it obtains the afs_xvcache lock. We could also keep
* the lock, and modify ResetUserConns to take parm saying we
afs_int32 locktype);
extern struct unixuser *afs_GetUser(register afs_int32 auid, afs_int32 acell,
afs_int32 locktype);
+extern void afs_NotifyUser(struct unixuser *auser, int event);
+
#if AFS_GCPAGS
extern afs_int32 afs_GCPAGs(afs_int32 * ReleasedCount);
extern void afs_GCPAGs_perproc_func(afs_proc_t * pproc);
} /*afs_SetPrimary */
+void
+afs_NotifyUser(struct unixuser *auser, int event)
+{
+#ifdef AFS_DARWIN_ENV
+ darwin_notify_perms(auser, event);
+#endif
+}
/**
* Mark all of the unixuser records held for a particular PAG as
# make config/settings.plist if it doesn't exist
if [ ! -e config/settings.plist -a -e config/settings.plist.orig ]; then
cp config/settings.plist.orig config/settings.plist
+ else
+ /usr/libexec/PlistBuddy -c "Add :Darwin:All:FSEvents bool" config/settings.plist && /usr/libexec/PlistBuddy -c "Set :Darwin:All:FSEvents true" config/settings.plist
fi
elif [ -e config/afssettings ]; then
# turn off execution of afssettings
<dict>
<key>RealModes</key>
<false/>
+ <key>FSEvents</key>
+ <true/>
</dict>
</dict>
</dict>