2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
22 #include <afsconfig.h>
23 #include "../afs/param.h"
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/afs_osidnlc.h"
35 extern afs_rwlock_t afs_xvcache;
36 extern afs_rwlock_t afs_xcbhash;
41 * Wire down file in cache: prefetch all data, and turn on CWired flag
42 * so that callbacks/callback expirations are (temporarily) ignored
43 * and cache file(s) are kept in cache. File will be unwired when
44 * afs_inactive is called (ie no one has VN_HOLD on vnode), or when
45 * afs_IsWired notices that the file is no longer Active.
48 #else /* AFS_OSF_ENV */
49 static void FetchWholeEnchilada(avc, areq)
51 struct vrequest *areq;
52 register struct vcache *avc; {
53 register afs_int32 nextChunk;
54 register struct dcache *tdc;
55 afs_size_t pos, offset, len;
57 AFS_STATCNT(FetchWholeEnchilada);
58 if ((avc->states & CStatd) == 0) return; /* don't know size */
59 for(nextChunk=0;nextChunk<1024;nextChunk++) { /* sanity check on N chunks */
60 pos = AFS_CHUNKTOBASE(nextChunk);
61 #if defined(AFS_OSF_ENV)
62 if (pos >= avc->m.Length) break; /* all done */
63 #else /* AFS_OSF_ENV */
64 if (pos >= avc->m.Length) return; /* all done */
66 tdc = afs_GetDCache(avc, pos, areq, &offset, &len, 0);
68 #if defined(AFS_OSF_ENV)
70 #else /* AFS_OSF_ENV */
75 #if defined(AFS_OSF_ENV)
76 avc->states |= CWired;
77 #endif /* AFS_OSF_ENV */
80 #if defined(AFS_OSF_ENV)
82 * Tests whether file is wired down, after unwiring the file if it
83 * is found to be inactive (ie not open and not being paged from).
86 register struct vcache *avc; {
87 if (avc->states & CWired) {
88 if (osi_Active(avc)) {
91 avc->states &= ~CWired;
95 #endif /* AFS_OSF_ENV */
97 int afsremove(register struct vcache *adp, register struct dcache *tdc,
98 register struct vcache *tvc, char *aname, struct AFS_UCRED *acred,
99 struct vrequest *treqp)
101 register afs_int32 code;
102 register struct conn *tc;
103 struct AFSFetchStatus OutDirStatus;
104 struct AFSVolSync tsync;
108 tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
110 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
112 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &adp->fid.Fid,
113 aname, &OutDirStatus, &tsync);
119 (afs_Analyze(tc, code, &adp->fid, treqp,
120 AFS_STATS_FS_RPCIDX_REMOVEFILE, SHARED_LOCK, NULL));
122 osi_dnlc_remove (adp, aname, tvc);
123 if (tvc) afs_symhint_inval(tvc); /* XXX: don't really need to be so extreme */
127 ReleaseSharedLock(&tdc->lock);
130 if (tvc) afs_PutVCache(tvc);
133 ObtainWriteLock(&afs_xcbhash, 497);
134 afs_DequeueCallback(adp);
135 adp->states &= ~CStatd;
136 ReleaseWriteLock(&afs_xcbhash);
137 osi_dnlc_purgedp(adp);
139 ReleaseWriteLock(&adp->lock);
140 code = afs_CheckCode(code, treqp, 21);
143 if (tdc) UpgradeSToWLock(&tdc->lock, 637);
144 if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
145 /* we can do it locally */
146 code = afs_dir_Delete(&tdc->f.inode, aname);
148 ZapDCE(tdc); /* surprise error -- invalid value */
153 ReleaseWriteLock(&tdc->lock);
154 afs_PutDCache(tdc); /* drop ref count */
156 ReleaseWriteLock(&adp->lock);
158 /* now, get vnode for unlinked dude, and see if we should force it
159 * from cache. adp is now the deleted files vnode. Note that we
160 * call FindVCache instead of GetVCache since if the file's really
161 * gone, we won't be able to fetch the status info anyway. */
163 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
164 afs_BozonLock(&tvc->pvnLock, tvc);
165 /* Since afs_TryToSmush will do a pvn_vptrunc */
167 ObtainWriteLock(&tvc->lock,141);
168 /* note that callback will be broken on the deleted file if there are
169 * still >0 links left to it, so we'll get the stat right */
171 tvc->states &= ~CUnique; /* For the dfs xlator */
172 if (tvc->m.LinkCount == 0 && !osi_Active(tvc)) {
173 if (!AFS_NFSXLATORREQ(acred)) afs_TryToSmush(tvc, acred, 0);
175 ReleaseWriteLock(&tvc->lock);
176 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
177 afs_BozonUnlock(&tvc->pvnLock, tvc);
184 static char *newname(void)
186 char *name, *sp, *p = ".__afs";
187 afs_int32 rd = afs_random() & 0xffff;
189 sp = name = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
190 while (*p != '\0') *sp++ = *p++;
192 *sp++= "0123456789ABCDEF"[rd & 0x0f];
199 /* these variables appear to exist for debugging purposes */
200 struct vcache * Tadp1, * Ttvc;
205 /* Note that we don't set CDirty here, this is OK because the unlink
206 * RPC is called synchronously */
209 struct nameidata *ndp; {
210 register struct vcache *adp = VTOAFS(ndp->ni_dvp);
211 char *aname = ndp->ni_dent.d_name;
212 struct ucred *acred = ndp->ni_cred;
213 #else /* AFS_OSF_ENV */
214 afs_remove(OSI_VC_ARG(adp), aname, acred)
217 struct AFS_UCRED *acred; {
219 struct vrequest treq;
220 register struct dcache *tdc;
221 struct VenusFid unlinkFid;
222 register afs_int32 code;
223 register struct vcache *tvc;
224 afs_size_t offset, len;
225 struct AFSFetchStatus OutDirStatus;
226 struct AFSVolSync tsync;
227 struct afs_fakestat_state fakestate;
231 AFS_STATCNT(afs_remove);
232 afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
233 ICL_TYPE_STRING, aname);
236 tvc = (struct vcache *)ndp->ni_vp; /* should never be null */
239 if ((code = afs_InitReq(&treq, acred))) {
247 afs_InitFakeStat(&fakestate);
248 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
250 afs_PutFakeStat(&fakestate);
258 /* Check if this is dynroot */
259 if (afs_IsDynroot(adp)) {
260 code = afs_DynrootVOPRemove(adp, acred, aname);
261 afs_PutFakeStat(&fakestate);
268 if (strlen(aname) > AFSNAMEMAX) {
269 afs_PutFakeStat(&fakestate);
277 code = afs_VerifyVCache(adp, &treq);
279 tvc = VTOAFS(ndp->ni_vp); /* should never be null */
283 afs_PutFakeStat(&fakestate);
284 return afs_CheckCode(code, &treq, 22);
286 #else /* AFS_OSF_ENV */
289 code = afs_CheckCode(code, &treq, 23);
290 afs_PutFakeStat(&fakestate);
295 /** If the volume is read-only, return error without making an RPC to the
298 if ( adp->states & CRO ) {
304 afs_PutFakeStat(&fakestate);
308 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
309 ObtainWriteLock(&adp->lock,142);
310 if (tdc) ObtainSharedLock(&tdc->lock, 638);
313 * Make sure that the data in the cache is current. We may have
314 * received a callback while we were waiting for the write lock.
316 if (!(adp->states & CStatd)
317 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
318 ReleaseWriteLock(&adp->lock);
320 ReleaseSharedLock(&tdc->lock);
326 unlinkFid.Fid.Vnode = 0;
328 tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
330 /* This should not be necessary since afs_lookup() has already
334 code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
338 unlinkFid.Cell = adp->fid.Cell;
339 unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
340 if (unlinkFid.Fid.Unique == 0) {
341 tvc = afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
343 ObtainReadLock(&afs_xvcache);
344 tvc = afs_FindVCache(&unlinkFid, 0, DO_STATS);
345 ReleaseReadLock(&afs_xvcache);
350 if (tvc && osi_Active(tvc)) {
351 /* about to delete whole file, prefetch it first */
352 ReleaseWriteLock(&adp->lock);
353 ObtainWriteLock(&tvc->lock,143);
354 #if defined(AFS_OSF_ENV)
355 afs_Wire(tvc, &treq);
356 #else /* AFS_OSF_ENV */
357 FetchWholeEnchilada(tvc, &treq);
359 ReleaseWriteLock(&tvc->lock);
360 ObtainWriteLock(&adp->lock,144);
363 osi_dnlc_remove ( adp, aname, tvc);
364 if (tvc) afs_symhint_inval(tvc);
366 Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
367 if (tvc) Ttvcr = VREFCOUNT(tvc);
369 if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
371 if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
373 char *unlname = newname();
375 ReleaseWriteLock(&adp->lock);
376 if (tdc) ReleaseSharedLock(&tdc->lock);
377 code = afsrename(adp, aname, adp, unlname, acred, &treq);
380 tvc->mvid = (struct VenusFid *)unlname;
386 tvc->states |= CUnlinked;
388 osi_FreeSmallSpace(unlname);
394 code = afsremove(adp, tdc, tvc, aname, acred, &treq);
398 #endif /* AFS_OSF_ENV */
399 afs_PutFakeStat(&fakestate);
404 /* afs_remunlink -- This tries to delete the file at the server after it has
405 * been renamed when unlinked locally but now has been finally released.
407 * CAUTION -- may be called with avc unheld. */
409 int afs_remunlink(register struct vcache *avc, register int doit)
411 struct AFS_UCRED *cred;
414 struct vrequest treq;
415 struct VenusFid dirFid;
416 register struct dcache *tdc;
419 if (NBObtainWriteLock(&avc->lock, 423))
422 if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
423 if ((code = afs_InitReq(&treq, avc->uncred))) {
424 ReleaseWriteLock(&avc->lock);
427 /* Must bump the refCount because GetVCache may block.
428 * Also clear mvid so no other thread comes here if we block.
430 unlname = (char *)avc->mvid;
435 #ifdef AFS_DARWIN_ENV
436 /* this is called by vrele (via VOP_INACTIVE) when the refcount
437 is 0. we can't just call VN_HOLD since vref will panic.
438 we can't just call osi_vnhold because a later AFS_RELE will call
439 vrele again, which will try to call VOP_INACTIVE again after
440 vn_locking the vnode. which would be fine except that our vrele
441 caller also locked the vnode... So instead, we just gimmick the
442 refcounts and hope nobody else can touch the file now */
443 osi_Assert(VREFCOUNT(avc) == 0);
444 VREFCOUNT_SET(avc, 1);
448 /* We'll only try this once. If it fails, just release the vnode.
449 * Clear after doing hold so that NewVCache doesn't find us yet.
451 avc->states &= ~(CUnlinked | CUnlinkedDel);
453 ReleaseWriteLock(&avc->lock);
455 dirFid.Cell = avc->fid.Cell;
456 dirFid.Fid.Volume = avc->fid.Fid.Volume;
457 dirFid.Fid.Vnode = avc->parentVnode;
458 dirFid.Fid.Unique = avc->parentUnique;
459 adp = afs_GetVCache(&dirFid, &treq, NULL, NULL);
462 tdc = afs_FindDCache(adp, 0);
463 ObtainWriteLock(&adp->lock, 159);
464 if (tdc) ObtainSharedLock(&tdc->lock, 639);
466 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
467 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
470 /* we failed - and won't be back to try again. */
473 osi_FreeSmallSpace(unlname);
475 #ifdef AFS_DARWIN_ENV
476 osi_Assert(VREFCOUNT(avc) == 1);
477 VREFCOUNT_SET(avc, 0);
482 ReleaseWriteLock(&avc->lock);