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 afsremove(adp, tdc, tvc, aname, acred, treqp)
98 register struct vcache *adp;
99 register struct dcache *tdc;
100 register struct vcache *tvc;
102 struct vrequest *treqp;
103 struct AFS_UCRED *acred; {
104 register afs_int32 code;
105 register struct conn *tc;
106 struct AFSFetchStatus OutDirStatus;
107 struct AFSVolSync tsync;
111 tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
113 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
114 #ifdef RX_ENABLE_LOCKS
116 #endif /* RX_ENABLE_LOCKS */
117 code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &adp->fid.Fid,
118 aname, &OutDirStatus, &tsync);
119 #ifdef RX_ENABLE_LOCKS
121 #endif /* RX_ENABLE_LOCKS */
126 (afs_Analyze(tc, code, &adp->fid, treqp,
127 AFS_STATS_FS_RPCIDX_REMOVEFILE, SHARED_LOCK, (struct cell *)0));
129 osi_dnlc_remove (adp, aname, tvc);
130 if (tvc) afs_symhint_inval(tvc); /* XXX: don't really need to be so extreme */
134 ReleaseSharedLock(&tdc->lock);
137 if (tvc) afs_PutVCache(tvc, WRITE_LOCK);
140 ObtainWriteLock(&afs_xcbhash, 497);
141 afs_DequeueCallback(adp);
142 adp->states &= ~CStatd;
143 ReleaseWriteLock(&afs_xcbhash);
144 osi_dnlc_purgedp(adp);
146 ReleaseWriteLock(&adp->lock);
147 code = afs_CheckCode(code, treqp, 21);
150 if (tdc) UpgradeSToWLock(&tdc->lock, 637);
151 if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
152 /* we can do it locally */
153 code = afs_dir_Delete(&tdc->f.inode, aname);
155 ZapDCE(tdc); /* surprise error -- invalid value */
160 ReleaseWriteLock(&tdc->lock);
161 afs_PutDCache(tdc); /* drop ref count */
163 ReleaseWriteLock(&adp->lock);
165 /* now, get vnode for unlinked dude, and see if we should force it
166 * from cache. adp is now the deleted files vnode. Note that we
167 * call FindVCache instead of GetVCache since if the file's really
168 * gone, we won't be able to fetch the status info anyway. */
170 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
171 afs_BozonLock(&tvc->pvnLock, tvc);
172 /* Since afs_TryToSmush will do a pvn_vptrunc */
174 ObtainWriteLock(&tvc->lock,141);
175 /* note that callback will be broken on the deleted file if there are
176 * still >0 links left to it, so we'll get the stat right */
178 tvc->states &= ~CUnique; /* For the dfs xlator */
179 if (tvc->m.LinkCount == 0 && !osi_Active(tvc)) {
180 if (!AFS_NFSXLATORREQ(acred)) afs_TryToSmush(tvc, acred, 0);
182 ReleaseWriteLock(&tvc->lock);
183 #if defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
184 afs_BozonUnlock(&tvc->pvnLock, tvc);
186 afs_PutVCache(tvc, WRITE_LOCK);
191 static char *newname() {
192 char *name, *sp, *p = ".__afs";
193 afs_int32 rd = afs_random() & 0xffff;
195 sp = name = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
196 while (*p != '\0') *sp++ = *p++;
198 *sp++= "0123456789ABCDEF"[rd & 0x0f];
205 /* these variables appear to exist for debugging purposes */
206 struct vcache * Tadp1, * Ttvc;
211 /* Note that we don't set CDirty here, this is OK because the unlink
212 * RPC is called synchronously */
215 struct nameidata *ndp; {
216 register struct vcache *adp = VTOAFS(ndp->ni_dvp);
217 char *aname = ndp->ni_dent.d_name;
218 struct ucred *acred = ndp->ni_cred;
219 #else /* AFS_OSF_ENV */
220 afs_remove(OSI_VC_ARG(adp), aname, acred)
223 struct AFS_UCRED *acred; {
225 struct vrequest treq;
226 register struct dcache *tdc;
227 struct VenusFid unlinkFid;
228 register afs_int32 code;
229 register struct vcache *tvc;
230 afs_size_t offset, len;
231 struct AFSFetchStatus OutDirStatus;
232 struct AFSVolSync tsync;
233 struct afs_fakestat_state fakestate;
237 AFS_STATCNT(afs_remove);
238 afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
239 ICL_TYPE_STRING, aname);
242 tvc = (struct vcache *)ndp->ni_vp; /* should never be null */
245 if (code = afs_InitReq(&treq, acred)) {
247 afs_PutVCache(adp, 0);
248 afs_PutVCache(tvc, 0);
253 afs_InitFakeStat(&fakestate);
254 code = afs_EvalFakeStat(&adp, &fakestate, &treq);
256 afs_PutFakeStat(&fakestate);
258 afs_PutVCache(adp, 0);
259 afs_PutVCache(tvc, 0);
264 /* Check if this is dynroot */
265 if (afs_IsDynroot(adp)) {
266 code = afs_DynrootVOPRemove(adp, acred, aname);
267 afs_PutFakeStat(&fakestate);
269 afs_PutVCache(adp, 0);
270 afs_PutVCache(tvc, 0);
274 if (strlen(aname) > AFSNAMEMAX) {
275 afs_PutFakeStat(&fakestate);
277 afs_PutVCache(adp, 0);
278 afs_PutVCache(tvc, 0);
283 code = afs_VerifyVCache(adp, &treq);
285 tvc = VTOAFS(ndp->ni_vp); /* should never be null */
287 afs_PutVCache(adp, 0);
288 afs_PutVCache(tvc, 0);
289 afs_PutFakeStat(&fakestate);
290 return afs_CheckCode(code, &treq, 22);
292 #else /* AFS_OSF_ENV */
293 tvc = (struct vcache *) 0;
295 code = afs_CheckCode(code, &treq, 23);
296 afs_PutFakeStat(&fakestate);
301 /** If the volume is read-only, return error without making an RPC to the
304 if ( adp->states & CRO ) {
306 afs_PutVCache(adp, 0);
307 afs_PutVCache(tvc, 0);
310 afs_PutFakeStat(&fakestate);
314 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1); /* test for error below */
315 ObtainWriteLock(&adp->lock,142);
316 ObtainSharedLock(&tdc->lock, 638);
319 * Make sure that the data in the cache is current. We may have
320 * received a callback while we were waiting for the write lock.
322 if (!(adp->states & CStatd)
323 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
324 ReleaseWriteLock(&adp->lock);
326 ReleaseSharedLock(&tdc->lock);
332 unlinkFid.Fid.Vnode = 0;
334 tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
336 /* This should not be necessary since afs_lookup() has already
340 code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
344 unlinkFid.Cell = adp->fid.Cell;
345 unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
346 if (unlinkFid.Fid.Unique == 0) {
347 tvc = afs_LookupVCache(&unlinkFid, &treq, &cached,
348 WRITE_LOCK, adp, aname);
350 ObtainReadLock(&afs_xvcache);
351 tvc = afs_FindVCache(&unlinkFid, 1, WRITE_LOCK,
353 ReleaseReadLock(&afs_xvcache);
358 if (tvc && osi_Active(tvc)) {
359 /* about to delete whole file, prefetch it first */
360 ReleaseWriteLock(&adp->lock);
361 ObtainWriteLock(&tvc->lock,143);
362 #if defined(AFS_OSF_ENV)
363 afs_Wire(tvc, &treq);
364 #else /* AFS_OSF_ENV */
365 FetchWholeEnchilada(tvc, &treq);
367 ReleaseWriteLock(&tvc->lock);
368 ObtainWriteLock(&adp->lock,144);
371 osi_dnlc_remove ( adp, aname, tvc);
372 if (tvc) afs_symhint_inval(tvc);
374 Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
375 if (tvc) Ttvcr = VREFCOUNT(tvc);
377 if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
379 if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
381 char *unlname = newname();
383 ReleaseWriteLock(&adp->lock);
384 if (tdc) ReleaseSharedLock(&tdc->lock);
385 code = afsrename(adp, aname, adp, unlname, acred, &treq);
388 tvc->mvid = (struct VenusFid *)unlname;
394 tvc->states |= CUnlinked;
396 osi_FreeSmallSpace(unlname);
400 afs_PutVCache(tvc, WRITE_LOCK);
402 code = afsremove(adp, tdc, tvc, aname, acred, &treq);
405 afs_PutVCache(adp, WRITE_LOCK);
406 #endif /* AFS_OSF_ENV */
407 afs_PutFakeStat(&fakestate);
412 /* afs_remunlink -- This tries to delete the file at the server after it has
413 * been renamed when unlinked locally but now has been finally released.
415 * CAUTION -- may be called with avc unheld. */
417 afs_remunlink(avc, doit)
418 register struct vcache *avc;
421 struct AFS_UCRED *cred;
424 struct vrequest treq;
425 struct VenusFid dirFid;
426 register struct dcache *tdc;
429 if (NBObtainWriteLock(&avc->lock, 423))
432 if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
433 if (code = afs_InitReq(&treq, avc->uncred)) {
434 ReleaseWriteLock(&avc->lock);
437 /* Must bump the refCount because GetVCache may block.
438 * Also clear mvid so no other thread comes here if we block.
440 unlname = (char *)avc->mvid;
445 #ifdef AFS_DARWIN_ENV
446 /* this is called by vrele (via VOP_INACTIVE) when the refcount
447 is 0. we can't just call VN_HOLD since vref will panic.
448 we can't just call osi_vnhold because a later AFS_RELE will call
449 vrele again, which will try to call VOP_INACTIVE again after
450 vn_locking the vnode. which would be fine except that our vrele
451 caller also locked the vnode... So instead, we just gimmick the
452 refcounts and hope nobody else can touch the file now */
453 osi_Assert(VREFCOUNT(avc) == 0);
454 VREFCOUNT_SET(avc, 1);
458 /* We'll only try this once. If it fails, just release the vnode.
459 * Clear after doing hold so that NewVCache doesn't find us yet.
461 avc->states &= ~(CUnlinked | CUnlinkedDel);
463 ReleaseWriteLock(&avc->lock);
465 dirFid.Cell = avc->fid.Cell;
466 dirFid.Fid.Volume = avc->fid.Fid.Volume;
467 dirFid.Fid.Vnode = avc->parentVnode;
468 dirFid.Fid.Unique = avc->parentUnique;
469 adp = afs_GetVCache(&dirFid, &treq, (afs_int32 *)0,
470 (struct vcache *)0, WRITE_LOCK);
473 tdc = afs_FindDCache(adp, 0);
474 ObtainWriteLock(&adp->lock, 159);
475 if (tdc) ObtainSharedLock(&tdc->lock, 639);
477 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
478 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
479 afs_PutVCache(adp, WRITE_LOCK);
481 /* we failed - and won't be back to try again. */
482 afs_PutVCache(avc, WRITE_LOCK);
484 osi_FreeSmallSpace(unlname);
486 #ifdef AFS_DARWIN_ENV
487 osi_Assert(VREFCOUNT(avc) == 1);
488 VREFCOUNT_SET(avc, 0);
493 ReleaseWriteLock(&avc->lock);