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 "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 */
210 struct nameidata *ndp; {
211 register struct vcache *adp = VTOAFS(ndp->ni_dvp);
212 char *aname = ndp->ni_dent.d_name;
213 struct ucred *acred = ndp->ni_cred;
214 #else /* AFS_OSF_ENV */
215 afs_remove(OSI_VC_ARG(adp), aname, acred)
218 struct AFS_UCRED *acred; {
220 struct vrequest treq;
221 register struct dcache *tdc;
222 struct VenusFid unlinkFid;
223 register afs_int32 code;
224 register struct vcache *tvc;
225 afs_size_t offset, len;
226 struct afs_fakestat_state fakestate;
229 AFS_STATCNT(afs_remove);
230 afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
231 ICL_TYPE_STRING, aname);
234 tvc = (struct vcache *)ndp->ni_vp; /* should never be null */
237 if ((code = afs_InitReq(&treq, acred))) {
245 afs_InitFakeStat(&fakestate);
246 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
248 afs_PutFakeStat(&fakestate);
256 /* Check if this is dynroot */
257 if (afs_IsDynroot(adp)) {
258 code = afs_DynrootVOPRemove(adp, acred, aname);
259 afs_PutFakeStat(&fakestate);
266 if (strlen(aname) > AFSNAMEMAX) {
267 afs_PutFakeStat(&fakestate);
275 code = afs_VerifyVCache(adp, &treq);
277 tvc = VTOAFS(ndp->ni_vp); /* should never be null */
281 afs_PutFakeStat(&fakestate);
282 return afs_CheckCode(code, &treq, 22);
284 #else /* AFS_OSF_ENV */
287 code = afs_CheckCode(code, &treq, 23);
288 afs_PutFakeStat(&fakestate);
293 /** If the volume is read-only, return error without making an RPC to the
296 if ( adp->states & CRO ) {
302 afs_PutFakeStat(&fakestate);
306 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
307 ObtainWriteLock(&adp->lock,142);
308 if (tdc) ObtainSharedLock(&tdc->lock, 638);
311 * Make sure that the data in the cache is current. We may have
312 * received a callback while we were waiting for the write lock.
314 if (!(adp->states & CStatd)
315 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
316 ReleaseWriteLock(&adp->lock);
318 ReleaseSharedLock(&tdc->lock);
324 unlinkFid.Fid.Vnode = 0;
326 tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
328 /* This should not be necessary since afs_lookup() has already
332 code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
336 unlinkFid.Cell = adp->fid.Cell;
337 unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
338 if (unlinkFid.Fid.Unique == 0) {
339 tvc = afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
341 ObtainReadLock(&afs_xvcache);
342 tvc = afs_FindVCache(&unlinkFid, 0, DO_STATS);
343 ReleaseReadLock(&afs_xvcache);
348 if (tvc && osi_Active(tvc)) {
349 /* about to delete whole file, prefetch it first */
350 ReleaseWriteLock(&adp->lock);
351 ObtainWriteLock(&tvc->lock,143);
352 #if defined(AFS_OSF_ENV)
353 afs_Wire(tvc, &treq);
354 #else /* AFS_OSF_ENV */
355 FetchWholeEnchilada(tvc, &treq);
357 ReleaseWriteLock(&tvc->lock);
358 ObtainWriteLock(&adp->lock,144);
361 osi_dnlc_remove ( adp, aname, tvc);
362 if (tvc) afs_symhint_inval(tvc);
364 Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
365 if (tvc) Ttvcr = VREFCOUNT(tvc);
367 if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
369 if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
371 char *unlname = newname();
373 ReleaseWriteLock(&adp->lock);
374 if (tdc) ReleaseSharedLock(&tdc->lock);
375 code = afsrename(adp, aname, adp, unlname, acred, &treq);
378 tvc->mvid = (struct VenusFid *)unlname;
384 tvc->states |= CUnlinked;
386 osi_FreeSmallSpace(unlname);
392 code = afsremove(adp, tdc, tvc, aname, acred, &treq);
396 #endif /* AFS_OSF_ENV */
397 afs_PutFakeStat(&fakestate);
402 /* afs_remunlink -- This tries to delete the file at the server after it has
403 * been renamed when unlinked locally but now has been finally released.
405 * CAUTION -- may be called with avc unheld. */
407 int afs_remunlink(register struct vcache *avc, register int doit)
409 struct AFS_UCRED *cred;
412 struct vrequest treq;
413 struct VenusFid dirFid;
414 register struct dcache *tdc;
417 if (NBObtainWriteLock(&avc->lock, 423))
420 if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
421 if ((code = afs_InitReq(&treq, avc->uncred))) {
422 ReleaseWriteLock(&avc->lock);
425 /* Must bump the refCount because GetVCache may block.
426 * Also clear mvid so no other thread comes here if we block.
428 unlname = (char *)avc->mvid;
433 #ifdef AFS_DARWIN_ENV
434 /* this is called by vrele (via VOP_INACTIVE) when the refcount
435 is 0. we can't just call VN_HOLD since vref will panic.
436 we can't just call osi_vnhold because a later AFS_RELE will call
437 vrele again, which will try to call VOP_INACTIVE again after
438 vn_locking the vnode. which would be fine except that our vrele
439 caller also locked the vnode... So instead, we just gimmick the
440 refcounts and hope nobody else can touch the file now */
441 osi_Assert(VREFCOUNT(avc) == 0);
442 VREFCOUNT_SET(avc, 1);
444 VN_HOLD(AFSTOV(avc));
446 /* We'll only try this once. If it fails, just release the vnode.
447 * Clear after doing hold so that NewVCache doesn't find us yet.
449 avc->states &= ~(CUnlinked | CUnlinkedDel);
451 ReleaseWriteLock(&avc->lock);
453 dirFid.Cell = avc->fid.Cell;
454 dirFid.Fid.Volume = avc->fid.Fid.Volume;
455 dirFid.Fid.Vnode = avc->parentVnode;
456 dirFid.Fid.Unique = avc->parentUnique;
457 adp = afs_GetVCache(&dirFid, &treq, NULL, NULL);
460 tdc = afs_FindDCache(adp, (afs_size_t)0);
461 ObtainWriteLock(&adp->lock, 159);
462 if (tdc) ObtainSharedLock(&tdc->lock, 639);
464 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
465 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
468 /* we failed - and won't be back to try again. */
471 osi_FreeSmallSpace(unlname);
473 #ifdef AFS_DARWIN_ENV
474 osi_Assert(VREFCOUNT(avc) == 1);
475 VREFCOUNT_SET(avc, 0);
480 ReleaseWriteLock(&avc->lock);