openbsd-20021011
[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 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)
100 {
101     register afs_int32 code;
102     register struct conn *tc;
103     struct AFSFetchStatus OutDirStatus;
104     struct AFSVolSync tsync;
105     XSTATS_DECLS
106
107     do {
108         tc = afs_Conn(&adp->fid, treqp, SHARED_LOCK);
109         if (tc) {
110           XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEFILE);
111             RX_AFS_GUNLOCK();
112             code = RXAFS_RemoveFile(tc->id, (struct AFSFid *) &adp->fid.Fid,
113                                     aname, &OutDirStatus, &tsync);
114             RX_AFS_GLOCK();
115           XSTATS_END_TIME;
116       }
117         else code = -1;
118     } while
119       (afs_Analyze(tc, code, &adp->fid, treqp,
120                    AFS_STATS_FS_RPCIDX_REMOVEFILE, SHARED_LOCK, NULL));
121
122     osi_dnlc_remove (adp, aname, tvc);
123     if (tvc) afs_symhint_inval(tvc);   /* XXX: don't really need to be so extreme */
124
125     if (code) {
126         if (tdc) {
127             ReleaseSharedLock(&tdc->lock);
128             afs_PutDCache(tdc);
129         }
130         if (tvc) afs_PutVCache(tvc);
131
132         if (code < 0) {
133           ObtainWriteLock(&afs_xcbhash, 497);
134           afs_DequeueCallback(adp);
135           adp->states &= ~CStatd;
136           ReleaseWriteLock(&afs_xcbhash);
137           osi_dnlc_purgedp(adp);
138         }
139         ReleaseWriteLock(&adp->lock);
140         code = afs_CheckCode(code, treqp, 21);
141         return code;
142     }
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);
147         if (code) {
148             ZapDCE(tdc);        /* surprise error -- invalid value */
149             DZap(&tdc->f.inode);
150         }
151     }
152     if (tdc) {
153         ReleaseWriteLock(&tdc->lock);
154         afs_PutDCache(tdc);     /* drop ref count */
155     }
156     ReleaseWriteLock(&adp->lock);
157
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.  */
162     if (tvc) {
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 */
166 #endif
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 */
170         tvc->m.LinkCount--;
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);
174         } 
175         ReleaseWriteLock(&tvc->lock);
176 #if     defined(AFS_SUN_ENV) || defined(AFS_ALPHA_ENV) || defined(AFS_SUN5_ENV)
177         afs_BozonUnlock(&tvc->pvnLock, tvc);
178 #endif
179         afs_PutVCache(tvc);
180     }
181     return (0);
182 }
183
184 static char *newname(void)
185 {
186     char *name, *sp, *p = ".__afs";
187     afs_int32 rd = afs_random() & 0xffff;
188
189     sp = name = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
190     while (*p != '\0') *sp++ = *p++;
191     while (rd) {
192         *sp++= "0123456789ABCDEF"[rd & 0x0f];
193         rd >>= 4;
194     }
195     *sp = '\0';
196     return (name);
197 }
198
199 /* these variables appear to exist for debugging purposes */
200 struct vcache * Tadp1, * Ttvc;
201 int Tadpr, Ttvcr;
202 char *Tnam;
203 char *Tnam1;
204
205 /* Note that we don't set CDirty here, this is OK because the unlink
206  * RPC is called synchronously */
207 #ifdef  AFS_OSF_ENV
208 afs_remove(ndp)
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)
215     OSI_VC_DECL(adp);
216     char *aname;
217     struct AFS_UCRED *acred; {
218 #endif
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 afs_fakestat_state fakestate;
226     OSI_VC_CONVERT(adp)
227
228     AFS_STATCNT(afs_remove);
229     afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
230                ICL_TYPE_STRING, aname);
231
232 #ifdef  AFS_OSF_ENV
233     tvc = (struct vcache *)ndp->ni_vp;  /* should never be null */
234 #endif
235
236     if ((code = afs_InitReq(&treq, acred))) {
237 #ifdef  AFS_OSF_ENV
238         afs_PutVCache(adp);
239         afs_PutVCache(tvc);
240 #endif
241         return code;
242     }
243
244     afs_InitFakeStat(&fakestate);
245     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
246     if (code) {
247         afs_PutFakeStat(&fakestate);
248 #ifdef  AFS_OSF_ENV
249         afs_PutVCache(adp);
250         afs_PutVCache(tvc);
251 #endif
252         return code;
253     }
254
255     /* Check if this is dynroot */
256     if (afs_IsDynroot(adp)) {
257         code = afs_DynrootVOPRemove(adp, acred, aname);
258         afs_PutFakeStat(&fakestate);
259 #ifdef  AFS_OSF_ENV
260         afs_PutVCache(adp);
261         afs_PutVCache(tvc);
262 #endif
263         return code;
264     }
265     if (strlen(aname) > AFSNAMEMAX) {
266         afs_PutFakeStat(&fakestate);
267 #ifdef  AFS_OSF_ENV
268         afs_PutVCache(adp);
269         afs_PutVCache(tvc);
270 #endif
271         return ENAMETOOLONG;
272     }
273 tagain:
274     code = afs_VerifyVCache(adp, &treq);
275 #ifdef  AFS_OSF_ENV
276     tvc = VTOAFS(ndp->ni_vp);  /* should never be null */
277     if (code) {
278         afs_PutVCache(adp);
279         afs_PutVCache(tvc);
280         afs_PutFakeStat(&fakestate);
281         return afs_CheckCode(code, &treq, 22);
282     }
283 #else   /* AFS_OSF_ENV */
284     tvc = NULL;
285     if (code) {
286         code = afs_CheckCode(code, &treq, 23);
287         afs_PutFakeStat(&fakestate);
288         return code;
289     }
290 #endif
291
292     /** If the volume is read-only, return error without making an RPC to the
293       * fileserver
294       */
295     if ( adp->states & CRO ) {
296 #ifdef  AFS_OSF_ENV
297         afs_PutVCache(adp);
298         afs_PutVCache(tvc);
299 #endif
300         code = EROFS;
301         afs_PutFakeStat(&fakestate);
302         return code;
303     }
304
305     tdc = afs_GetDCache(adp, (afs_size_t) 0,    &treq, &offset, &len, 1);  /* test for error below */
306     ObtainWriteLock(&adp->lock,142);
307     if (tdc) ObtainSharedLock(&tdc->lock, 638);
308
309     /*
310      * Make sure that the data in the cache is current. We may have
311      * received a callback while we were waiting for the write lock.
312      */
313     if (!(adp->states & CStatd)
314         || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
315         ReleaseWriteLock(&adp->lock);
316         if (tdc) {
317             ReleaseSharedLock(&tdc->lock);
318             afs_PutDCache(tdc);
319         }
320         goto tagain;
321     }
322
323     unlinkFid.Fid.Vnode = 0;
324     if (!tvc) {
325       tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
326     }
327     /* This should not be necessary since afs_lookup() has already
328      * done the work */
329     if (!tvc)
330       if (tdc) {
331         code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
332         if (code == 0) {        
333             afs_int32 cached=0;
334
335             unlinkFid.Cell = adp->fid.Cell;
336             unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
337             if (unlinkFid.Fid.Unique == 0) {
338                 tvc = afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
339             } else {
340                 ObtainReadLock(&afs_xvcache);
341                 tvc = afs_FindVCache(&unlinkFid, 0, DO_STATS);
342                 ReleaseReadLock(&afs_xvcache);
343             }
344         }
345     }
346
347     if (tvc && osi_Active(tvc)) {
348         /* about to delete whole file, prefetch it first */
349         ReleaseWriteLock(&adp->lock);
350         ObtainWriteLock(&tvc->lock,143);
351 #if     defined(AFS_OSF_ENV)
352         afs_Wire(tvc, &treq);
353 #else   /* AFS_OSF_ENV */
354         FetchWholeEnchilada(tvc, &treq);
355 #endif
356         ReleaseWriteLock(&tvc->lock);
357         ObtainWriteLock(&adp->lock,144);
358     }
359
360     osi_dnlc_remove ( adp, aname, tvc);
361     if (tvc) afs_symhint_inval(tvc);
362
363     Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
364     if (tvc) Ttvcr = VREFCOUNT(tvc);
365 #ifdef  AFS_AIX_ENV
366     if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
367 #else
368     if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
369 #endif
370         char *unlname = newname();
371
372         ReleaseWriteLock(&adp->lock);
373         if (tdc) ReleaseSharedLock(&tdc->lock);
374         code = afsrename(adp, aname, adp, unlname, acred, &treq);
375         Tnam1 = unlname;
376         if (!code) {
377             tvc->mvid = (struct VenusFid *)unlname;
378             crhold(acred);
379             if (tvc->uncred) {
380                 crfree(tvc->uncred);
381             }
382             tvc->uncred = acred;
383             tvc->states |= CUnlinked;
384         } else {
385             osi_FreeSmallSpace(unlname);            
386         }
387         if ( tdc )
388                 afs_PutDCache(tdc);
389         afs_PutVCache(tvc);     
390     } else {
391         code = afsremove(adp, tdc, tvc, aname, acred, &treq);
392     }
393 #ifdef  AFS_OSF_ENV
394     afs_PutVCache(adp);
395 #endif  /* AFS_OSF_ENV */
396     afs_PutFakeStat(&fakestate);
397     return code;
398 }
399
400
401 /* afs_remunlink -- This tries to delete the file at the server after it has
402  *     been renamed when unlinked locally but now has been finally released.
403  *
404  * CAUTION -- may be called with avc unheld. */
405
406 int afs_remunlink(register struct vcache *avc, register int doit)
407 {
408     struct AFS_UCRED *cred;
409     char *unlname;
410     struct vcache *adp;
411     struct vrequest treq;
412     struct VenusFid dirFid;
413     register struct dcache *tdc;
414     afs_int32 code=0;
415
416     if (NBObtainWriteLock(&avc->lock, 423))
417         return 0;
418
419     if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
420         if ((code = afs_InitReq(&treq, avc->uncred))) {
421             ReleaseWriteLock(&avc->lock);
422         }
423         else {
424             /* Must bump the refCount because GetVCache may block.
425              * Also clear mvid so no other thread comes here if we block.
426              */
427             unlname = (char *)avc->mvid;
428             avc->mvid = NULL;
429             cred = avc->uncred;
430             avc->uncred = NULL;
431
432 #ifdef AFS_DARWIN_ENV
433            /* this is called by vrele (via VOP_INACTIVE) when the refcount
434               is 0. we can't just call VN_HOLD since vref will panic.
435               we can't just call osi_vnhold because a later AFS_RELE will call
436               vrele again, which will try to call VOP_INACTIVE again after
437               vn_locking the vnode. which would be fine except that our vrele
438               caller also locked the vnode... So instead, we just gimmick the
439               refcounts and hope nobody else can touch the file now */
440             osi_Assert(VREFCOUNT(avc) == 0);
441             VREFCOUNT_SET(avc, 1);
442 #endif
443             VN_HOLD(&avc->v);
444
445             /* We'll only try this once. If it fails, just release the vnode.
446              * Clear after doing hold so that NewVCache doesn't find us yet.
447              */
448             avc->states  &= ~(CUnlinked | CUnlinkedDel);
449
450             ReleaseWriteLock(&avc->lock);
451
452             dirFid.Cell = avc->fid.Cell;
453             dirFid.Fid.Volume = avc->fid.Fid.Volume;
454             dirFid.Fid.Vnode = avc->parentVnode;
455             dirFid.Fid.Unique = avc->parentUnique;
456             adp = afs_GetVCache(&dirFid, &treq, NULL, NULL);
457             
458             if (adp) {
459                 tdc = afs_FindDCache(adp, (afs_size_t)0);
460                 ObtainWriteLock(&adp->lock, 159);
461                 if (tdc) ObtainSharedLock(&tdc->lock, 639);
462
463                 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
464                 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
465                 afs_PutVCache(adp);
466             } else {
467                 /* we failed - and won't be back to try again. */
468                 afs_PutVCache(avc);
469             }
470             osi_FreeSmallSpace(unlname);
471             crfree(cred);
472 #ifdef AFS_DARWIN_ENV
473             osi_Assert(VREFCOUNT(avc) == 1);
474             VREFCOUNT_SET(avc, 0);
475 #endif
476         }
477     }
478     else {
479         ReleaseWriteLock(&avc->lock);
480     }
481
482     return code;
483 }