From bdbfda392d0364c6daa68e7d218870190bf36414 Mon Sep 17 00:00:00 2001 From: Alexei Kosut Date: Thu, 15 May 2003 16:09:00 +0000 Subject: [PATCH] STABLE12-darwin-mount-and-disk-arbitration-enhancements-20030515 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) --- src/afs/DARWIN/osi_vfsops.c | 87 +++++++++++++++++++++++++++++++---- src/afs/DARWIN/osi_vnodeops.c | 40 ++++++---------- src/afs/afs_call.c | 2 + src/afsd/Makefile.in | 2 + src/afsd/afsd.c | 43 +++++++++++++++++ 5 files changed, 139 insertions(+), 35 deletions(-) diff --git a/src/afs/DARWIN/osi_vfsops.c b/src/afs/DARWIN/osi_vfsops.c index 785e8cec6..2ca43a862 100644 --- a/src/afs/DARWIN/osi_vfsops.c +++ b/src/afs/DARWIN/osi_vfsops.c @@ -67,7 +67,7 @@ struct proc *p; 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); } @@ -80,8 +80,51 @@ struct proc *p; (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); @@ -97,8 +140,23 @@ struct proc *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; @@ -119,18 +177,24 @@ afs_root(struct mount *mp, 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; } @@ -140,9 +204,12 @@ afs_root(struct mount *mp, 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, @@ -165,7 +232,7 @@ int lfl; } 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; } diff --git a/src/afs/DARWIN/osi_vnodeops.c b/src/afs/DARWIN/osi_vnodeops.c index 5a510c075..81982745b 100644 --- a/src/afs/DARWIN/osi_vnodeops.c +++ b/src/afs/DARWIN/osi_vnodeops.c @@ -173,6 +173,7 @@ struct vop_lookup_args /* { 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. @@ -237,6 +238,7 @@ afs_vop_create(ap) 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)) @@ -810,11 +812,6 @@ afs_vop_link(ap) 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; @@ -858,25 +855,6 @@ afs_vop_rename(ap) 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. @@ -885,7 +863,18 @@ abortit: 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. */ @@ -968,6 +957,7 @@ afs_vop_mkdir(ap) } 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; diff --git a/src/afs/afs_call.c b/src/afs/afs_call.c index ad47c04d1..272e00499 100644 --- a/src/afs/afs_call.c +++ b/src/afs/afs_call.c @@ -731,8 +731,10 @@ long parm, parm2, parm3, parm4, parm5, parm6; #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(); } diff --git a/src/afsd/Makefile.in b/src/afsd/Makefile.in index 9d4ab4542..f07062e07 100644 --- a/src/afsd/Makefile.in +++ b/src/afsd/Makefile.in @@ -52,6 +52,8 @@ afsd: afsd.o $(AFSLIBS) ${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 diff --git a/src/afsd/afsd.c b/src/afsd/afsd.c index 5afd464b0..a9ec41dbc 100644 --- a/src/afsd/afsd.c +++ b/src/afsd/afsd.c @@ -146,6 +146,27 @@ void set_staticaddrs(void); #ifdef AFS_LINUX20_ENV #include #endif +#ifdef AFS_DARWIN_ENV +#include +/* 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 @@ -246,6 +267,7 @@ static int enable_afsdb = 0; /* enable AFSDB support */ #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 @@ -1343,6 +1365,10 @@ mainproc(as, arock) /* -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 @@ -1811,6 +1837,8 @@ mainproc(as, arock) 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 @@ -1893,6 +1921,8 @@ mainproc(as, arock) HandleMTab(); + } + if (afsd_rmtsys) { if (afsd_verbose) printf("%s: Forking 'rmtsys' daemon.\n", rn); @@ -1956,6 +1986,7 @@ char **argv; { 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)); } @@ -2029,6 +2060,18 @@ static int HandleMTab() { #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; } -- 2.39.5