FIXES 1363
* Allow AFS to be mounted multiple times, each mountpoint with its
own root volume. This allows usage similar to the Windows client,
e.g., mounting a drive that contains only the user's home
directory. Our users find this much easier to work with than
having to navigate the entire AFS tree in the Finder or open/save
dialog.
* Have afsd register /afs with the DiskArbitration system
when mounting it. This means that the root afs volume shows up in
the Finder immediately, and prevents the Finder from getting
confused by additional AFS volumes later on.
* Add a "-nomount" option to afsd, which prevents afsd from
mounting /afs. We use this by default on our Mac OS X client, so
that AFS doesn't show up in the interface at all unless the user
explicitly asks for an AFS volume to be mounted. This is
especially handy for portable or remote users who don't always
have a network connection, since there isn't an AFS filesystem
around to hang the Finder if the AFS servers can't be contacted
(the cache manager may still hang, but since there are no AFS
volumes mounted, the rest of the OS doesn't notice).
* Make it so that /afs (mounted by afsd) will not unmount unless
MNT_FORCE is given. This prevents the user from accidentally
ejecting /afs in the Finder, and also works around a DiskArb bug in
Mac OS X (possibly fixed in 10.2) where autodiskmount would sometimes
unmount /afs when logging out, even though it's marked as
non-ejectable.
(cherry picked from commit
26ee3fcc3947c8df88b5e95d413b5144f13c7e6a)
AFS_GLOCK();
AFS_STATCNT(afs_mount);
- if (afs_globalVFS) { /* Don't allow remounts. */
+ if (data == NULL && afs_globalVFS) { /* Don't allow remounts. */
AFS_GUNLOCK();
return (EBUSY);
}
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
- strcpy(mp->mnt_stat.f_mntfromname, "AFS");
- /* null terminated string "AFS" will fit, just leave it be. */
+
+ if (data == NULL) {
+ strcpy(mp->mnt_stat.f_mntfromname, "AFS");
+ /* null terminated string "AFS" will fit, just leave it be. */
+ mp->mnt_data = (qaddr_t)NULL;
+ } else {
+ struct VenusFid *rootFid = NULL;
+ struct volume *tvp;
+ char volName[MNAMELEN];
+
+ (void) copyinstr((char *)data, volName, MNAMELEN-1, &size);
+ memset(volName + size, 0, MNAMELEN - size);
+
+ if (volName[0] == 0) {
+ strcpy(mp->mnt_stat.f_mntfromname, "AFS");
+ mp->mnt_data = (qaddr_t)&afs_rootFid;
+ } else {
+ struct cell *localcell = afs_GetPrimaryCell(READ_LOCK);
+ if (localcell == NULL) {
+ AFS_GUNLOCK();
+ return ENODEV;
+ }
+
+ /* Set the volume identifier to "AFS:volume.name" */
+ snprintf(mp->mnt_stat.f_mntfromname, MNAMELEN-1, "AFS:%s",
+ volName);
+ tvp = afs_GetVolumeByName(volName, localcell->cellNum, 1,
+ (struct vrequest *)0, READ_LOCK);
+
+ if (tvp) {
+ int volid = (tvp->roVol ? tvp->roVol : tvp->volume);
+ MALLOC(rootFid, struct VenusFid *, sizeof(*rootFid),
+ M_UFSMNT, M_WAITOK);
+ rootFid->Cell = localcell->cellNum;
+ rootFid->Fid.Volume = volid;
+ rootFid->Fid.Vnode = 1;
+ rootFid->Fid.Unique = 1;
+ } else {
+ AFS_GUNLOCK();
+ return ENODEV;
+ }
+
+ mp->mnt_data = (qaddr_t)rootFid;
+ }
+ }
strcpy(mp->mnt_stat.f_fstypename, "afs");
AFS_GUNLOCK();
(void) afs_statfs(mp, &mp->mnt_stat, p);
AFS_GLOCK();
AFS_STATCNT(afs_unmount);
- afs_globalVFS = 0;
- afs_shutdown();
+
+ if (mp->mnt_data != (qaddr_t)-1) {
+ if (mp->mnt_data != NULL) {
+ FREE(mp->mnt_data, M_UFSMNT);
+ mp->mnt_data = (qaddr_t)-1;
+ } else {
+ if (flags & MNT_FORCE) {
+ afs_globalVFS = 0;
+ afs_shutdown();
+ } else {
+ AFS_GUNLOCK();
+ return EBUSY;
+ }
+ }
+ mp->mnt_flag &= ~MNT_LOCAL;
+ }
+
AFS_GUNLOCK();
return 0;
pcred_unlock(p);
AFS_GLOCK();
AFS_STATCNT(afs_root);
- if (afs_globalVp && (afs_globalVp->states & CStatd)) {
+ if (mp->mnt_data == NULL
+ && afs_globalVp && (afs_globalVp->states & CStatd)) {
tvp = afs_globalVp;
error=0;
+ } else if (mp->mnt_data == (qaddr_t)-1) {
+ error = ENOENT;
} else {
+ struct VenusFid *rootFid = (mp->mnt_data == NULL)
+ ? &afs_rootFid : (struct VenusFid *)mp->mnt_data;
if (!(error = afs_InitReq(&treq, &cr)) &&
!(error = afs_CheckInit())) {
- tvp = afs_GetVCache(&afs_rootFid, &treq, (afs_int32 *)0,
+ tvp = afs_GetVCache(rootFid, &treq, (afs_int32 *)0,
(struct vcache*)0, WRITE_LOCK);
/* we really want this to stay around */
if (tvp) {
- afs_globalVp = tvp;
+ if (mp->mnt_data == NULL)
+ afs_globalVp = tvp;
} else
error = ENOENT;
}
AFS_GUNLOCK();
vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, p);
AFS_GLOCK();
- afs_globalVFS = mp;
+ if (mp->mnt_data == NULL) {
+ afs_globalVFS = mp;
+ }
*vpp = AFSTOV(tvp);
AFSTOV(tvp)->v_flag |= VROOT;
+ AFSTOV(tvp)->v_vfsp = mp;
}
afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
}
error = vget(vp, lfl, current_proc());
if (!error)
- insmntque(vp, afs_globalVFS); /* take off free list */
+ insmntque(vp, mp); /* take off free list */
return error;
}
return (error);
}
vp = AFSTOV(vcp); /* always get a node if no error */
+ vp->v_vfsp = dvp->v_vfsp;
/* The parent directory comes in locked. We unlock it on return
unless the caller wants it left locked.
if (vcp) {
*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))
GETNAME();
p=cnp->cn_proc;
- if (dvp->v_mount != vp->v_mount) {
- VOP_ABORTOP(vp, cnp);
- error = EXDEV;
- goto out;
- }
if (vp->v_type == VDIR) {
VOP_ABORTOP(vp, cnp);
error = EISDIR;
register struct vnode *fdvp = ap->a_fdvp;
struct proc *p=fcnp->cn_proc;
- /*
- * Check for cross-device rename.
- */
- if ((fvp->v_mount != tdvp->v_mount) ||
- (tvp && (fvp->v_mount != tvp->v_mount))) {
- error = EXDEV;
-abortit:
- VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
- if (tdvp == tvp)
- vrele(tdvp);
- else
- vput(tdvp);
- if (tvp)
- vput(tvp);
- VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
- vrele(fdvp);
- vrele(fvp);
- return (error);
- }
/*
* if fvp == tvp, we're just removing one name of a pair of
* directory entries for the same element. convert call into rename.
if (fvp == tvp) {
if (fvp->v_type == VDIR) {
error = EINVAL;
- goto abortit;
+ abortit:
+ VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
}
/* Release destination completely. */
}
if (vcp) {
*ap->a_vpp = AFSTOV(vcp);
+ (*ap->a_vpp)->v_vfsp = dvp->v_vfsp;
vn_lock(*ap->a_vpp, LK_EXCLUSIVE|LK_RETRY, p);
} else
*ap->a_vpp = 0;
#endif
afs_cold_shutdown = 0;
if (parm == 1) afs_cold_shutdown = 1;
+#ifndef AFS_DARWIN_ENV
if (afs_globalVFS != 0)
afs_warn("AFS isn't unmounted yet!\n");
+#endif
afs_shutdown();
}
${CC} ${CFLAGS} -g -o afsd afsd.o $(NON_SHARED) $(LDFLAGS) $(AFSLIBS) ${XLIBS} /usr/lib/libdwarf.a /usr/lib/libelf.a ;; \
sgi_64 | sgi_65 ) \
${CC} ${CFLAGS} -g -o afsd afsd.o $(NON_SHARED) $(LDFLAGS) $(AFSLIBS) ${XLIBS} /usr/lib32/libdwarf.a /usr/lib32/libelf.a ;; \
+ ppc_darwin* ) \
+ ${CC} ${CFLAGS} -g -o afsd afsd.o $(NON_SHARED) $(LDFLAGS) $(AFSLIBS) ${XLIBS} -F/System/Library/PrivateFrameworks -framework DiskArbitration ;; \
* ) \
${CC} ${CFLAGS} -g -o afsd afsd.o $(NON_SHARED) $(LDFLAGS) $(AFSLIBS) ${XLIBS} ;; \
esac
#ifdef AFS_LINUX20_ENV
#include <sys/resource.h>
#endif
+#ifdef AFS_DARWIN_ENV
+#include <mach/mach.h>
+/* Relevant definitions from DiskArbitration.h (not included with Mac OS X) */
+#ifndef __DISKARBITRATION_H
+typedef char DiskArbDiskIdentifier[1024];
+typedef char DiskArbMountpoint[1024];
+kern_return_t DiskArbStart(mach_port_t * portPtr);
+kern_return_t DiskArbDiskAppearedWithMountpointPing_auto(
+ DiskArbDiskIdentifier diskIdentifier,
+ unsigned flags,
+ DiskArbMountpoint mountpoint);
+kern_return_t DiskArbDiskDisappearedPing_auto(
+ DiskArbDiskIdentifier diskIdentifier,
+ unsigned flags);
+enum {
+ kDiskArbDiskAppearedNoFlags = 0x00000000,
+ kDiskArbDiskAppearedEjectableMask = 1 << 1,
+ kDiskArbDiskAppearedNetworkDiskMask = 1 << 3
+};
+#endif /* __DISKARBITRATION_H */
+#endif /* AFS_DARWIN_ENV */
#ifndef MOUNT_AFS
#define MOUNT_AFS AFS_MOUNT_AFS
#endif
static int enable_dynroot = 0; /* enable dynroot support */
static int enable_fakestat = 0; /* enable fakestat support */
+static int enable_nomount = 0; /* do not mount */
#ifdef notdef
static int inodes = 60; /* VERY conservative, but has to be */
#endif
/* -fakestat-all */
enable_fakestat = 1;
}
+ if (as->parms[29].items) {
+ /* -nomount */
+ enable_nomount = 1;
+ }
/*
* Pull out all the configuration info for the workstation's AFS cache and
exit(1);
}
+ if (!enable_nomount) {
+
mountFlags = 0; /* Read/write file system, can do setuid() */
#if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
#ifdef AFS_SUN5_ENV
HandleMTab();
+ }
+
if (afsd_rmtsys) {
if (afsd_verbose)
printf("%s: Forking 'rmtsys' daemon.\n", rn);
cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL, "Enable dynroot support");
cmd_AddParm(ts, "-fakestat", CMD_FLAG, CMD_OPTIONAL, "Enable fakestat support for cross-cell mounts");
cmd_AddParm(ts, "-fakestat-all", CMD_FLAG, CMD_OPTIONAL, "Enable fakestat support for all mounts");
+ cmd_AddParm(ts, "-nomount", CMD_FLAG, CMD_OPTIONAL, "Do not mount AFS");
return (cmd_Dispatch(argc, argv));
}
#endif /* AFS_SGI_ENV */
#endif /* AFS_SUN5_ENV */
#endif /* unreasonable systems */
+#ifdef AFS_DARWIN_ENV
+ mach_port_t diskarb_port;
+ kern_return_t status;
+
+ status = DiskArbStart(&diskarb_port);
+ if (status == KERN_SUCCESS) {
+ status = DiskArbDiskAppearedWithMountpointPing_auto("AFS",
+ kDiskArbDiskAppearedNetworkDiskMask, cacheMountDir);
+ }
+
+ return status;
+#endif /* AFS_DARWIN_ENV */
return 0;
}