831196a8ce5ecccba615e14fa1f3d27df6a54a73
[openafs.git] / src / afs / VNOPS / afs_vnop_remove.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * Implements:
12  * afs_Wire (DUX)
13  * FetchWholeEnchilada
14  * afs_IsWired (DUX)
15  * afsremove
16  * afs_remove
17  *
18  * Local:
19  * newname
20  *
21  */
22 #include <afsconfig.h>
23 #include "../afs/param.h"
24
25 RCSID("$Header$");
26
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"
33
34
35 extern afs_rwlock_t afs_xvcache;
36 extern afs_rwlock_t afs_xcbhash;
37
38
39 #ifdef  AFS_OSF_ENV
40 /*
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.
46  */
47 afs_Wire(avc, areq)
48 #else   /* AFS_OSF_ENV */
49 static void FetchWholeEnchilada(avc, areq)
50 #endif
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;
56
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 */
65 #endif
66         tdc = afs_GetDCache(avc, pos, areq, &offset, &len, 0);
67         if (!tdc) 
68 #if     defined(AFS_OSF_ENV)
69             break;
70 #else   /* AFS_OSF_ENV */
71             return;
72 #endif
73         afs_PutDCache(tdc);
74     }
75 #if defined(AFS_OSF_ENV)
76     avc->states |= CWired;
77 #endif  /* AFS_OSF_ENV */
78 }
79
80 #if     defined(AFS_OSF_ENV)
81 /*
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).
84  */
85 afs_IsWired(avc)
86     register struct vcache *avc; {
87     if (avc->states & CWired) {
88         if (osi_Active(avc)) {
89             return 1;
90         }
91         avc->states &= ~CWired;
92     }
93     return 0;
94 }
95 #endif  /* AFS_OSF_ENV */
96
97 afsremove(adp, tdc, tvc, aname, acred, treqp)
98     register struct vcache *adp;
99     register struct dcache *tdc;
100     register struct vcache *tvc;
101     char *aname;
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;
108     XSTATS_DECLS
109
110     do {
111         tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
112         if (tc) {
113           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
114 #ifdef RX_ENABLE_LOCKS
115             AFS_GUNLOCK();
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
120             AFS_GLOCK();
121 #endif /* RX_ENABLE_LOCKS */
122           XSTATS_END_TIME;
123       }
124         else code = -1;
125     } while
126       (afs_Analyze(tc, code, &adp->fid, treqp,
127                    AFS_STATS_FS_RPCIDX_REMOVEFILE, SHARED_LOCK, (struct cell *)0));
128
129     osi_dnlc_remove (adp, aname, tvc);
130     if (tvc) afs_symhint_inval(tvc);   /* XXX: don't really need to be so extreme */
131
132     if (code) {
133         if (tdc) {
134             ReleaseSharedLock(&tdc->lock);
135             afs_PutDCache(tdc);
136         }
137         if (tvc) afs_PutVCache(tvc, WRITE_LOCK);
138
139         if (code < 0) {
140           ObtainWriteLock(&afs_xcbhash, 497);
141           afs_DequeueCallback(adp);
142           adp->states &= ~CStatd;
143           ReleaseWriteLock(&afs_xcbhash);
144           osi_dnlc_purgedp(adp);
145         }
146         ReleaseWriteLock(&adp->lock);
147         code = afs_CheckCode(code, treqp, 21);
148         return code;
149     }
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);
154         if (code) {
155             ZapDCE(tdc);        /* surprise error -- invalid value */
156             DZap(&tdc->f.inode);
157         }
158     }
159     if (tdc) {
160         ReleaseWriteLock(&tdc->lock);
161         afs_PutDCache(tdc);     /* drop ref count */
162     }
163     ReleaseWriteLock(&adp->lock);
164
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.  */
169     if (tvc) {
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 */
173 #endif
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 */
177         tvc->m.LinkCount--;
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);
181         } 
182         ReleaseWriteLock(&tvc->lock);
183 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
184         afs_BozonUnlock(&tvc->pvnLock, tvc);
185 #endif
186         afs_PutVCache(tvc, WRITE_LOCK);
187     }
188     return (0);
189 }
190
191 static char *newname() {
192     char *name, *sp, *p = ".__afs";
193     afs_int32 rd = afs_random() & 0xffff;
194
195     sp = name = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
196     while (*p != '\0') *sp++ = *p++;
197     while (rd) {
198         *sp++= "0123456789ABCDEF"[rd & 0x0f];
199         rd >>= 4;
200     }
201     *sp = '\0';
202     return (name);
203 }
204
205 /* these variables appear to exist for debugging purposes */
206 struct vcache * Tadp1, * Ttvc;
207 int Tadpr, Ttvcr;
208 char *Tnam;
209 char *Tnam1;
210
211 /* Note that we don't set CDirty here, this is OK because the unlink
212  * RPC is called synchronously */
213 #ifdef  AFS_OSF_ENV
214 afs_remove(ndp)
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)
221     OSI_VC_DECL(adp);
222     char *aname;
223     struct AFS_UCRED *acred; {
224 #endif
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;
234     XSTATS_DECLS
235     OSI_VC_CONVERT(adp)
236
237     AFS_STATCNT(afs_remove);
238     afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
239                ICL_TYPE_STRING, aname);
240
241 #ifdef  AFS_OSF_ENV
242     tvc = (struct vcache *)ndp->ni_vp;  /* should never be null */
243 #endif
244
245     if (code = afs_InitReq(&treq, acred)) {
246 #ifdef  AFS_OSF_ENV
247         afs_PutVCache(adp, 0);
248         afs_PutVCache(tvc, 0);
249 #endif
250         return code;
251     }
252
253     afs_InitFakeStat(&fakestate);
254     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
255     if (code) {
256         afs_PutFakeStat(&fakestate);
257 #ifdef  AFS_OSF_ENV
258         afs_PutVCache(adp, 0);
259         afs_PutVCache(tvc, 0);
260 #endif
261         return code;
262     }
263
264     /* Check if this is dynroot */
265     if (afs_IsDynroot(adp)) {
266         code = afs_DynrootVOPRemove(adp, acred, aname);
267         afs_PutFakeStat(&fakestate);
268 #ifdef  AFS_OSF_ENV
269         afs_PutVCache(adp, 0);
270         afs_PutVCache(tvc, 0);
271 #endif
272         return code;
273     }
274     if (strlen(aname) > AFSNAMEMAX) {
275         afs_PutFakeStat(&fakestate);
276 #ifdef  AFS_OSF_ENV
277         afs_PutVCache(adp, 0);
278         afs_PutVCache(tvc, 0);
279 #endif
280         return ENAMETOOLONG;
281     }
282 tagain:
283     code = afs_VerifyVCache(adp, &treq);
284 #ifdef  AFS_OSF_ENV
285     tvc = VTOAFS(ndp->ni_vp);  /* should never be null */
286     if (code) {
287         afs_PutVCache(adp, 0);
288         afs_PutVCache(tvc, 0);
289         afs_PutFakeStat(&fakestate);
290         return afs_CheckCode(code, &treq, 22);
291     }
292 #else   /* AFS_OSF_ENV */
293     tvc = (struct vcache *) 0;
294     if (code) {
295         code = afs_CheckCode(code, &treq, 23);
296         afs_PutFakeStat(&fakestate);
297         return code;
298     }
299 #endif
300
301     /** If the volume is read-only, return error without making an RPC to the
302       * fileserver
303       */
304     if ( adp->states & CRO ) {
305 #ifdef  AFS_OSF_ENV
306         afs_PutVCache(adp, 0);
307         afs_PutVCache(tvc, 0);
308 #endif
309         code = EROFS;
310         afs_PutFakeStat(&fakestate);
311         return code;
312     }
313
314     tdc = afs_GetDCache(adp, (afs_size_t) 0,    &treq, &offset, &len, 1);  /* test for error below */
315     ObtainWriteLock(&adp->lock,142);
316     if (tdc) ObtainSharedLock(&tdc->lock, 638);
317
318     /*
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.
321      */
322     if (!(adp->states & CStatd)
323         || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
324         ReleaseWriteLock(&adp->lock);
325         if (tdc) {
326             ReleaseSharedLock(&tdc->lock);
327             afs_PutDCache(tdc);
328         }
329         goto tagain;
330     }
331
332     unlinkFid.Fid.Vnode = 0;
333     if (!tvc) {
334       tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
335     }
336     /* This should not be necessary since afs_lookup() has already
337      * done the work */
338     if (!tvc)
339       if (tdc) {
340         code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
341         if (code == 0) {        
342             afs_int32 cached=0;
343
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);
349             } else {
350                 ObtainReadLock(&afs_xvcache);
351                 tvc = afs_FindVCache(&unlinkFid, 1, WRITE_LOCK, 
352                                      0 , DO_STATS );
353                 ReleaseReadLock(&afs_xvcache);
354             }
355         }
356     }
357
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);
366 #endif
367         ReleaseWriteLock(&tvc->lock);
368         ObtainWriteLock(&adp->lock,144);
369     }
370
371     osi_dnlc_remove ( adp, aname, tvc);
372     if (tvc) afs_symhint_inval(tvc);
373
374     Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
375     if (tvc) Ttvcr = VREFCOUNT(tvc);
376 #ifdef  AFS_AIX_ENV
377     if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
378 #else
379     if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
380 #endif
381         char *unlname = newname();
382
383         ReleaseWriteLock(&adp->lock);
384         if (tdc) ReleaseSharedLock(&tdc->lock);
385         code = afsrename(adp, aname, adp, unlname, acred, &treq);
386         Tnam1 = unlname;
387         if (!code) {
388             tvc->mvid = (struct VenusFid *)unlname;
389             crhold(acred);
390             if (tvc->uncred) {
391                 crfree(tvc->uncred);
392             }
393             tvc->uncred = acred;
394             tvc->states |= CUnlinked;
395         } else {
396             osi_FreeSmallSpace(unlname);            
397         }
398         if ( tdc )
399                 afs_PutDCache(tdc);
400         afs_PutVCache(tvc, WRITE_LOCK); 
401     } else {
402         code = afsremove(adp, tdc, tvc, aname, acred, &treq);
403     }
404 #ifdef  AFS_OSF_ENV
405     afs_PutVCache(adp, WRITE_LOCK);
406 #endif  /* AFS_OSF_ENV */
407     afs_PutFakeStat(&fakestate);
408     return code;
409 }
410
411
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.
414  *
415  * CAUTION -- may be called with avc unheld. */
416
417 afs_remunlink(avc, doit)
418     register struct vcache *avc;
419     register int doit;
420 {
421     struct AFS_UCRED *cred;
422     char *unlname;
423     struct vcache *adp;
424     struct vrequest treq;
425     struct VenusFid dirFid;
426     register struct dcache *tdc;
427     afs_int32 code=0;
428
429     if (NBObtainWriteLock(&avc->lock, 423))
430         return 0;
431
432     if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
433         if (code = afs_InitReq(&treq, avc->uncred)) {
434             ReleaseWriteLock(&avc->lock);
435         }
436         else {
437             /* Must bump the refCount because GetVCache may block.
438              * Also clear mvid so no other thread comes here if we block.
439              */
440             unlname = (char *)avc->mvid;
441             avc->mvid = NULL;
442             cred = avc->uncred;
443             avc->uncred = NULL;
444
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);
455 #endif
456             VN_HOLD(&avc->v);
457
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.
460              */
461             avc->states  &= ~(CUnlinked | CUnlinkedDel);
462
463             ReleaseWriteLock(&avc->lock);
464
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);
471             
472             if (adp) {
473                 tdc = afs_FindDCache(adp, 0);
474                 ObtainWriteLock(&adp->lock, 159);
475                 if (tdc) ObtainSharedLock(&tdc->lock, 639);
476
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);
480             } else {
481                 /* we failed - and won't be back to try again. */
482                 afs_PutVCache(avc, WRITE_LOCK);
483             }
484             osi_FreeSmallSpace(unlname);
485             crfree(cred);
486 #ifdef AFS_DARWIN_ENV
487             osi_Assert(VREFCOUNT(avc) == 1);
488             VREFCOUNT_SET(avc, 0);
489 #endif
490         }
491     }
492     else {
493         ReleaseWriteLock(&avc->lock);
494     }
495
496     return code;
497 }