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