2 * Copyright 2000, International Business Machines Corporation and others.
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
16 #include <afsconfig.h>
17 #include "afs/param.h"
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/afs_stats.h" /* statistics */
23 #include "afs/afs_cbqueue.h"
24 #include "afs/nfsclient.h"
25 #include "afs/afs_osidnlc.h"
26 #include "afs/unified_afs.h"
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.
34 afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, int flags,
35 int amode, struct vcache **avcp, afs_ucred_t *acred)
36 #else /* AFS_SGI64_ENV */
38 afs_create(OSI_VC_DECL(adp), char *aname, struct vattr *attrs,
39 enum vcexcl aexcl, int amode, struct vcache **avcp,
41 #endif /* AFS_SGI64_ENV */
43 afs_int32 origCBs, origZaps, finalZaps;
44 struct vrequest *treq = NULL;
47 struct VenusFid newFid;
48 struct AFSStoreStatus InStatus;
49 struct AFSFetchStatus *OutFidStatus, *OutDirStatus;
50 struct AFSVolSync tsync;
51 struct AFSCallBack CallBack;
54 afs_size_t offset, len;
55 struct server *hostp = 0;
57 struct volume *volp = 0;
58 struct afs_fakestat_state fakestate;
59 struct rx_connection *rxconn;
63 AFS_STATCNT(afs_create);
65 OutFidStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
66 OutDirStatus = osi_AllocSmallSpace(sizeof(struct AFSFetchStatus));
67 memset(&InStatus, 0, sizeof(InStatus));
69 if ((code = afs_CreateReq(&treq, acred)))
72 afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
73 ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
75 afs_InitFakeStat(&fakestate);
78 /* If avcp is passed not null, it's the old reference to this file.
79 * We can use this to avoid create races. For now, just decrement
80 * the reference count on it.
83 AFS_RELE(AFSTOV(*avcp));
88 if (strlen(aname) > AFSNAMEMAX) {
93 if (!afs_ENameOK(aname)) {
97 switch (attrs->va_type) {
100 #if !defined(AFS_SUN5_ENV)
104 /* We don't support special devices or FIFOs */
112 code = afs_EvalFakeStat(&adp, &fakestate, treq);
116 code = afs_VerifyVCache(adp, treq);
120 /** If the volume is read-only, return error without making an RPC to the
123 if (adp->f.states & CRO) {
128 if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
133 tdc = afs_GetDCache(adp, (afs_size_t) 0, treq, &offset, &len, 1);
134 ObtainWriteLock(&adp->lock, 135);
136 ObtainSharedLock(&tdc->lock, 630);
139 * Make sure that the data in the cache is current. We may have
140 * received a callback while we were waiting for the write lock.
142 if (!(adp->f.states & CStatd)
143 || (tdc && !hsame(adp->f.m.DataVersion, tdc->f.versionNo))) {
144 ReleaseWriteLock(&adp->lock);
146 ReleaseSharedLock(&tdc->lock);
152 /* see if file already exists. If it does, we only set
153 * the size attributes (to handle O_TRUNC) */
154 code = afs_dir_Lookup(tdc, aname, &newFid.Fid); /* use dnlc first xxx */
156 ReleaseSharedLock(&tdc->lock);
158 ReleaseWriteLock(&adp->lock);
162 if (aexcl != NONEXCL) {
164 code = EEXIST; /* file exists in excl mode open */
167 /* found the file, so use it */
168 newFid.Cell = adp->f.fid.Cell;
169 newFid.Fid.Volume = adp->f.fid.Fid.Volume;
171 if (newFid.Fid.Unique == 0) {
172 tvc = afs_LookupVCache(&newFid, treq, NULL, adp, aname);
174 if (!tvc) /* lookup failed or wasn't called */
175 tvc = afs_GetVCache(&newFid, treq, NULL, NULL);
178 /* if the thing exists, we need the right access to open it.
179 * we must check that here, since no other checks are
180 * made by the open system call */
181 len = attrs->va_size; /* only do the truncate */
183 * We used to check always for READ access before; the
184 * problem is that we will fail if the existing file
185 * has mode -w-w-w, which is wrong.
188 && !afs_AccessOK(tvc, PRSFS_READ, treq, CHECK_MODE_BITS)) {
193 #if defined(AFS_DARWIN80_ENV)
194 if ((amode & VWRITE) || VATTR_IS_ACTIVE(attrs, va_data_size))
195 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
196 if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
198 if ((amode & VWRITE) || len != 0xffffffff)
201 /* needed for write access check */
202 tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
203 tvc->f.parent.unique = adp->f.fid.Fid.Unique;
204 /* need write mode for these guys */
206 (tvc, PRSFS_WRITE, treq, CHECK_MODE_BITS)) {
212 #if defined(AFS_DARWIN80_ENV)
213 if (VATTR_IS_ACTIVE(attrs, va_data_size))
214 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
215 if (attrs->va_mask & AT_SIZE)
217 if (len != 0xffffffff)
220 if (vType(tvc) != VREG) {
226 #if defined(AFS_DARWIN80_ENV)
228 VATTR_SET_SUPPORTED(attrs, va_data_size);
229 VATTR_SET_ACTIVE(attrs, va_data_size);
230 #elif defined(UKERNEL)
231 attrs->va_mask = ATTR_SIZE;
232 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
233 attrs->va_mask = AT_SIZE;
237 attrs->va_size = len;
238 ObtainWriteLock(&tvc->lock, 136);
239 tvc->f.states |= CCreating;
240 ReleaseWriteLock(&tvc->lock);
241 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
242 #if defined(AFS_SGI64_ENV)
244 afs_setattr(VNODE_TO_FIRST_BHV((vnode_t *) tvc),
247 code = afs_setattr(tvc, attrs, 0, acred);
248 #endif /* AFS_SGI64_ENV */
249 #else /* SUN5 || SGI */
250 code = afs_setattr(tvc, attrs, acred);
251 #endif /* SUN5 || SGI */
252 ObtainWriteLock(&tvc->lock, 137);
253 tvc->f.states &= ~CCreating;
254 ReleaseWriteLock(&tvc->lock);
263 /* Directory entry already exists, but we cannot fetch the
264 * fid it points to. */
267 /* make sure vrefCount bumped only if code == 0 */
272 /* if we create the file, we don't do any access checks, since
273 * that's how O_CREAT is supposed to work */
274 if (adp->f.states & CForeign) {
275 origCBs = afs_allCBs;
276 origZaps = afs_allZaps;
278 origCBs = afs_evenCBs; /* if changes, we don't really have a callback */
279 origZaps = afs_evenZaps; /* number of even numbered vnodes discarded */
281 InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
282 InStatus.ClientModTime = osi_Time();
283 InStatus.Group = (afs_int32) afs_cr_gid(acred);
284 if (AFS_NFSXLATORREQ(acred)) {
286 * XXX The following is mainly used to fix a bug in the HP-UX
287 * nfs client where they create files with mode of 0 without
288 * doing any setattr later on to fix it. * XXX
290 #if defined(AFS_AIX_ENV)
291 if (attrs->va_mode != -1) {
293 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
294 if (attrs->va_mask & AT_MODE) {
296 if (attrs->va_mode != ((unsigned short)-1)) {
300 attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
304 if (!AFS_IS_DISCONNECTED) {
305 /* If not disconnected, connect to the server.*/
307 InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
309 tc = afs_Conn(&adp->f.fid, treq, SHARED_LOCK, &rxconn);
311 hostp = tc->parent->srvr->server; /* remember for callback processing */
313 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
316 RXAFS_CreateFile(rxconn, (struct AFSFid *)&adp->f.fid.Fid,
317 aname, &InStatus, (struct AFSFid *)
318 &newFid.Fid, OutFidStatus, OutDirStatus,
322 CallBack.ExpirationTime += now;
326 (tc, rxconn, code, &adp->f.fid, treq, AFS_STATS_FS_RPCIDX_CREATEFILE,
329 if ((code == EEXIST || code == UAEEXIST) &&
332 #else /* AFS_SGI64_ENV */
336 /* if we get an EEXIST in nonexcl mode, just do a lookup */
338 ReleaseSharedLock(&tdc->lock);
341 ReleaseWriteLock(&adp->lock);
344 #if defined(AFS_SGI64_ENV)
345 code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t *) adp), aname, avcp,
346 NULL, 0, NULL, acred);
347 #elif defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
348 code = afs_lookup(adp, aname, avcp, NULL, 0, NULL, acred);
349 #elif defined(UKERNEL)
350 code = afs_lookup(adp, aname, avcp, acred, 0);
351 #elif !defined(AFS_DARWIN_ENV)
352 code = afs_lookup(adp, aname, avcp, acred);
359 ObtainWriteLock(&afs_xcbhash, 488);
360 afs_DequeueCallback(adp);
361 adp->f.states &= ~CStatd;
362 ReleaseWriteLock(&afs_xcbhash);
363 osi_dnlc_purgedp(adp);
365 ReleaseWriteLock(&adp->lock);
367 ReleaseSharedLock(&tdc->lock);
374 /* Generate a fake FID for disconnected mode. */
375 newFid.Cell = adp->f.fid.Cell;
376 newFid.Fid.Volume = adp->f.fid.Fid.Volume;
377 afs_GenFakeFid(&newFid, VREG, 1);
378 } /* if (!AFS_IS_DISCON_RW) */
380 /* otherwise, we should see if we can make the change to the dir locally */
382 UpgradeSToWLock(&tdc->lock, 631);
383 if (AFS_IS_DISCON_RW || afs_LocalHero(adp, tdc, OutDirStatus, 1)) {
384 /* we can do it locally */
385 ObtainWriteLock(&afs_xdcache, 291);
386 code = afs_dir_Create(tdc, aname, &newFid.Fid);
387 ReleaseWriteLock(&afs_xdcache);
394 ReleaseWriteLock(&tdc->lock);
397 if (AFS_IS_DISCON_RW)
398 adp->f.m.LinkCount++;
400 newFid.Cell = adp->f.fid.Cell;
401 newFid.Fid.Volume = adp->f.fid.Fid.Volume;
402 ReleaseWriteLock(&adp->lock);
403 volp = afs_FindVolume(&newFid, READ_LOCK);
405 /* New tricky optimistic callback handling algorithm for file creation works
406 * as follows. We create the file essentially with no locks set at all. File
407 * server may thus handle operations from others cache managers as well as from
408 * this very own cache manager that reference the file in question before
409 * we managed to create the cache entry. However, if anyone else changes
410 * any of the status information for a file, we'll see afs_evenCBs increase
411 * (files always have even fids). If someone on this workstation manages
412 * to do something to the file, they'll end up having to create a cache
413 * entry for the new file. Either we'll find it once we've got the afs_xvcache
414 * lock set, or it was also *deleted* the vnode before we got there, in which case
415 * we will find evenZaps has changed, too. Thus, we only assume we have the right
416 * status information if no callbacks or vnode removals have occurred to even
417 * numbered files from the time the call started until the time that we got the xvcache
418 * lock set. Of course, this also assumes that any call that modifies a file first
419 * gets a write lock on the file's vnode, but if that weren't true, the whole cache manager
420 * would fail, since no call would be able to update the local vnode status after modifying
421 * a file on a file server. */
422 ObtainWriteLock(&afs_xvcache, 138);
423 if (adp->f.states & CForeign)
424 finalZaps = afs_allZaps; /* do this before calling newvcache */
426 finalZaps = afs_evenZaps; /* do this before calling newvcache */
427 /* don't need to call RemoveVCB, since only path leaving a callback is the
428 * one where we pass through afs_NewVCache. Can't have queued a VCB unless
429 * we created and freed an entry between file creation time and here, and the
430 * freeing of the vnode will change evenZaps. Don't need to update the VLRU
431 * queue, since the find will only succeed in the event of a create race, and
432 * then the vcache will be at the front of the VLRU queue anyway... */
433 if (!(tvc = afs_FindVCache(&newFid, 0, DO_STATS))) {
434 tvc = afs_NewVCache(&newFid, hostp);
437 ObtainWriteLock(&tvc->lock, 139);
439 ObtainWriteLock(&afs_xcbhash, 489);
440 finalCBs = afs_evenCBs;
441 /* add the callback in */
442 if (adp->f.states & CForeign) {
443 tvc->f.states |= CForeign;
444 finalCBs = afs_allCBs;
446 if (origCBs == finalCBs && origZaps == finalZaps) {
447 tvc->f.states |= CStatd; /* we've fake entire thing, so don't stat */
448 tvc->f.states &= ~CBulkFetching;
449 if (!AFS_IS_DISCON_RW) {
450 tvc->cbExpires = CallBack.ExpirationTime;
451 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
454 afs_DequeueCallback(tvc);
455 tvc->f.states &= ~(CStatd | CUnique);
457 if (tvc->f.fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
458 osi_dnlc_purgedp(tvc);
460 ReleaseWriteLock(&afs_xcbhash);
461 if (AFS_IS_DISCON_RW) {
462 afs_DisconAddDirty(tvc, VDisconCreate, 0);
463 afs_GenDisconStatus(adp, tvc, &newFid, attrs, treq, VREG);
465 afs_ProcessFS(tvc, OutFidStatus, treq);
468 tvc->f.parent.vnode = adp->f.fid.Fid.Vnode;
469 tvc->f.parent.unique = adp->f.fid.Fid.Unique;
470 ReleaseWriteLock(&tvc->lock);
475 /* Cannot create a new vcache. */
479 /* otherwise cache entry already exists, someone else must
480 * have created it. Comments used to say: "don't need write
481 * lock to *clear* these flags" but we should do it anyway.
482 * Code used to clear stat bit and callback, but I don't see
483 * the point -- we didn't have a create race, somebody else just
484 * snuck into NewVCache before we got here, probably a racing
490 ReleaseWriteLock(&afs_xvcache);
497 afs_PutVolume(volp, READ_LOCK);
501 afs_AddMarinerName(aname, *avcp);
502 /* return the new status in vattr */
503 afs_CopyOutAttrs(*avcp, attrs);
505 afs_MarinerLog("store$Creating", *avcp);
508 afs_PutFakeStat(&fakestate);
509 code = afs_CheckCode(code, treq, 20);
510 afs_DestroyReq(treq);
513 osi_FreeSmallSpace(OutFidStatus);
514 osi_FreeSmallSpace(OutDirStatus);
520 * Check to see if we can track the change locally: requires that
521 * we have sufficiently recent info in data cache. If so, we
522 * know the new DataVersion number, and place it correctly in both the
523 * data and stat cache entries. This routine returns 1 if we should
524 * do the operation locally, and 0 otherwise.
526 * This routine must be called with the stat cache entry write-locked,
527 * and dcache entry write-locked.
530 afs_LocalHero(struct vcache *avc, struct dcache *adc,
531 AFSFetchStatus * astat, int aincr)
536 AFS_STATCNT(afs_LocalHero);
537 hset64(avers, astat->dataVersionHigh, astat->DataVersion);
538 /* avers *is* the version number now, no matter what */
541 /* does what's in the dcache *now* match what's in the vcache *now*,
542 * and do we have a valid callback? if not, our local copy is not "ok" */
543 ok = (hsame(avc->f.m.DataVersion, adc->f.versionNo) && avc->callback
544 && (avc->f.states & CStatd) && avc->cbExpires >= osi_Time());
549 /* check that the DV on the server is what we expect it to be */
551 hset(newDV, adc->f.versionNo);
552 hadd32(newDV, aincr);
553 if (!hsame(avers, newDV)) {
557 #if defined(AFS_SGI_ENV)
558 osi_Assert(avc->v.v_type == VDIR);
560 /* The bulk status code used the length as a sequence number. */
561 /* Don't update the vcache entry unless the stats are current. */
562 if (avc->f.states & CStatd) {
563 hset(avc->f.m.DataVersion, avers);
564 #ifdef AFS_64BIT_CLIENT
565 FillInt64(avc->f.m.Length, astat->Length_hi, astat->Length);
566 #else /* AFS_64BIT_CLIENT */
567 avc->f.m.Length = astat->Length;
568 #endif /* AFS_64BIT_CLIENT */
569 avc->f.m.Date = astat->ClientModTime;
572 /* we've been tracking things correctly */
573 adc->dflags |= DFEntryMod;
574 adc->f.versionNo = avers;
581 if (avc->f.states & CStatd) {
582 osi_dnlc_purgedp(avc);