示例#1
0
afs_link(struct vcache *avc, OSI_VC_DECL(adp), char *aname, 
	 afs_ucred_t *acred)
#endif
{
    struct vrequest treq;
    struct dcache *tdc;
    afs_int32 code;
    struct afs_conn *tc;
    afs_size_t offset, len;
    struct AFSFetchStatus OutFidStatus, OutDirStatus;
    struct AFSVolSync tsync;
    struct afs_fakestat_state vfakestate, dfakestate;
    struct rx_connection *rxconn;
    XSTATS_DECLS;
    OSI_VC_CONVERT(adp);

    AFS_STATCNT(afs_link);
    afs_Trace3(afs_iclSetp, CM_TRACE_LINK, ICL_TYPE_POINTER, adp,
	       ICL_TYPE_POINTER, avc, ICL_TYPE_STRING, aname);
    /* create a hard link; new entry is aname in dir adp */
    if ((code = afs_InitReq(&treq, acred)))
	goto done2;

    afs_InitFakeStat(&vfakestate);
    afs_InitFakeStat(&dfakestate);
    
    AFS_DISCON_LOCK();

    code = afs_EvalFakeStat(&avc, &vfakestate, &treq);
    if (code)
	goto done;
    code = afs_EvalFakeStat(&adp, &dfakestate, &treq);
    if (code)
	goto done;

    if (avc->f.fid.Cell != adp->f.fid.Cell
	|| avc->f.fid.Fid.Volume != adp->f.fid.Fid.Volume) {
	code = EXDEV;
	goto done;
    }
    if (strlen(aname) > AFSNAMEMAX) {
	code = ENAMETOOLONG;
	goto done;
    }
    code = afs_VerifyVCache(adp, &treq);
    if (code)
	goto done;

    /** If the volume is read-only, return error without making an RPC to the
      * fileserver
      */
    if (adp->f.states & CRO) {
	code = EROFS;
	goto done;
    }
    
    if (AFS_IS_DISCONNECTED) {
        code = ENETDOWN;
        goto done;
    }

    tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);	/* test for error below */
    ObtainWriteLock(&adp->lock, 145);
    do {
	tc = afs_Conn(&adp->f.fid, &treq, SHARED_LOCK, &rxconn);
	if (tc) {
	    XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_LINK);
	    RX_AFS_GUNLOCK();
	    code =
		RXAFS_Link(rxconn, (struct AFSFid *)&adp->f.fid.Fid, aname,
			   (struct AFSFid *)&avc->f.fid.Fid, &OutFidStatus,
			   &OutDirStatus, &tsync);
	    RX_AFS_GLOCK();
	    XSTATS_END_TIME;

	} else
	    code = -1;
    } while (afs_Analyze
	     (tc, rxconn, code, &adp->f.fid, &treq, AFS_STATS_FS_RPCIDX_LINK,
	      SHARED_LOCK, NULL));

    if (code) {
	if (tdc)
	    afs_PutDCache(tdc);
	if (code < 0) {
	    ObtainWriteLock(&afs_xcbhash, 492);
	    afs_DequeueCallback(adp);
	    adp->f.states &= ~CStatd;
	    ReleaseWriteLock(&afs_xcbhash);
	    osi_dnlc_purgedp(adp);
	}
	ReleaseWriteLock(&adp->lock);
	goto done;
    }
    if (tdc)
	ObtainWriteLock(&tdc->lock, 635);
    if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
	/* we can do it locally */
	ObtainWriteLock(&afs_xdcache, 290);
	code = afs_dir_Create(tdc, aname, &avc->f.fid.Fid);
	ReleaseWriteLock(&afs_xdcache);
	if (code) {
	    ZapDCE(tdc);	/* surprise error -- invalid value */
	    DZap(tdc);
	}
    }
    if (tdc) {
	ReleaseWriteLock(&tdc->lock);
	afs_PutDCache(tdc);	/* drop ref count */
    }
    ReleaseWriteLock(&adp->lock);
    ObtainWriteLock(&avc->lock, 146);	/* correct link count */

    /* we could lock both dir and file; since we get the new fid
     * status back, you'd think we could put it in the cache status
     * entry at that point.  Note that if we don't lock the file over
     * the rpc call, we have no guarantee that the status info
     * returned in ustat is the most recent to store in the file's
     * cache entry */

    ObtainWriteLock(&afs_xcbhash, 493);
    afs_DequeueCallback(avc);
    avc->f.states &= ~CStatd;	/* don't really know new link count */
    ReleaseWriteLock(&afs_xcbhash);
    if (avc->f.fid.Fid.Vnode & 1 || (vType(avc) == VDIR))
	osi_dnlc_purgedp(avc);
    ReleaseWriteLock(&avc->lock);
    code = 0;
  done:
    code = afs_CheckCode(code, &treq, 24);
    afs_PutFakeStat(&vfakestate);
    afs_PutFakeStat(&dfakestate);
    AFS_DISCON_UNLOCK();
  done2:
    return code;
}
示例#2
0
int
afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, 
     struct vcache **avcp, afs_ucred_t *acred)
{
    struct vrequest *treq = NULL;
    afs_int32 code;
    struct afs_conn *tc;
    struct rx_connection *rxconn;
    struct VenusFid newFid;
    struct dcache *tdc;
    struct dcache *new_dc;
    afs_size_t offset, len;
    struct vcache *tvc;
    struct AFSStoreStatus InStatus;
    struct AFSFetchStatus *OutFidStatus, *OutDirStatus;
    struct AFSCallBack CallBack;
    struct AFSVolSync tsync;
    afs_int32 now;
    struct afs_fakestat_state fakestate;
    XSTATS_DECLS;
    OSI_VC_CONVERT(adp);

    AFS_STATCNT(afs_mkdir);
    afs_Trace2(afs_iclSetp, CM_TRACE_MKDIR, ICL_TYPE_POINTER, adp,
	       ICL_TYPE_STRING, aname);

    OutFidStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
    OutDirStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
    memset(&InStatus, 0, sizeof(InStatus));

    if ((code = afs_CreateReq(&treq, acred)))
	goto done2;
    afs_InitFakeStat(&fakestate);

    if (strlen(aname) > AFSNAMEMAX) {
	code = ENAMETOOLONG;
	goto done3;
    }

    if (!afs_ENameOK(aname)) {
	code = EINVAL;
	goto done3;
    }
    
    AFS_DISCON_LOCK();

    code = afs_EvalFakeStat(&adp, &fakestate, treq);
    if (code)
	goto done;
    code = afs_VerifyVCache(adp, treq);
    if (code)
	goto done;

    /** If the volume is read-only, return error without making an RPC to the
      * fileserver
      */
    if (adp->f.states & CRO) {
	code = EROFS;
	goto done;
    }
   
    if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
	/*printf("Network is down in afs_mkdir\n");*/
	code = ENETDOWN;
	goto done;
    }
    InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
    InStatus.ClientModTime = osi_Time();
    InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
    InStatus.Group = (afs_int32) afs_cr_gid(acred);
    tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);
    ObtainWriteLock(&adp->lock, 153);

    if (!AFS_IS_DISCON_RW) {
    	do {
	    tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
	    if (tc) {
	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
	    	now = osi_Time();
	    	RX_AFS_GUNLOCK();
	    	code =
		    RXAFS_MakeDir(rxconn,
		    		(struct AFSFid *)&adp->f.fid.Fid,
				aname,
				&InStatus,
				(struct AFSFid *)&newFid.Fid,
				OutFidStatus,
				OutDirStatus,
				&CallBack,
				&tsync);
	    	RX_AFS_GLOCK();
	    	XSTATS_END_TIME;
	    	CallBack.ExpirationTime += now;
	    	/* DON'T forget to Set the callback value... */
	    } else
	    	code = -1;
    	} while (afs_Analyze
		    (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_MAKEDIR,
		     SHARED_LOCK, NULL));

    	if (code) {
	    if (code < 0) {
		afs_StaleVCache(adp);
	    }
	    ReleaseWriteLock(&adp->lock);
	    if (tdc)
	    	afs_PutDCache(tdc);
	    goto done;
        }

    } else {
    	/* Disconnected. */

	/* We have the dir entry now, we can use it while disconnected. */
	if (adp->mvid.target_root == NULL) {
	    /* If not mount point, generate a new fid. */
	    newFid.Cell = adp->f.fid.Cell;
    	    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
	    afs_GenFakeFid(&newFid, VDIR, 1);
	}
    	/* XXX: If mount point???*/

	/* Operations with the actual dir's cache entry are further
	 * down, where the dir entry gets created.
	 */
    }			/* if (!AFS_IS_DISCON_RW) */

    /* otherwise, we should see if we can make the change to the dir locally */
    if (tdc)
	ObtainWriteLock(&tdc->lock, 632);
    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, OutDirStatus, 1)) {
	/* we can do it locally */
	ObtainWriteLock(&afs_xdcache, 294);
	code = afs_dir_Create(tdc, aname, &newFid.Fid);
	ReleaseWriteLock(&afs_xdcache);
	if (code) {
	    ZapDCE(tdc);	/* surprise error -- use invalid value */
	    DZap(tdc);
	}
    }
    if (tdc) {
	ReleaseWriteLock(&tdc->lock);
	afs_PutDCache(tdc);
    }

    if (AFS_IS_DISCON_RW)
	/* We will have to settle with the local link count. */
	adp->f.m.LinkCount++;
    else
	adp->f.m.LinkCount = OutDirStatus->LinkCount;
    newFid.Cell = adp->f.fid.Cell;
    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
    ReleaseWriteLock(&adp->lock);
    if (AFS_IS_DISCON_RW) {
    	/* When disconnected, we have to create the full dir here. */

	/* Generate a new vcache and fill it. */
	tvc = afs_NewVCache(&newFid, NULL);
	if (tvc) {
	    *avcp = tvc;
	} else {
	    code = EIO;
	    goto done;
	}

	ObtainWriteLock(&tvc->lock, 738);
	afs_GenDisconStatus(adp, tvc, &newFid, attrs, treq, VDIR);
	ReleaseWriteLock(&tvc->lock);

	/* And now make an empty dir, containing . and .. : */
	/* Get a new dcache for it first. */
	new_dc = afs_GetDCache(tvc, (afs_size_t) 0, treq, &offset, &len, 1);
	if (!new_dc) {
	    /* printf("afs_mkdir: can't get new dcache for dir.\n"); */
	    code = EIO;
	    goto done;
	}

	ObtainWriteLock(&afs_xdcache, 739);
	code = afs_dir_MakeDir(new_dc,
			       (afs_int32 *) &newFid.Fid,
			       (afs_int32 *) &adp->f.fid.Fid);
	ReleaseWriteLock(&afs_xdcache);
	/* if (code) printf("afs_mkdir: afs_dirMakeDir code = %u\n", code); */

	afs_PutDCache(new_dc);

	ObtainWriteLock(&tvc->lock, 731);
	/* Update length in the vcache. */
	tvc->f.m.Length = new_dc->f.chunkBytes;

	afs_DisconAddDirty(tvc, VDisconCreate, 1);
	ReleaseWriteLock(&tvc->lock);
    } else {
    	/* now we're done with parent dir, create the real dir's cache entry */
	tvc = afs_GetVCache(&newFid, treq, NULL, NULL);
    	if (tvc) {
	    code = 0;
	    *avcp = tvc;

	} else {
	    /* For some reason, we cannot fetch the vcache for our
	     * newly-created dir. */
	    code = EIO;
	}
    }				/* if (AFS_DISCON_RW) */

  done:
    AFS_DISCON_UNLOCK();
  done3:
    afs_PutFakeStat(&fakestate);
    code = afs_CheckCode(code, treq, 26);
    afs_DestroyReq(treq);
  done2:
    osi_FreeSmallSpace(OutFidStatus);
    osi_FreeSmallSpace(OutDirStatus);
    return code;
}
示例#3
0
afs_rmdir(OSI_VC_DECL(adp), char *aname, afs_ucred_t *acred)
#endif
{
    struct vrequest *treq = NULL;
    struct dcache *tdc;
    struct vcache *tvc = NULL;
    afs_int32 code;
    struct afs_conn *tc;
    afs_size_t offset, len;
    struct AFSFetchStatus OutDirStatus;
    struct AFSVolSync tsync;
    struct afs_fakestat_state fakestate;
    struct rx_connection *rxconn;
    XSTATS_DECLS;
    OSI_VC_CONVERT(adp);

    AFS_STATCNT(afs_rmdir);

    afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp,
	       ICL_TYPE_STRING, aname);

    if ((code = afs_CreateReq(&treq, acred)))
	goto done2;
    afs_InitFakeStat(&fakestate);

    if (strlen(aname) > AFSNAMEMAX) {
	code = ENAMETOOLONG;
	goto done;
    }

    AFS_DISCON_LOCK();

    code = afs_EvalFakeStat(&adp, &fakestate, treq);
    if (code)
	goto done;

    code = afs_VerifyVCache(adp, treq);
    if (code)
	goto done;

    /** If the volume is read-only, return error without making an RPC to the
      * fileserver
      */
    if (adp->f.states & CRO) {
	code = EROFS;
	goto done;
    }

   if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
    	/* Disconnected read only mode. */
        code = ENETDOWN;
        goto done;
    }

    tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);	/* test for error below */
    ObtainWriteLock(&adp->lock, 154);
    if (tdc)
	ObtainSharedLock(&tdc->lock, 633);
    if (tdc && (adp->f.states & CForeign)) {
	struct VenusFid unlinkFid;

	unlinkFid.Fid.Vnode = 0;
	code = afs_dir_Lookup(tdc, aname, &unlinkFid.Fid);
	if (code == 0) {
	    afs_int32 cached = 0;

	    unlinkFid.Cell = adp->f.fid.Cell;
	    unlinkFid.Fid.Volume = adp->f.fid.Fid.Volume;
	    if (unlinkFid.Fid.Unique == 0) {
		tvc =
		    afs_LookupVCache(&unlinkFid, treq, &cached, adp, aname);
	    } else {
		ObtainReadLock(&afs_xvcache);
		tvc = afs_FindVCache(&unlinkFid, 0, 1 /* do xstats */ );
		ReleaseReadLock(&afs_xvcache);
	    }
	}
    }

    if (!AFS_IS_DISCON_RW) {
	/* Not disconnected, can connect to server. */
    	do {
	    tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
	    if (tc) {
	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
	    	RX_AFS_GUNLOCK();
	    	code =
		    RXAFS_RemoveDir(rxconn,
		    		(struct AFSFid *)&adp->f.fid.Fid,
				aname,
				&OutDirStatus,
				&tsync);
	    	RX_AFS_GLOCK();
	    	XSTATS_END_TIME;
	    } else
	    	code = -1;
    	} while (afs_Analyze
	         (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_REMOVEDIR,
	         SHARED_LOCK, NULL));

    	if (code) {
	    if (tdc) {
	    	ReleaseSharedLock(&tdc->lock);
	    	afs_PutDCache(tdc);
	    }

	    if (code < 0) {
		afs_StaleVCache(adp);
	    }
	    ReleaseWriteLock(&adp->lock);
	    goto done;
    	}

    	/* here if rpc worked; update the in-core link count */
    	adp->f.m.LinkCount = OutDirStatus.LinkCount;

    } else {
    	/* Disconnected. */

	if (!tdc) {
	    ReleaseWriteLock(&adp->lock);
	    /* printf("afs_rmdir: No local dcache!\n"); */
	    code = ENETDOWN;
	    goto done;
	}
	
	if (!tvc) {
	    /* Find the vcache. */
	    struct VenusFid tfid;

	    tfid.Cell = adp->f.fid.Cell;
	    tfid.Fid.Volume = adp->f.fid.Fid.Volume;
	    code = afs_dir_Lookup(tdc, aname, &tfid.Fid);

	    ObtainSharedLock(&afs_xvcache, 764);
	    tvc = afs_FindVCache(&tfid, 0, 1 /* do xstats */ );
	    ReleaseSharedLock(&afs_xvcache);
	    
	    if (!tvc) {
		/* printf("afs_rmdir: Can't find dir's vcache!\n"); */
		ReleaseSharedLock(&tdc->lock);
	        afs_PutDCache(tdc);	/* drop ref count */
    	        ReleaseWriteLock(&adp->lock);
		code = ENETDOWN;
	        goto done;
	    }
	}

	if (tvc->f.m.LinkCount > 2) {
	    /* This dir contains more than . and .., thus it can't be
	     * deleted.
	     */
	    ReleaseSharedLock(&tdc->lock);
	    afs_PutDCache(tdc);
	    afs_PutVCache(tvc);
	    ReleaseWriteLock(&adp->lock);
	    code = ENOTEMPTY;
	    goto done;
	}

    	/* Make a shadow copy of the parent dir (if not done already).
	 * If we were created locally, then we don't need to have a shadow
	 * directory (as there's no server state to remember)
	 */
	if (!adp->f.shadow.vnode && !(adp->f.ddirty_flags & VDisconCreate)) {
	    afs_MakeShadowDir(adp, tdc);
	}

	adp->f.m.LinkCount--;
    }				/* if (!AFS_IS_DISCON_RW) */

    if (tdc)
	UpgradeSToWLock(&tdc->lock, 634);
    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
	/* we can do it locally */
	code = afs_dir_Delete(tdc, aname);
	if (code) {
	    ZapDCE(tdc);	/* surprise error -- invalid value */
	    DZap(tdc);
	}
    }
    if (tdc) {
	ReleaseWriteLock(&tdc->lock);
	afs_PutDCache(tdc);	/* drop ref count */
    }

    if (tvc)
	osi_dnlc_purgedp(tvc);	/* get rid of any entries for this directory */
    else
	osi_dnlc_remove(adp, aname, 0);

    if (tvc) {
	ObtainWriteLock(&tvc->lock, 155);
	tvc->f.states &= ~CUnique;	/* For the dfs xlator */
	if (AFS_IS_DISCON_RW) {
	    if (tvc->f.ddirty_flags & VDisconCreate) {
		/* If we we were created whilst disconnected, removal doesn't
		 * need to get logged. Just go away gracefully */
		afs_DisconRemoveDirty(tvc);
	    } else {
		afs_DisconAddDirty(tvc, VDisconRemove, 1);
	    }
	}
	ReleaseWriteLock(&tvc->lock);
	afs_PutVCache(tvc);
    }
    ReleaseWriteLock(&adp->lock);
    /* don't worry about link count since dirs can not be hardlinked */
    code = 0;

  done:
    AFS_DISCON_UNLOCK();
    afs_PutFakeStat(&fakestate);
    code = afs_CheckCode(code, treq, 27);
    afs_DestroyReq(treq);
  done2:
    return code;
}
/* don't set CDirty in here because RPC is called synchronously */
int
afs_symlink(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
            char *atargetName, struct AFS_UCRED *acred)
{
    afs_uint32 now = 0;
    struct vrequest treq;
    afs_int32 code = 0;
    struct afs_conn *tc;
    struct VenusFid newFid;
    struct dcache *tdc;
    afs_size_t offset, len;
    afs_int32 alen;
    struct server *hostp = 0;
    struct vcache *tvc;
    struct AFSStoreStatus InStatus;
    struct AFSFetchStatus OutFidStatus, OutDirStatus;
    struct AFSCallBack CallBack;
    struct AFSVolSync tsync;
    struct volume *volp = 0;
    struct afs_fakestat_state fakestate;
    XSTATS_DECLS;
    OSI_VC_CONVERT(adp);

    AFS_STATCNT(afs_symlink);
    afs_Trace2(afs_iclSetp, CM_TRACE_SYMLINK, ICL_TYPE_POINTER, adp,
               ICL_TYPE_STRING, aname);

    if ((code = afs_InitReq(&treq, acred)))
        goto done2;

    afs_InitFakeStat(&fakestate);

    AFS_DISCON_LOCK();

    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
    if (code)
        goto done;

    if (strlen(aname) > AFSNAMEMAX || strlen(atargetName) > AFSPATHMAX) {
        code = ENAMETOOLONG;
        goto done;
    }

    if (afs_IsDynroot(adp)) {
        code = afs_DynrootVOPSymlink(adp, acred, aname, atargetName);
        goto done;
    }
    if (afs_IsDynrootMount(adp)) {
        code = EROFS;
        goto done;
    }

    code = afs_VerifyVCache(adp, &treq);
    if (code) {
        code = afs_CheckCode(code, &treq, 30);
        goto done;
    }

    /** If the volume is read-only, return error without making an RPC to the
      * fileserver
      */
    if (adp->f.states & CRO) {
        code = EROFS;
        goto done;
    }

    if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
        code = ENETDOWN;
        goto done;
    }

    InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE;
    InStatus.ClientModTime = osi_Time();
    alen = strlen(atargetName);	/* we want it to include the null */
    if ( (*atargetName == '#' || *atargetName == '%') && alen > 1 && atargetName[alen-1] == '.') {
        InStatus.UnixModeBits = 0644;	/* mt pt: null from "." at end */
        if (alen == 1)
            alen++;		/* Empty string */
    } else {
        InStatus.UnixModeBits = 0755;
        alen++;			/* add in the null */
    }
    tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
    volp = afs_FindVolume(&adp->f.fid, READ_LOCK);	/*parent is also in same vol */
    ObtainWriteLock(&adp->lock, 156);
    if (tdc)
        ObtainWriteLock(&tdc->lock, 636);
    ObtainSharedLock(&afs_xvcache, 17);	/* prevent others from creating this entry */
    /* XXX Pay attention to afs_xvcache around the whole thing!! XXX */
    if (!AFS_IS_DISCON_RW) {
        do {
            tc = afs_Conn(&adp->f.fid, &treq, SHARED_LOCK);
            if (tc) {
                hostp = tc->srvr->server;
                XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_SYMLINK);
                if (adp->f.states & CForeign) {
                    now = osi_Time();
                    RX_AFS_GUNLOCK();
                    code =
                        RXAFS_DFSSymlink(tc->id,
                                         (struct AFSFid *)&adp->f.fid.Fid,
                                         aname, atargetName, &InStatus,
                                         (struct AFSFid *)&newFid.Fid,
                                         &OutFidStatus, &OutDirStatus,
                                         &CallBack, &tsync);
                    RX_AFS_GLOCK();
                } else {
                    RX_AFS_GUNLOCK();
                    code =
                        RXAFS_Symlink(tc->id, (struct AFSFid *)&adp->f.fid.Fid,
                                      aname, atargetName, &InStatus,
                                      (struct AFSFid *)&newFid.Fid,
                                      &OutFidStatus, &OutDirStatus, &tsync);
                    RX_AFS_GLOCK();
                }
                XSTATS_END_TIME;
            } else
                code = -1;
        } while (afs_Analyze
                 (tc, code, &adp->f.fid, &treq, AFS_STATS_FS_RPCIDX_SYMLINK,
                  SHARED_LOCK, NULL));
    } else {
#ifdef AFS_DISCON_ENV
        newFid.Cell = adp->f.fid.Cell;
        newFid.Fid.Volume = adp->f.fid.Fid.Volume;
        afs_GenFakeFid(&newFid, VREG, 0);
#endif
    }

    UpgradeSToWLock(&afs_xvcache, 40);
    if (code) {
        if (code < 0) {
            ObtainWriteLock(&afs_xcbhash, 499);
            afs_DequeueCallback(adp);
            adp->f.states &= ~CStatd;
            ReleaseWriteLock(&afs_xcbhash);
            osi_dnlc_purgedp(adp);
        }
        ReleaseWriteLock(&adp->lock);
        ReleaseWriteLock(&afs_xvcache);
        if (tdc) {
            ReleaseWriteLock(&tdc->lock);
            afs_PutDCache(tdc);
        }
        goto done;
    }
    /* otherwise, we should see if we can make the change to the dir locally */
    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
        /* we can do it locally */
        ObtainWriteLock(&afs_xdcache, 293);
        code = afs_dir_Create(tdc, aname, &newFid.Fid);
        ReleaseWriteLock(&afs_xdcache);
        if (code && !AFS_IS_DISCON_RW) {
            ZapDCE(tdc);	/* surprise error -- use invalid value */
            DZap(tdc);
        }
    }
    if (tdc) {
        ReleaseWriteLock(&tdc->lock);
        afs_PutDCache(tdc);
    }
    newFid.Cell = adp->f.fid.Cell;
    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
    ReleaseWriteLock(&adp->lock);

    /* now we're done with parent dir, create the link's entry.  Note that
     * no one can get a pointer to the new cache entry until we release
     * the xvcache lock. */
    tvc = afs_NewVCache(&newFid, hostp);
    if (!tvc)
    {
        code = -2;
        ReleaseWriteLock(&afs_xvcache);
        goto done;
    }
    ObtainWriteLock(&tvc->lock, 157);
    ObtainWriteLock(&afs_xcbhash, 500);
    tvc->f.states |= CStatd;	/* have valid info */
    tvc->f.states &= ~CBulkFetching;

    if (adp->f.states & CForeign) {
        tvc->f.states |= CForeign;
        /* We don't have to worry about losing the callback since we're doing it
         * under the afs_xvcache lock actually, afs_NewVCache may drop the
         * afs_xvcache lock, if it calls afs_FlushVCache */
        tvc->cbExpires = CallBack.ExpirationTime + now;
        afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
    } else {
        tvc->cbExpires = 0x7fffffff;	/* never expires, they can't change */
        /* since it never expires, we don't have to queue the callback */
    }
    ReleaseWriteLock(&afs_xcbhash);

    if (AFS_IS_DISCON_RW) {
#ifdef AFS_DISCON_ENV
        attrs->va_mode = InStatus.UnixModeBits;
        afs_GenDisconStatus(adp, tvc, &newFid, attrs, &treq, VLNK);
        code = afs_DisconCreateSymlink(tvc, atargetName, &treq);
        if (code) {
            /* XXX - When this goes wrong, we need to tidy up the changes we made to
             * the parent, and get rid of the vcache we just created */
            ReleaseWriteLock(&tvc->lock);
            ReleaseWriteLock(&afs_xvcache);
            afs_PutVCache(tvc);
            goto done;
        }
        afs_DisconAddDirty(tvc, VDisconCreate, 0);
#endif
    } else {
        afs_ProcessFS(tvc, &OutFidStatus, &treq);
    }

    if (!tvc->linkData) {
        tvc->linkData = (char *)afs_osi_Alloc(alen);
        strncpy(tvc->linkData, atargetName, alen - 1);
        tvc->linkData[alen - 1] = 0;
    }
    ReleaseWriteLock(&tvc->lock);
    ReleaseWriteLock(&afs_xvcache);
    afs_PutVCache(tvc);
    code = 0;
done:
    afs_PutFakeStat(&fakestate);
    if (volp)
        afs_PutVolume(volp, READ_LOCK);
    AFS_DISCON_UNLOCK();
    code = afs_CheckCode(code, &treq, 31);
done2:
    return code;
}
示例#5
0
/* question: does afs_create need to set CDirty in the adp or the avc?
 * I think we can get away without it, but I'm not sure.  Note that
 * afs_setattr is called in here for truncation.
 */
#ifdef AFS_SGI64_ENV
int
afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, int flags,
	   int amode, struct vcache **avcp, afs_ucred_t *acred)
#else /* AFS_SGI64_ENV */
int
afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
	   enum vcexcl aexcl, int amode, struct vcache **avcp,
	   afs_ucred_t *acred)
#endif				/* AFS_SGI64_ENV */
{
    afs_int32 origCBs, origZaps, finalZaps;
    struct vrequest treq;
    afs_int32 code;
    struct afs_conn *tc;
    struct VenusFid newFid;
    struct AFSStoreStatus InStatus;
    struct AFSFetchStatus OutFidStatus, OutDirStatus;
    struct AFSVolSync tsync;
    struct AFSCallBack CallBack;
    afs_int32 now;
    struct dcache *tdc;
    afs_size_t offset, len;
    struct server *hostp = 0;
    struct vcache *tvc;
    struct volume *volp = 0;
    struct afs_fakestat_state fakestate;
    struct rx_connection *rxconn;
    XSTATS_DECLS;
    OSI_VC_CONVERT(adp);


    AFS_STATCNT(afs_create);
    if ((code = afs_InitReq(&treq, acred)))
	goto done2;

    afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
	       ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);

    afs_InitFakeStat(&fakestate);

#ifdef AFS_SGI65_ENV
    /* If avcp is passed not null, it's the old reference to this file.
     * We can use this to avoid create races. For now, just decrement
     * the reference count on it.
     */
    if (*avcp) {
	AFS_RELE(AFSTOV(*avcp));
	*avcp = NULL;
    }
#endif

    if (strlen(aname) > AFSNAMEMAX) {
	code = ENAMETOOLONG;
	goto done3;
    }

    if (!afs_ENameOK(aname)) {
	code = EINVAL;
	goto done3;
    }
    switch (attrs->va_type) {
    case VBLK:
    case VCHR:
#if	!defined(AFS_SUN5_ENV)
    case VSOCK:
#endif
    case VFIFO:
	/* We don't support special devices or FIFOs */
	code = EINVAL;
	goto done3;
    default:
	;
    }
    AFS_DISCON_LOCK();

    code = afs_EvalFakeStat(&adp, &fakestate, &treq);
    if (code)
	goto done;
  tagain:
    code = afs_VerifyVCache(adp, &treq);
    if (code)
	goto done;

    /** If the volume is read-only, return error without making an RPC to the
      * fileserver
      */
    if (adp->f.states & CRO) {
	code = EROFS;
	goto done;
    }

    if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
        code = ENETDOWN;
        goto done;
    }

    tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
    ObtainWriteLock(&adp->lock, 135);
    if (tdc)
	ObtainSharedLock(&tdc->lock, 630);

    /*
     * Make sure that the data in the cache is current. We may have
     * received a callback while we were waiting for the write lock.
     */
    if (!(adp->f.states & CStatd)
	|| (tdc && !hsame(adp->f.m.DataVersion, tdc->f.versionNo))) {
	ReleaseWriteLock(&adp->lock);
	if (tdc) {
	    ReleaseSharedLock(&tdc->lock);
	    afs_PutDCache(tdc);
	}
	goto tagain;
    }
    if (tdc) {
	/* see if file already exists.  If it does, we only set 
	 * the size attributes (to handle O_TRUNC) */
	code = afs_dir_Lookup(tdc, aname, &newFid.Fid);	/* use dnlc first xxx */
	if (code == 0) {
	    ReleaseSharedLock(&tdc->lock);
	    afs_PutDCache(tdc);
	    ReleaseWriteLock(&adp->lock);
#ifdef AFS_SGI64_ENV
	    if (flags & VEXCL) {
#else
	    if (aexcl != NONEXCL) {
#endif
		code = EEXIST;	/* file exists in excl mode open */
		goto done;
	    }
	    /* found the file, so use it */
	    newFid.Cell = adp->f.fid.Cell;
	    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
	    tvc = NULL;
	    if (newFid.Fid.Unique == 0) {
		tvc = afs_LookupVCache(&newFid, &treq, NULL, adp, aname);
	    }
	    if (!tvc)		/* lookup failed or wasn't called */
		tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);

	    if (tvc) {
		/* if the thing exists, we need the right access to open it.
		 * we must check that here, since no other checks are
		 * made by the open system call */
		len = attrs->va_size;	/* only do the truncate */
		/*
		 * We used to check always for READ access before; the
		 * problem is that we will fail if the existing file
		 * has mode -w-w-w, which is wrong.
		 */
		if ((amode & VREAD)
		    && !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
		    afs_PutVCache(tvc);
		    code = EACCES;
		    goto done;
		}
#if defined(AFS_DARWIN80_ENV)
		if ((amode & VWRITE) || VATTR_IS_ACTIVE(attrs, va_data_size))
#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
		if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
#else
		if ((amode & VWRITE) || len != 0xffffffff)
#endif
		{
		    /* needed for write access check */
		    tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
		    tvc->f.parent.unique = adp->f.fid.Fid.Unique;
		    /* need write mode for these guys */
		    if (!afs_AccessOK
			(tvc, PRSFS_WRITE, &treq, CHECK_MODE_BITS)) {
			afs_PutVCache(tvc);
			code = EACCES;
			goto done;
		    }
		}
#if defined(AFS_DARWIN80_ENV)
		if (VATTR_IS_ACTIVE(attrs, va_data_size))
#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
		if (attrs->va_mask & AT_SIZE)
#else
		if (len != 0xffffffff)
#endif
		{
		    if (vType(tvc) != VREG) {
			afs_PutVCache(tvc);
			code = EISDIR;
			goto done;
		    }
		    /* do a truncate */
#if defined(AFS_DARWIN80_ENV)
		    VATTR_INIT(attrs);
		    VATTR_SET_SUPPORTED(attrs, va_data_size);
		    VATTR_SET_ACTIVE(attrs, va_data_size);
#elif defined(UKERNEL)
		    attrs->va_mask = ATTR_SIZE;
#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
		    attrs->va_mask = AT_SIZE;
#else
		    VATTR_NULL(attrs);
#endif
		    attrs->va_size = len;
		    ObtainWriteLock(&tvc->lock, 136);
		    tvc->f.states |= CCreating;
		    ReleaseWriteLock(&tvc->lock);
#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
#if defined(AFS_SGI64_ENV)
		    code =
			afs_setattr(VNODE_TO_FIRST_BHV((vnode_t *) tvc),
				    attrs, 0, acred);
#else
		    code = afs_setattr(tvc, attrs, 0, acred);
#endif /* AFS_SGI64_ENV */
#else /* SUN5 || SGI */
		    code = afs_setattr(tvc, attrs, acred);
#endif /* SUN5 || SGI */
		    ObtainWriteLock(&tvc->lock, 137);
		    tvc->f.states &= ~CCreating;
		    ReleaseWriteLock(&tvc->lock);
		    if (code) {
			afs_PutVCache(tvc);
			goto done;
		    }
		}
		*avcp = tvc;
	    } else
		code = ENOENT;	/* shouldn't get here */
	    /* make sure vrefCount bumped only if code == 0 */
	    goto done;
	}
    }
    
    /* if we create the file, we don't do any access checks, since
     * that's how O_CREAT is supposed to work */
    if (adp->f.states & CForeign) {
	origCBs = afs_allCBs;
	origZaps = afs_allZaps;
    } else {
	origCBs = afs_evenCBs;	/* if changes, we don't really have a callback */
	origZaps = afs_evenZaps;	/* number of even numbered vnodes discarded */
    }
    InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
    InStatus.ClientModTime = osi_Time();
    InStatus.Group = (afs_int32) afs_cr_gid(acred);
    if (AFS_NFSXLATORREQ(acred)) {
	/*
	 * XXX The following is mainly used to fix a bug in the HP-UX
	 * nfs client where they create files with mode of 0 without
	 * doing any setattr later on to fix it.  * XXX
	 */
#if	defined(AFS_AIX_ENV)
	if (attrs->va_mode != -1) {
#else
#if	defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
	if (attrs->va_mask & AT_MODE) {
#else
	if (attrs->va_mode != ((unsigned short)-1)) {
#endif
#endif
	    if (!attrs->va_mode)
		attrs->va_mode = 0x1b6;	/* XXX default mode: rw-rw-rw XXX */
	}
    }

    if (!AFS_IS_DISCONNECTED) {
	/* If not disconnected, connect to the server.*/

    	InStatus.UnixModeBits = attrs->va_mode & 0xffff;	/* only care about protection bits */
    	do {
	  tc = afs_Conn(&adp->f.fid, &treq, SHARED_LOCK, &rxconn);
	    if (tc) {
	    	hostp = tc->srvr->server;	/* remember for callback processing */
	    	now = osi_Time();
	    	XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
	    	RX_AFS_GUNLOCK();
	    	code =
		    RXAFS_CreateFile(rxconn, (struct AFSFid *)&adp->f.fid.Fid,
				 aname, &InStatus, (struct AFSFid *)
				 &newFid.Fid, &OutFidStatus, &OutDirStatus,
				 &CallBack, &tsync);
	    	RX_AFS_GLOCK();
	    	XSTATS_END_TIME;
	    	CallBack.ExpirationTime += now;
	    } else
	    	code = -1;
    	} while (afs_Analyze
	         (tc, rxconn, code, &adp->f.fid, &treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
	          SHARED_LOCK, NULL));

	if ((code == EEXIST || code == UAEEXIST) &&
#ifdef AFS_SGI64_ENV
    	!(flags & VEXCL)
#else /* AFS_SGI64_ENV */
    	aexcl == NONEXCL
#endif
    	) {
	    /* if we get an EEXIST in nonexcl mode, just do a lookup */
	    if (tdc) {
	    	ReleaseSharedLock(&tdc->lock);
	    	afs_PutDCache(tdc);
	    }
	    ReleaseWriteLock(&adp->lock);


#if defined(AFS_SGI64_ENV)
	    code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp,
				  NULL, 0, NULL, acred);
#elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
	    code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
#elif defined(UKERNEL)
	    code = afs_lookup(adp, aname, avcp, acred, 0);
#elif !defined(AFS_DARWIN_ENV)
	    code = afs_lookup(adp, aname, avcp, acred);
#endif
	goto done;
        }

	if (code) {
	    if (code < 0) {
	    	ObtainWriteLock(&afs_xcbhash, 488);
	    	afs_DequeueCallback(adp);
	    	adp->f.states &= ~CStatd;
	    	ReleaseWriteLock(&afs_xcbhash);
	    	osi_dnlc_purgedp(adp);
	    }
	    ReleaseWriteLock(&adp->lock);
	    if (tdc) {
	    	ReleaseSharedLock(&tdc->lock);
	    	afs_PutDCache(tdc);
	    }
	goto done;
	}

    } else {
	/* Generate a fake FID for disconnected mode. */
	newFid.Cell = adp->f.fid.Cell;
	newFid.Fid.Volume = adp->f.fid.Fid.Volume;
	afs_GenFakeFid(&newFid, VREG, 1);
    }				/* if (!AFS_IS_DISCON_RW) */

    /* otherwise, we should see if we can make the change to the dir locally */
    if (tdc)
	UpgradeSToWLock(&tdc->lock, 631);
    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
	/* we can do it locally */
	ObtainWriteLock(&afs_xdcache, 291);
	code = afs_dir_Create(tdc, aname, &newFid.Fid);
	ReleaseWriteLock(&afs_xdcache);
	if (code) {
	    ZapDCE(tdc);
	    DZap(tdc);
	}
    }
    if (tdc) {
	ReleaseWriteLock(&tdc->lock);
	afs_PutDCache(tdc);
    }
    if (AFS_IS_DISCON_RW)
	adp->f.m.LinkCount++;

    newFid.Cell = adp->f.fid.Cell;
    newFid.Fid.Volume = adp->f.fid.Fid.Volume;
    ReleaseWriteLock(&adp->lock);
    volp = afs_FindVolume(&newFid, READ_LOCK);

    /* New tricky optimistic callback handling algorithm for file creation works
     * as follows.  We create the file essentially with no locks set at all.  File
     * server may thus handle operations from others cache managers as well as from
     * this very own cache manager that reference the file in question before
     * we managed to create the cache entry.  However, if anyone else changes
     * any of the status information for a file, we'll see afs_evenCBs increase
     * (files always have even fids).  If someone on this workstation manages
     * to do something to the file, they'll end up having to create a cache
     * entry for the new file.  Either we'll find it once we've got the afs_xvcache
     * lock set, or it was also *deleted* the vnode before we got there, in which case
     * we will find evenZaps has changed, too.  Thus, we only assume we have the right
     * status information if no callbacks or vnode removals have occurred to even
     * numbered files from the time the call started until the time that we got the xvcache
     * lock set.  Of course, this also assumes that any call that modifies a file first
     * gets a write lock on the file's vnode, but if that weren't true, the whole cache manager
     * would fail, since no call would be able to update the local vnode status after modifying
     * a file on a file server. */
    ObtainWriteLock(&afs_xvcache, 138);
    if (adp->f.states & CForeign)
	finalZaps = afs_allZaps;	/* do this before calling newvcache */
    else
	finalZaps = afs_evenZaps;	/* do this before calling newvcache */
    /* don't need to call RemoveVCB, since only path leaving a callback is the
     * one where we pass through afs_NewVCache.  Can't have queued a VCB unless
     * we created and freed an entry between file creation time and here, and the
     * freeing of the vnode will change evenZaps.  Don't need to update the VLRU
     * queue, since the find will only succeed in the event of a create race, and 
     * then the vcache will be at the front of the VLRU queue anyway...  */
    if (!(tvc = afs_FindVCache(&newFid, 0, DO_STATS))) {
	tvc = afs_NewVCache(&newFid, hostp);
	if (tvc) {
	    int finalCBs;
	    ObtainWriteLock(&tvc->lock, 139);

	    ObtainWriteLock(&afs_xcbhash, 489);
	    finalCBs = afs_evenCBs;
	    /* add the callback in */
	    if (adp->f.states & CForeign) {
		tvc->f.states |= CForeign;
		finalCBs = afs_allCBs;
	    }
	    if (origCBs == finalCBs && origZaps == finalZaps) {
		tvc->f.states |= CStatd;	/* we've fake entire thing, so don't stat */
		tvc->f.states &= ~CBulkFetching;
		if (!AFS_IS_DISCON_RW) {
		    tvc->cbExpires = CallBack.ExpirationTime;
		    afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
		}
	    } else {
		afs_DequeueCallback(tvc);
		tvc->f.states &= ~(CStatd | CUnique);
		tvc->callback = 0;
		if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
		    osi_dnlc_purgedp(tvc);
	    }
	    ReleaseWriteLock(&afs_xcbhash);
	    if (AFS_IS_DISCON_RW) {
		afs_DisconAddDirty(tvc, VDisconCreate, 0);
		afs_GenDisconStatus(adp, tvc, &newFid, attrs, &treq, VREG);
	    } else {
		afs_ProcessFS(tvc, &OutFidStatus, &treq);
	    }

	    tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
	    tvc->f.parent.unique = adp->f.fid.Fid.Unique;
#if !defined(UKERNEL)
            if (volp && (volp->states & VPartVisible))
                tvc->f.states |= CPartVisible;
#endif
	    ReleaseWriteLock(&tvc->lock);
	    *avcp = tvc;
	    code = 0;
	} else
	    code = ENOENT;
    } else {
	/* otherwise cache entry already exists, someone else must
	 * have created it.  Comments used to say:  "don't need write
	 * lock to *clear* these flags" but we should do it anyway.
	 * Code used to clear stat bit and callback, but I don't see 
	 * the point -- we didn't have a create race, somebody else just
	 * snuck into NewVCache before we got here, probably a racing 
	 * lookup.
	 */
	*avcp = tvc;
	code = 0;
    }
    ReleaseWriteLock(&afs_xvcache);

  done:
    AFS_DISCON_UNLOCK();

  done3:
    if (volp)
	afs_PutVolume(volp, READ_LOCK);

    if (code == 0) {
	if (afs_mariner)
	    afs_AddMarinerName(aname, *avcp);
	/* return the new status in vattr */
	afs_CopyOutAttrs(*avcp, attrs);
	if (afs_mariner)
	    afs_MarinerLog("store$Creating", *avcp);
    }

    afs_PutFakeStat(&fakestate);
    code = afs_CheckCode(code, &treq, 20);

  done2:
    return code;
}


/*
 * Check to see if we can track the change locally: requires that
 * we have sufficiently recent info in data cache.  If so, we
 * know the new DataVersion number, and place it correctly in both the
 * data and stat cache entries.  This routine returns 1 if we should
 * do the operation locally, and 0 otherwise.
 *
 * This routine must be called with the stat cache entry write-locked,
 * and dcache entry write-locked.
 */
int
afs_LocalHero(struct vcache *avc, struct dcache *adc,
	      AFSFetchStatus * astat, int aincr)
{
    afs_int32 ok;
    afs_hyper_t avers;

    AFS_STATCNT(afs_LocalHero);
    hset64(avers, astat->dataVersionHigh, astat->DataVersion);
    /* avers *is* the version number now, no matter what */

    if (adc) {
	/* does what's in the dcache *now* match what's in the vcache *now*,
	 * and do we have a valid callback? if not, our local copy is not "ok" */
	ok = (hsame(avc->f.m.DataVersion, adc->f.versionNo) && avc->callback
	      && (avc->f.states & CStatd) && avc->cbExpires >= osi_Time());
    } else {
	ok = 0;
    }
    if (ok) {
	/* check that the DV on the server is what we expect it to be */
	afs_hyper_t newDV;
	hset(newDV, adc->f.versionNo);
	hadd32(newDV, aincr);
	if (!hsame(avers, newDV)) {
	    ok = 0;
	}
    }
#if defined(AFS_SGI_ENV)
    osi_Assert(avc->v.v_type == VDIR);
#endif
    /* The bulk status code used the length as a sequence number.  */
    /* Don't update the vcache entry unless the stats are current. */
    if (avc->f.states & CStatd) {
	hset(avc->f.m.DataVersion, avers);
#ifdef AFS_64BIT_CLIENT
	FillInt64(avc->f.m.Length, astat->Length_hi, astat->Length);
#else /* AFS_64BIT_CLIENT */
	avc->f.m.Length = astat->Length;
#endif /* AFS_64BIT_CLIENT */
	avc->f.m.Date = astat->ClientModTime;
    }
    if (ok) {
	/* we've been tracking things correctly */
	adc->dflags |= DFEntryMod;
	adc->f.versionNo = avers;
	return 1;
    } else {
	if (adc) {
	    ZapDCE(adc);
	    DZap(adc);
	}
	if (avc->f.states & CStatd) {
	    osi_dnlc_purgedp(avc);
	}
	return 0;
    }
}
示例#6
0
int
afsremove(struct vcache *adp, struct dcache *tdc,
	  struct vcache *tvc, char *aname, afs_ucred_t *acred,
	  struct vrequest *treqp)
{
    afs_int32 code = 0;
    struct afs_conn *tc;
    struct AFSFetchStatus OutDirStatus;
    struct AFSVolSync tsync;
    struct rx_connection *rxconn;
    XSTATS_DECLS;
    if (!AFS_IS_DISCONNECTED) {
        do {
	    tc = afs_Conn(&adp->f.fid, treqp, SHARED_LOCK, &rxconn);
	    if (tc) {
	        XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
	        RX_AFS_GUNLOCK();
	        code =
		    RXAFS_RemoveFile(rxconn, (struct AFSFid *)&adp->f.fid.Fid,
		  		     aname, &OutDirStatus, &tsync);
	        RX_AFS_GLOCK();
	        XSTATS_END_TIME;
	    } else
	        code = -1;
        } while (afs_Analyze
	         (tc, rxconn, code, &adp->f.fid, treqp, AFS_STATS_FS_RPCIDX_REMOVEFILE,
	          SHARED_LOCK, NULL));
    }

    osi_dnlc_remove(adp, aname, tvc);

    if (code) {
	if (tdc) {
	    ReleaseSharedLock(&tdc->lock);
	    afs_PutDCache(tdc);
	}

	if (tvc)
	    afs_PutVCache(tvc);

	if (code < 0) {
	    ObtainWriteLock(&afs_xcbhash, 497);
	    afs_DequeueCallback(adp);
	    adp->f.states &= ~CStatd;
	    ReleaseWriteLock(&afs_xcbhash);
	    osi_dnlc_purgedp(adp);
	}
	ReleaseWriteLock(&adp->lock);
	code = afs_CheckCode(code, treqp, 21);
	return code;
    }
    if (tdc)
	UpgradeSToWLock(&tdc->lock, 637);
    if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
	/* we can do it locally */
	code = afs_dir_Delete(tdc, aname);
	if (code) {
	    ZapDCE(tdc);	/* surprise error -- invalid value */
	    DZap(tdc);
	}
    }
    if (tdc) {
	ReleaseWriteLock(&tdc->lock);
	afs_PutDCache(tdc);	/* drop ref count */
    }
    ReleaseWriteLock(&adp->lock);

    /* now, get vnode for unlinked dude, and see if we should force it
     * from cache.  adp is now the deleted files vnode.  Note that we
     * call FindVCache instead of GetVCache since if the file's really
     * gone, we won't be able to fetch the status info anyway.  */
    if (tvc) {
	if (afs_mariner)
	    afs_MarinerLog("store$Removing", tvc);
#ifdef AFS_BOZONLOCK_ENV
	afs_BozonLock(&tvc->pvnLock, tvc);
	/* Since afs_TryToSmush will do a pvn_vptrunc */
#endif
	ObtainWriteLock(&tvc->lock, 141);
	/* note that callback will be broken on the deleted file if there are
	 * still >0 links left to it, so we'll get the stat right */
	tvc->f.m.LinkCount--;
	tvc->f.states &= ~CUnique;	/* For the dfs xlator */
	if (tvc->f.m.LinkCount == 0 && !osi_Active(tvc)) {
	    if (!AFS_NFSXLATORREQ(acred))
		afs_TryToSmush(tvc, acred, 0);
	}
	ReleaseWriteLock(&tvc->lock);
#ifdef AFS_BOZONLOCK_ENV
	afs_BozonUnlock(&tvc->pvnLock, tvc);
#endif
	afs_PutVCache(tvc);
    }
    return (0);
}