openbsd-20021115
[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 "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 int
208 #ifdef  AFS_OSF_ENV
209 afs_remove(ndp)
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)
216     OSI_VC_DECL(adp);
217     char *aname;
218     struct AFS_UCRED *acred; {
219 #endif
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;
227     OSI_VC_CONVERT(adp)
228
229     AFS_STATCNT(afs_remove);
230     afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
231                ICL_TYPE_STRING, aname);
232
233 #ifdef  AFS_OSF_ENV
234     tvc = (struct vcache *)ndp->ni_vp;  /* should never be null */
235 #endif
236
237     if ((code = afs_InitReq(&treq, acred))) {
238 #ifdef  AFS_OSF_ENV
239         afs_PutVCache(adp);
240         afs_PutVCache(tvc);
241 #endif
242         return code;
243     }
244
245     afs_InitFakeStat(&fakestate);
246     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
247     if (code) {
248         afs_PutFakeStat(&fakestate);
249 #ifdef  AFS_OSF_ENV
250         afs_PutVCache(adp);
251         afs_PutVCache(tvc);
252 #endif
253         return code;
254     }
255
256     /* Check if this is dynroot */
257     if (afs_IsDynroot(adp)) {
258         code = afs_DynrootVOPRemove(adp, acred, aname);
259         afs_PutFakeStat(&fakestate);
260 #ifdef  AFS_OSF_ENV
261         afs_PutVCache(adp);
262         afs_PutVCache(tvc);
263 #endif
264         return code;
265     }
266     if (strlen(aname) > AFSNAMEMAX) {
267         afs_PutFakeStat(&fakestate);
268 #ifdef  AFS_OSF_ENV
269         afs_PutVCache(adp);
270         afs_PutVCache(tvc);
271 #endif
272         return ENAMETOOLONG;
273     }
274 tagain:
275     code = afs_VerifyVCache(adp, &treq);
276 #ifdef  AFS_OSF_ENV
277     tvc = VTOAFS(ndp->ni_vp);  /* should never be null */
278     if (code) {
279         afs_PutVCache(adp);
280         afs_PutVCache(tvc);
281         afs_PutFakeStat(&fakestate);
282         return afs_CheckCode(code, &treq, 22);
283     }
284 #else   /* AFS_OSF_ENV */
285     tvc = NULL;
286     if (code) {
287         code = afs_CheckCode(code, &treq, 23);
288         afs_PutFakeStat(&fakestate);
289         return code;
290     }
291 #endif
292
293     /** If the volume is read-only, return error without making an RPC to the
294       * fileserver
295       */
296     if ( adp->states & CRO ) {
297 #ifdef  AFS_OSF_ENV
298         afs_PutVCache(adp);
299         afs_PutVCache(tvc);
300 #endif
301         code = EROFS;
302         afs_PutFakeStat(&fakestate);
303         return code;
304     }
305
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);
309
310     /*
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.
313      */
314     if (!(adp->states & CStatd)
315         || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
316         ReleaseWriteLock(&adp->lock);
317         if (tdc) {
318             ReleaseSharedLock(&tdc->lock);
319             afs_PutDCache(tdc);
320         }
321         goto tagain;
322     }
323
324     unlinkFid.Fid.Vnode = 0;
325     if (!tvc) {
326       tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
327     }
328     /* This should not be necessary since afs_lookup() has already
329      * done the work */
330     if (!tvc)
331       if (tdc) {
332         code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
333         if (code == 0) {        
334             afs_int32 cached=0;
335
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);
340             } else {
341                 ObtainReadLock(&afs_xvcache);
342                 tvc = afs_FindVCache(&unlinkFid, 0, DO_STATS);
343                 ReleaseReadLock(&afs_xvcache);
344             }
345         }
346     }
347
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);
356 #endif
357         ReleaseWriteLock(&tvc->lock);
358         ObtainWriteLock(&adp->lock,144);
359     }
360
361     osi_dnlc_remove ( adp, aname, tvc);
362     if (tvc) afs_symhint_inval(tvc);
363
364     Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
365     if (tvc) Ttvcr = VREFCOUNT(tvc);
366 #ifdef  AFS_AIX_ENV
367     if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
368 #else
369     if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
370 #endif
371         char *unlname = newname();
372
373         ReleaseWriteLock(&adp->lock);
374         if (tdc) ReleaseSharedLock(&tdc->lock);
375         code = afsrename(adp, aname, adp, unlname, acred, &treq);
376         Tnam1 = unlname;
377         if (!code) {
378             tvc->mvid = (struct VenusFid *)unlname;
379             crhold(acred);
380             if (tvc->uncred) {
381                 crfree(tvc->uncred);
382             }
383             tvc->uncred = acred;
384             tvc->states |= CUnlinked;
385         } else {
386             osi_FreeSmallSpace(unlname);            
387         }
388         if ( tdc )
389                 afs_PutDCache(tdc);
390         afs_PutVCache(tvc);     
391     } else {
392         code = afsremove(adp, tdc, tvc, aname, acred, &treq);
393     }
394 #ifdef  AFS_OSF_ENV
395     afs_PutVCache(adp);
396 #endif  /* AFS_OSF_ENV */
397     afs_PutFakeStat(&fakestate);
398     return code;
399 }
400
401
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.
404  *
405  * CAUTION -- may be called with avc unheld. */
406
407 int afs_remunlink(register struct vcache *avc, register int doit)
408 {
409     struct AFS_UCRED *cred;
410     char *unlname;
411     struct vcache *adp;
412     struct vrequest treq;
413     struct VenusFid dirFid;
414     register struct dcache *tdc;
415     afs_int32 code=0;
416
417     if (NBObtainWriteLock(&avc->lock, 423))
418         return 0;
419
420     if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
421         if ((code = afs_InitReq(&treq, avc->uncred))) {
422             ReleaseWriteLock(&avc->lock);
423         }
424         else {
425             /* Must bump the refCount because GetVCache may block.
426              * Also clear mvid so no other thread comes here if we block.
427              */
428             unlname = (char *)avc->mvid;
429             avc->mvid = NULL;
430             cred = avc->uncred;
431             avc->uncred = NULL;
432
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);
443 #endif
444             VN_HOLD(AFSTOV(avc));
445
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.
448              */
449             avc->states  &= ~(CUnlinked | CUnlinkedDel);
450
451             ReleaseWriteLock(&avc->lock);
452
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);
458             
459             if (adp) {
460                 tdc = afs_FindDCache(adp, (afs_size_t)0);
461                 ObtainWriteLock(&adp->lock, 159);
462                 if (tdc) ObtainSharedLock(&tdc->lock, 639);
463
464                 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
465                 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
466                 afs_PutVCache(adp);
467             } else {
468                 /* we failed - and won't be back to try again. */
469                 afs_PutVCache(avc);
470             }
471             osi_FreeSmallSpace(unlname);
472             crfree(cred);
473 #ifdef AFS_DARWIN_ENV
474             osi_Assert(VREFCOUNT(avc) == 1);
475             VREFCOUNT_SET(avc, 0);
476 #endif
477         }
478     }
479     else {
480         ReleaseWriteLock(&avc->lock);
481     }
482
483     return code;
484 }