unlink-fix-20050721
[openafs.git] / src / afs / VNOPS / afs_vnop_create.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_create
13  * afs_LocalHero
14  */
15
16 #include <afsconfig.h>
17 #include "afs/param.h"
18
19 RCSID
20     ("$Header$");
21
22 #include "afs/sysincludes.h"    /* Standard vendor system headers */
23 #include "afsincludes.h"        /* Afs-based standard headers */
24 #include "afs/afs_stats.h"      /* statistics */
25 #include "afs/afs_cbqueue.h"
26 #include "afs/nfsclient.h"
27 #include "afs/afs_osidnlc.h"
28
29 /* question: does afs_create need to set CDirty in the adp or the avc?
30  * I think we can get away without it, but I'm not sure.  Note that
31  * afs_setattr is called in here for truncation.
32  */
33 #ifdef AFS_SGI64_ENV
34 int
35 afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, int flags,
36            int amode, struct vcache **avcp, struct AFS_UCRED *acred)
37 #else /* AFS_SGI64_ENV */
38 int
39 afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
40            enum vcexcl aexcl, int amode, struct vcache **avcp,
41            struct AFS_UCRED *acred)
42 #endif                          /* AFS_SGI64_ENV */
43 {
44     afs_int32 origCBs, origZaps, finalZaps;
45     struct vrequest treq;
46     register afs_int32 code;
47     register struct conn *tc;
48     struct VenusFid newFid;
49     struct AFSStoreStatus InStatus;
50     struct AFSFetchStatus OutFidStatus, OutDirStatus;
51     struct AFSVolSync tsync;
52     struct AFSCallBack CallBack;
53     afs_int32 now;
54     struct dcache *tdc;
55     afs_size_t offset, len;
56     struct server *hostp = 0;
57     struct vcache *tvc;
58     struct volume *volp = 0;
59     struct afs_fakestat_state fakestate;
60     XSTATS_DECLS;
61     OSI_VC_CONVERT(adp);
62
63
64     AFS_STATCNT(afs_create);
65     if ((code = afs_InitReq(&treq, acred)))
66         goto done2;
67
68     afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
69                ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
70
71     afs_InitFakeStat(&fakestate);
72
73 #ifdef AFS_SGI65_ENV
74     /* If avcp is passed not null, it's the old reference to this file.
75      * We can use this to avoid create races. For now, just decrement
76      * the reference count on it.
77      */
78     if (*avcp) {
79         AFS_RELE(AFSTOV(*avcp));
80         *avcp = NULL;
81     }
82 #endif
83
84     if (strlen(aname) > AFSNAMEMAX) {
85         code = ENAMETOOLONG;
86         goto done;
87     }
88
89     if (!afs_ENameOK(aname)) {
90         code = EINVAL;
91         goto done;
92     }
93     switch (attrs->va_type) {
94     case VBLK:
95     case VCHR:
96 #if     !defined(AFS_SUN5_ENV)
97     case VSOCK:
98 #endif
99     case VFIFO:
100         /* We don't support special devices or FIFOs */
101         code = EINVAL;
102         goto done;
103     default:
104         ;
105     }
106     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
107     if (code)
108         goto done;
109   tagain:
110     code = afs_VerifyVCache(adp, &treq);
111     if (code)
112         goto done;
113
114     /** If the volume is read-only, return error without making an RPC to the
115       * fileserver
116       */
117     if (adp->states & CRO) {
118         code = EROFS;
119         goto done;
120     }
121
122     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
123     ObtainWriteLock(&adp->lock, 135);
124     if (tdc)
125         ObtainSharedLock(&tdc->lock, 630);
126
127     /*
128      * Make sure that the data in the cache is current. We may have
129      * received a callback while we were waiting for the write lock.
130      */
131     if (!(adp->states & CStatd)
132         || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
133         ReleaseWriteLock(&adp->lock);
134         if (tdc) {
135             ReleaseSharedLock(&tdc->lock);
136             afs_PutDCache(tdc);
137         }
138         goto tagain;
139     }
140     if (tdc) {
141         /* see if file already exists.  If it does, we only set 
142          * the size attributes (to handle O_TRUNC) */
143         code = afs_dir_Lookup(tdc, aname, &newFid.Fid); /* use dnlc first xxx */
144         if (code == 0) {
145             ReleaseSharedLock(&tdc->lock);
146             afs_PutDCache(tdc);
147             ReleaseWriteLock(&adp->lock);
148 #ifdef AFS_SGI64_ENV
149             if (flags & VEXCL) {
150 #else
151             if (aexcl != NONEXCL) {
152 #endif
153                 code = EEXIST;  /* file exists in excl mode open */
154                 goto done;
155             }
156             /* found the file, so use it */
157             newFid.Cell = adp->fid.Cell;
158             newFid.Fid.Volume = adp->fid.Fid.Volume;
159             tvc = NULL;
160             if (newFid.Fid.Unique == 0) {
161                 tvc = afs_LookupVCache(&newFid, &treq, NULL, adp, aname);
162             }
163             if (!tvc)           /* lookup failed or wasn't called */
164                 tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
165
166             if (tvc) {
167                 /* if the thing exists, we need the right access to open it.
168                  * we must check that here, since no other checks are
169                  * made by the open system call */
170                 len = attrs->va_size;   /* only do the truncate */
171                 /*
172                  * We used to check always for READ access before; the
173                  * problem is that we will fail if the existing file
174                  * has mode -w-w-w, which is wrong.
175                  */
176                 if ((amode & VREAD)
177                     && !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
178                     afs_PutVCache(tvc);
179                     code = EACCES;
180                     goto done;
181                 }
182 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
183                 if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
184 #else
185                 if ((amode & VWRITE) || len != 0xffffffff)
186 #endif
187                 {
188                     /* needed for write access check */
189                     tvc->parentVnode = adp->fid.Fid.Vnode;
190                     tvc->parentUnique = adp->fid.Fid.Unique;
191                     /* need write mode for these guys */
192                     if (!afs_AccessOK
193                         (tvc, PRSFS_WRITE, &treq, CHECK_MODE_BITS)) {
194                         afs_PutVCache(tvc);
195                         code = EACCES;
196                         goto done;
197                     }
198                 }
199 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
200                 if (attrs->va_mask & AT_SIZE)
201 #else
202                 if (len != 0xffffffff)
203 #endif
204                 {
205                     if (vType(tvc) != VREG) {
206                         afs_PutVCache(tvc);
207                         code = EISDIR;
208                         goto done;
209                     }
210                     /* do a truncate */
211 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
212                     attrs->va_mask = AT_SIZE;
213 #else
214                     VATTR_NULL(attrs);
215 #endif
216                     attrs->va_size = len;
217                     ObtainWriteLock(&tvc->lock, 136);
218                     tvc->states |= CCreating;
219                     ReleaseWriteLock(&tvc->lock);
220 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
221 #if defined(AFS_SGI64_ENV)
222                     code =
223                         afs_setattr(VNODE_TO_FIRST_BHV((vnode_t *) tvc),
224                                     attrs, 0, acred);
225 #else
226                     code = afs_setattr(tvc, attrs, 0, acred);
227 #endif /* AFS_SGI64_ENV */
228 #else /* SUN5 || SGI */
229                     code = afs_setattr(tvc, attrs, acred);
230 #endif /* SUN5 || SGI */
231                     ObtainWriteLock(&tvc->lock, 137);
232                     tvc->states &= ~CCreating;
233                     ReleaseWriteLock(&tvc->lock);
234                     if (code) {
235                         afs_PutVCache(tvc);
236                         goto done;
237                     }
238                 }
239                 *avcp = tvc;
240             } else
241                 code = ENOENT;  /* shouldn't get here */
242             /* make sure vrefCount bumped only if code == 0 */
243             goto done;
244         }
245     }
246
247     /* if we create the file, we don't do any access checks, since
248      * that's how O_CREAT is supposed to work */
249     if (adp->states & CForeign) {
250         origCBs = afs_allCBs;
251         origZaps = afs_allZaps;
252     } else {
253         origCBs = afs_evenCBs;  /* if changes, we don't really have a callback */
254         origZaps = afs_evenZaps;        /* number of even numbered vnodes discarded */
255     }
256     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
257     InStatus.ClientModTime = osi_Time();
258     InStatus.Group = (afs_int32) acred->cr_gid;
259     if (AFS_NFSXLATORREQ(acred)) {
260         /*
261          * XXX The following is mainly used to fix a bug in the HP-UX
262          * nfs client where they create files with mode of 0 without
263          * doing any setattr later on to fix it.  * XXX
264          */
265 #if     defined(AFS_AIX_ENV)
266         if (attrs->va_mode != -1) {
267 #else
268 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
269         if (attrs->va_mask & AT_MODE) {
270 #else
271         if (attrs->va_mode != ((unsigned short)-1)) {
272 #endif
273 #endif
274             if (!attrs->va_mode)
275                 attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
276         }
277     }
278     InStatus.UnixModeBits = attrs->va_mode & 0xffff;    /* only care about protection bits */
279     do {
280         tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
281         if (tc) {
282             hostp = tc->srvr->server;   /* remember for callback processing */
283             now = osi_Time();
284             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
285             RX_AFS_GUNLOCK();
286             code =
287                 RXAFS_CreateFile(tc->id, (struct AFSFid *)&adp->fid.Fid,
288                                  aname, &InStatus, (struct AFSFid *)
289                                  &newFid.Fid, &OutFidStatus, &OutDirStatus,
290                                  &CallBack, &tsync);
291             RX_AFS_GLOCK();
292             XSTATS_END_TIME;
293             CallBack.ExpirationTime += now;
294         } else
295             code = -1;
296     } while (afs_Analyze
297              (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
298               SHARED_LOCK, NULL));
299
300     if (code == EEXIST &&
301 #ifdef AFS_SGI64_ENV
302     !(flags & VEXCL)
303 #else /* AFS_SGI64_ENV */
304     aexcl == NONEXCL
305 #endif
306     ) {
307         /* if we get an EEXIST in nonexcl mode, just do a lookup */
308         if (tdc) {
309             ReleaseSharedLock(&tdc->lock);
310             afs_PutDCache(tdc);
311         }
312         ReleaseWriteLock(&adp->lock);
313 #if !(defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV))
314 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
315 #if defined(AFS_SGI64_ENV)
316         code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp, 
317                           NULL, 0, NULL, acred);
318 #else
319         code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
320 #endif /* AFS_SGI64_ENV */
321 #else /* SUN5 || SGI */
322         code = afs_lookup(adp, aname, avcp, acred);
323 #endif /* SUN5 || SGI */
324 #endif /* !(AFS_OSF_ENV || AFS_DARWIN_ENV) */
325         goto done;
326     }
327     if (code) {
328         if (code < 0) {
329             ObtainWriteLock(&afs_xcbhash, 488);
330             afs_DequeueCallback(adp);
331             adp->states &= ~CStatd;
332             ReleaseWriteLock(&afs_xcbhash);
333             osi_dnlc_purgedp(adp);
334         }
335         ReleaseWriteLock(&adp->lock);
336         if (tdc) {
337             ReleaseSharedLock(&tdc->lock);
338             afs_PutDCache(tdc);
339         }
340         goto done;
341     }
342     /* otherwise, we should see if we can make the change to the dir locally */
343     if (tdc)
344         UpgradeSToWLock(&tdc->lock, 631);
345     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
346         /* we can do it locally */
347         code = afs_dir_Create(tdc, aname, &newFid.Fid);
348         if (code) {
349             ZapDCE(tdc);
350             DZap(tdc);
351         }
352     }
353     if (tdc) {
354         ReleaseWriteLock(&tdc->lock);
355         afs_PutDCache(tdc);
356     }
357     newFid.Cell = adp->fid.Cell;
358     newFid.Fid.Volume = adp->fid.Fid.Volume;
359     ReleaseWriteLock(&adp->lock);
360     volp = afs_FindVolume(&newFid, READ_LOCK);
361
362     /* New tricky optimistic callback handling algorithm for file creation works
363      * as follows.  We create the file essentially with no locks set at all.  File
364      * server may thus handle operations from others cache managers as well as from
365      * this very own cache manager that reference the file in question before
366      * we managed to create the cache entry.  However, if anyone else changes
367      * any of the status information for a file, we'll see afs_evenCBs increase
368      * (files always have even fids).  If someone on this workstation manages
369      * to do something to the file, they'll end up having to create a cache
370      * entry for the new file.  Either we'll find it once we've got the afs_xvcache
371      * lock set, or it was also *deleted* the vnode before we got there, in which case
372      * we will find evenZaps has changed, too.  Thus, we only assume we have the right
373      * status information if no callbacks or vnode removals have occurred to even
374      * numbered files from the time the call started until the time that we got the xvcache
375      * lock set.  Of course, this also assumes that any call that modifies a file first
376      * gets a write lock on the file's vnode, but if that weren't true, the whole cache manager
377      * would fail, since no call would be able to update the local vnode status after modifying
378      * a file on a file server. */
379     ObtainWriteLock(&afs_xvcache, 138);
380     if (adp->states & CForeign)
381         finalZaps = afs_allZaps;        /* do this before calling newvcache */
382     else
383         finalZaps = afs_evenZaps;       /* do this before calling newvcache */
384     /* don't need to call RemoveVCB, since only path leaving a callback is the
385      * one where we pass through afs_NewVCache.  Can't have queued a VCB unless
386      * we created and freed an entry between file creation time and here, and the
387      * freeing of the vnode will change evenZaps.  Don't need to update the VLRU
388      * queue, since the find will only succeed in the event of a create race, and 
389      * then the vcache will be at the front of the VLRU queue anyway...  */
390     if (!(tvc = afs_FindVCache(&newFid, 0, DO_STATS))) {
391         tvc = afs_NewVCache(&newFid, hostp);
392         if (tvc) {
393             int finalCBs;
394             ObtainWriteLock(&tvc->lock, 139);
395
396             ObtainWriteLock(&afs_xcbhash, 489);
397             finalCBs = afs_evenCBs;
398             /* add the callback in */
399             if (adp->states & CForeign) {
400                 tvc->states |= CForeign;
401                 finalCBs = afs_allCBs;
402             }
403             if (origCBs == finalCBs && origZaps == finalZaps) {
404                 tvc->states |= CStatd;  /* we've fake entire thing, so don't stat */
405                 tvc->states &= ~CBulkFetching;
406                 tvc->cbExpires = CallBack.ExpirationTime;
407                 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
408             } else {
409                 afs_DequeueCallback(tvc);
410                 tvc->states &= ~(CStatd | CUnique);
411                 tvc->callback = 0;
412                 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
413                     osi_dnlc_purgedp(tvc);
414             }
415             ReleaseWriteLock(&afs_xcbhash);
416             afs_ProcessFS(tvc, &OutFidStatus, &treq);
417             tvc->parentVnode = adp->fid.Fid.Vnode;
418             tvc->parentUnique = adp->fid.Fid.Unique;
419             ReleaseWriteLock(&tvc->lock);
420             *avcp = tvc;
421             code = 0;
422         } else
423             code = ENOENT;
424     } else {
425         /* otherwise cache entry already exists, someone else must
426          * have created it.  Comments used to say:  "don't need write
427          * lock to *clear* these flags" but we should do it anyway.
428          * Code used to clear stat bit and callback, but I don't see 
429          * the point -- we didn't have a create race, somebody else just
430          * snuck into NewVCache before we got here, probably a racing 
431          * lookup.
432          */
433         *avcp = tvc;
434         code = 0;
435     }
436     ReleaseWriteLock(&afs_xvcache);
437
438   done:
439     if (volp)
440         afs_PutVolume(volp, READ_LOCK);
441
442     if (code == 0) {
443         afs_AddMarinerName(aname, *avcp);
444         /* return the new status in vattr */
445         afs_CopyOutAttrs(*avcp, attrs);
446     }
447 #ifdef  AFS_OSF_ENV
448     if (!code && !strcmp(aname, "core"))
449         tvc->states |= CCore1;
450 #endif
451
452     afs_PutFakeStat(&fakestate);
453     code = afs_CheckCode(code, &treq, 20);
454
455   done2:
456     return code;
457 }
458
459
460 /*
461  * Check to see if we can track the change locally: requires that
462  * we have sufficiently recent info in data cache.  If so, we
463  * know the new DataVersion number, and place it correctly in both the
464  * data and stat cache entries.  This routine returns 1 if we should
465  * do the operation locally, and 0 otherwise.
466  *
467  * This routine must be called with the stat cache entry write-locked,
468  * and dcache entry write-locked.
469  */
470 int
471 afs_LocalHero(register struct vcache *avc, register struct dcache *adc,
472               register AFSFetchStatus * astat, register int aincr)
473 {
474     register afs_int32 ok;
475     afs_hyper_t avers;
476
477     AFS_STATCNT(afs_LocalHero);
478     hset64(avers, astat->dataVersionHigh, astat->DataVersion);
479     /* this *is* the version number, no matter what */
480     if (adc) {
481         ok = (hsame(avc->m.DataVersion, adc->f.versionNo) && avc->callback
482               && (avc->states & CStatd) && avc->cbExpires >= osi_Time());
483     } else {
484         ok = 0;
485     }
486 #if defined(AFS_SGI_ENV)
487     osi_Assert(avc->v.v_type == VDIR);
488 #endif
489     /* The bulk status code used the length as a sequence number.  */
490     /* Don't update the vcache entry unless the stats are current. */
491     if (avc->states & CStatd) {
492         hset(avc->m.DataVersion, avers);
493 #ifdef AFS_64BIT_CLIENT
494         FillInt64(avc->m.Length, astat->Length_hi, astat->Length);
495 #else /* AFS_64BIT_ENV */
496         avc->m.Length = astat->Length;
497 #endif /* AFS_64BIT_ENV */
498         avc->m.Date = astat->ClientModTime;
499     }
500     if (ok) {
501         /* we've been tracking things correctly */
502         adc->dflags |= DFEntryMod;
503         adc->f.versionNo = avers;
504         return 1;
505     } else {
506         if (adc) {
507             ZapDCE(adc);
508             DZap(adc);
509         }
510         if (avc->states & CStatd) {
511             osi_dnlc_purgedp(avc);
512         }
513         return 0;
514     }
515 }