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