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