aix51-support-20021008
[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 AFSFetchStatus OutDirStatus;
226     struct AFSVolSync tsync;
227     struct afs_fakestat_state fakestate;
228     XSTATS_DECLS
229     OSI_VC_CONVERT(adp)
230
231     AFS_STATCNT(afs_remove);
232     afs_Trace2(afs_iclSetp, CM_TRACE_REMOVE, ICL_TYPE_POINTER, adp,
233                ICL_TYPE_STRING, aname);
234
235 #ifdef  AFS_OSF_ENV
236     tvc = (struct vcache *)ndp->ni_vp;  /* should never be null */
237 #endif
238
239     if ((code = afs_InitReq(&treq, acred))) {
240 #ifdef  AFS_OSF_ENV
241         afs_PutVCache(adp);
242         afs_PutVCache(tvc);
243 #endif
244         return code;
245     }
246
247     afs_InitFakeStat(&fakestate);
248     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
249     if (code) {
250         afs_PutFakeStat(&fakestate);
251 #ifdef  AFS_OSF_ENV
252         afs_PutVCache(adp);
253         afs_PutVCache(tvc);
254 #endif
255         return code;
256     }
257
258     /* Check if this is dynroot */
259     if (afs_IsDynroot(adp)) {
260         code = afs_DynrootVOPRemove(adp, acred, aname);
261         afs_PutFakeStat(&fakestate);
262 #ifdef  AFS_OSF_ENV
263         afs_PutVCache(adp);
264         afs_PutVCache(tvc);
265 #endif
266         return code;
267     }
268     if (strlen(aname) > AFSNAMEMAX) {
269         afs_PutFakeStat(&fakestate);
270 #ifdef  AFS_OSF_ENV
271         afs_PutVCache(adp);
272         afs_PutVCache(tvc);
273 #endif
274         return ENAMETOOLONG;
275     }
276 tagain:
277     code = afs_VerifyVCache(adp, &treq);
278 #ifdef  AFS_OSF_ENV
279     tvc = VTOAFS(ndp->ni_vp);  /* should never be null */
280     if (code) {
281         afs_PutVCache(adp);
282         afs_PutVCache(tvc);
283         afs_PutFakeStat(&fakestate);
284         return afs_CheckCode(code, &treq, 22);
285     }
286 #else   /* AFS_OSF_ENV */
287     tvc = NULL;
288     if (code) {
289         code = afs_CheckCode(code, &treq, 23);
290         afs_PutFakeStat(&fakestate);
291         return code;
292     }
293 #endif
294
295     /** If the volume is read-only, return error without making an RPC to the
296       * fileserver
297       */
298     if ( adp->states & CRO ) {
299 #ifdef  AFS_OSF_ENV
300         afs_PutVCache(adp);
301         afs_PutVCache(tvc);
302 #endif
303         code = EROFS;
304         afs_PutFakeStat(&fakestate);
305         return code;
306     }
307
308     tdc = afs_GetDCache(adp, (afs_size_t) 0,    &treq, &offset, &len, 1);  /* test for error below */
309     ObtainWriteLock(&adp->lock,142);
310     if (tdc) ObtainSharedLock(&tdc->lock, 638);
311
312     /*
313      * Make sure that the data in the cache is current. We may have
314      * received a callback while we were waiting for the write lock.
315      */
316     if (!(adp->states & CStatd)
317         || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
318         ReleaseWriteLock(&adp->lock);
319         if (tdc) {
320             ReleaseSharedLock(&tdc->lock);
321             afs_PutDCache(tdc);
322         }
323         goto tagain;
324     }
325
326     unlinkFid.Fid.Vnode = 0;
327     if (!tvc) {
328       tvc = osi_dnlc_lookup (adp, aname, WRITE_LOCK);
329     }
330     /* This should not be necessary since afs_lookup() has already
331      * done the work */
332     if (!tvc)
333       if (tdc) {
334         code = afs_dir_Lookup(&tdc->f.inode, aname, &unlinkFid.Fid);
335         if (code == 0) {        
336             afs_int32 cached=0;
337
338             unlinkFid.Cell = adp->fid.Cell;
339             unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
340             if (unlinkFid.Fid.Unique == 0) {
341                 tvc = afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
342             } else {
343                 ObtainReadLock(&afs_xvcache);
344                 tvc = afs_FindVCache(&unlinkFid, 0, DO_STATS);
345                 ReleaseReadLock(&afs_xvcache);
346             }
347         }
348     }
349
350     if (tvc && osi_Active(tvc)) {
351         /* about to delete whole file, prefetch it first */
352         ReleaseWriteLock(&adp->lock);
353         ObtainWriteLock(&tvc->lock,143);
354 #if     defined(AFS_OSF_ENV)
355         afs_Wire(tvc, &treq);
356 #else   /* AFS_OSF_ENV */
357         FetchWholeEnchilada(tvc, &treq);
358 #endif
359         ReleaseWriteLock(&tvc->lock);
360         ObtainWriteLock(&adp->lock,144);
361     }
362
363     osi_dnlc_remove ( adp, aname, tvc);
364     if (tvc) afs_symhint_inval(tvc);
365
366     Tadp1 = adp; Tadpr = VREFCOUNT(adp); Ttvc = tvc; Tnam = aname; Tnam1 = 0;
367     if (tvc) Ttvcr = VREFCOUNT(tvc);
368 #ifdef  AFS_AIX_ENV
369     if (tvc && (VREFCOUNT(tvc) > 2) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
370 #else
371     if (tvc && (VREFCOUNT(tvc) > 1) && tvc->opens > 0 && !(tvc->states & CUnlinked)) {
372 #endif
373         char *unlname = newname();
374
375         ReleaseWriteLock(&adp->lock);
376         if (tdc) ReleaseSharedLock(&tdc->lock);
377         code = afsrename(adp, aname, adp, unlname, acred, &treq);
378         Tnam1 = unlname;
379         if (!code) {
380             tvc->mvid = (struct VenusFid *)unlname;
381             crhold(acred);
382             if (tvc->uncred) {
383                 crfree(tvc->uncred);
384             }
385             tvc->uncred = acred;
386             tvc->states |= CUnlinked;
387         } else {
388             osi_FreeSmallSpace(unlname);            
389         }
390         if ( tdc )
391                 afs_PutDCache(tdc);
392         afs_PutVCache(tvc);     
393     } else {
394         code = afsremove(adp, tdc, tvc, aname, acred, &treq);
395     }
396 #ifdef  AFS_OSF_ENV
397     afs_PutVCache(adp);
398 #endif  /* AFS_OSF_ENV */
399     afs_PutFakeStat(&fakestate);
400     return code;
401 }
402
403
404 /* afs_remunlink -- This tries to delete the file at the server after it has
405  *     been renamed when unlinked locally but now has been finally released.
406  *
407  * CAUTION -- may be called with avc unheld. */
408
409 int afs_remunlink(register struct vcache *avc, register int doit)
410 {
411     struct AFS_UCRED *cred;
412     char *unlname;
413     struct vcache *adp;
414     struct vrequest treq;
415     struct VenusFid dirFid;
416     register struct dcache *tdc;
417     afs_int32 code=0;
418
419     if (NBObtainWriteLock(&avc->lock, 423))
420         return 0;
421
422     if (avc->mvid && (doit || (avc->states & CUnlinkedDel))) {
423         if ((code = afs_InitReq(&treq, avc->uncred))) {
424             ReleaseWriteLock(&avc->lock);
425         }
426         else {
427             /* Must bump the refCount because GetVCache may block.
428              * Also clear mvid so no other thread comes here if we block.
429              */
430             unlname = (char *)avc->mvid;
431             avc->mvid = NULL;
432             cred = avc->uncred;
433             avc->uncred = NULL;
434
435 #ifdef AFS_DARWIN_ENV
436            /* this is called by vrele (via VOP_INACTIVE) when the refcount
437               is 0. we can't just call VN_HOLD since vref will panic.
438               we can't just call osi_vnhold because a later AFS_RELE will call
439               vrele again, which will try to call VOP_INACTIVE again after
440               vn_locking the vnode. which would be fine except that our vrele
441               caller also locked the vnode... So instead, we just gimmick the
442               refcounts and hope nobody else can touch the file now */
443             osi_Assert(VREFCOUNT(avc) == 0);
444             VREFCOUNT_SET(avc, 1);
445 #endif
446             VN_HOLD(&avc->v);
447
448             /* We'll only try this once. If it fails, just release the vnode.
449              * Clear after doing hold so that NewVCache doesn't find us yet.
450              */
451             avc->states  &= ~(CUnlinked | CUnlinkedDel);
452
453             ReleaseWriteLock(&avc->lock);
454
455             dirFid.Cell = avc->fid.Cell;
456             dirFid.Fid.Volume = avc->fid.Fid.Volume;
457             dirFid.Fid.Vnode = avc->parentVnode;
458             dirFid.Fid.Unique = avc->parentUnique;
459             adp = afs_GetVCache(&dirFid, &treq, NULL, NULL);
460             
461             if (adp) {
462                 tdc = afs_FindDCache(adp, (afs_size_t)0);
463                 ObtainWriteLock(&adp->lock, 159);
464                 if (tdc) ObtainSharedLock(&tdc->lock, 639);
465
466                 /* afsremove releases the adp & tdc locks, and does vn_rele(avc) */
467                 code = afsremove(adp, tdc, avc, unlname, cred, &treq);
468                 afs_PutVCache(adp);
469             } else {
470                 /* we failed - and won't be back to try again. */
471                 afs_PutVCache(avc);
472             }
473             osi_FreeSmallSpace(unlname);
474             crfree(cred);
475 #ifdef AFS_DARWIN_ENV
476             osi_Assert(VREFCOUNT(avc) == 1);
477             VREFCOUNT_SET(avc, 0);
478 #endif
479         }
480     }
481     else {
482         ReleaseWriteLock(&avc->lock);
483     }
484
485     return code;
486 }