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"
21 #include "../afs/sysincludes.h" /* Standard vendor system headers */
22 #include "../afs/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"
28 extern afs_rwlock_t afs_xvcache;
29 extern afs_rwlock_t afs_xcbhash;
31 /* question: does afs_create need to set CDirty in the adp or the avc?
32 * I think we can get away without it, but I'm not sure. Note that
33 * afs_setattr is called in here for truncation.
36 afs_create(ndp, attrs)
37 struct nameidata *ndp;
38 struct vattr *attrs; {
39 register struct vcache *adp = VTOAFS(ndp->ni_dvp);
40 char *aname = ndp->ni_dent.d_name;
41 enum vcexcl aexcl = NONEXCL; /* XXX - create called properly */
42 int amode = 0; /* XXX - checked in higher level */
43 struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
44 struct ucred *acred = ndp->ni_cred;
45 #else /* AFS_OSF_ENV */
47 afs_create(OSI_VC_ARG(adp), aname, attrs, flags, amode, avcp, acred)
49 #else /* AFS_SGI64_ENV */
50 afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
52 #endif /* AFS_SGI64_ENV */
58 struct AFS_UCRED *acred; {
59 #endif /* AFS_OSF_ENV */
60 afs_int32 origCBs, origZaps, finalZaps;
62 register afs_int32 code;
63 register struct conn *tc;
64 struct VenusFid newFid;
65 struct AFSStoreStatus InStatus;
66 struct AFSFetchStatus OutFidStatus, OutDirStatus;
67 struct AFSVolSync tsync;
68 struct AFSCallBack CallBack;
71 afs_size_t offset, len;
72 struct server *hostp=0;
74 struct volume* volp = 0;
79 AFS_STATCNT(afs_create);
80 if (code = afs_InitReq(&treq, acred))
83 afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
84 ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
87 /* If avcp is passed not null, it's the old reference to this file.
88 * We can use this to avoid create races. For now, just decrement
89 * the reference count on it.
92 AFS_RELE(AFSTOV(*avcp));
97 if (strlen(aname) > AFSNAMEMAX) {
102 if (!afs_ENameOK(aname)) {
106 #if defined(AFS_SUN5_ENV)
107 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR)) {
109 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR) || (attrs->va_type == VSOCK)) {
111 /* We don't support special devices */
116 code = afs_VerifyVCache(adp, &treq);
119 /** If the volume is read-only, return error without making an RPC to the
122 if ( adp->states & CRO ) {
127 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
128 ObtainWriteLock(&adp->lock,135);
129 if (tdc) ObtainSharedLock(&tdc->lock,630);
132 * Make sure that the data in the cache is current. We may have
133 * received a callback while we were waiting for the write lock.
135 if (!(adp->states & CStatd)
136 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
137 ReleaseWriteLock(&adp->lock);
139 ReleaseSharedLock(&tdc->lock);
145 /* see if file already exists. If it does, we only set
146 * the size attributes (to handle O_TRUNC) */
147 code = afs_dir_Lookup(&tdc->f.inode, aname, &newFid.Fid); /* use dnlc first xxx */
149 ReleaseSharedLock(&tdc->lock);
151 ReleaseWriteLock(&adp->lock);
155 if (aexcl != NONEXCL) {
157 code = EEXIST; /* file exists in excl mode open */
160 /* found the file, so use it */
161 newFid.Cell = adp->fid.Cell;
162 newFid.Fid.Volume = adp->fid.Fid.Volume;
163 tvc = (struct vcache *)0;
164 if (newFid.Fid.Unique == 0) {
165 tvc = afs_LookupVCache(&newFid, &treq, (afs_int32 *)0,
166 WRITE_LOCK, adp, aname);
168 if (!tvc) /* lookup failed or wasn't called */
169 tvc = afs_GetVCache(&newFid, &treq, (afs_int32 *)0,
170 (struct vcache*)0, WRITE_LOCK);
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 */
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.
182 if ((amode & VREAD) &&
183 !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
184 afs_PutVCache(tvc, READ_LOCK);
189 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
190 if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
192 if ((amode & VWRITE) || len != 0xffffffff)
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, READ_LOCK);
205 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
206 if (attrs->va_mask & AT_SIZE)
208 if (len != 0xffffffff)
211 if (vType(tvc) != VREG) {
212 afs_PutVCache(tvc, READ_LOCK);
217 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
218 attrs->va_mask = AT_SIZE;
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),
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);
240 afs_PutVCache(tvc, 0);
246 else code = ENOENT; /* shouldn't get here */
247 /* make sure vrefCount bumped only if code == 0 */
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;
258 origCBs = afs_evenCBs; /* if changes, we don't really have a callback */
259 origZaps = afs_evenZaps; /* number of even numbered vnodes discarded */
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)) {
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
270 #if defined(AFS_AIX_ENV)
271 if (attrs->va_mode != -1) {
273 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
274 if (attrs->va_mask & AT_MODE) {
276 if (attrs->va_mode != ((unsigned short)-1)) {
280 attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
283 InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
285 tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
287 hostp = tc->srvr->server; /* remember for callback processing */
289 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
290 #ifdef RX_ENABLE_LOCKS
292 #endif /* RX_ENABLE_LOCKS */
293 code = RXAFS_CreateFile(tc->id, (struct AFSFid *) &adp->fid.Fid,
294 aname, &InStatus, (struct AFSFid *)
295 &newFid.Fid, &OutFidStatus,
296 &OutDirStatus, &CallBack, &tsync);
297 #ifdef RX_ENABLE_LOCKS
299 #endif /* RX_ENABLE_LOCKS */
301 CallBack.ExpirationTime += now;
305 (afs_Analyze(tc, code, &adp->fid, &treq,
306 AFS_STATS_FS_RPCIDX_CREATEFILE, SHARED_LOCK, (struct cell *)0));
308 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
309 if (code == EEXIST && aexcl == NONEXCL) {
310 /* This lookup was handled in the common vn_open code in the
313 ReleaseSharedLock(&tdc->lock);
316 ReleaseWriteLock(&adp->lock);
319 #else /* AFS_OSF_ENV */
321 if (code == EEXIST && !(flags & VEXCL)) {
322 #else /* AFS_SGI64_ENV */
323 if (code == EEXIST && aexcl == NONEXCL) {
324 #endif /* AFS_SGI64_ENV */
325 /* if we get an EEXIST in nonexcl mode, just do a lookup */
327 ReleaseSharedLock(&tdc->lock);
330 ReleaseWriteLock(&adp->lock);
331 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
332 #if defined(AFS_SGI64_ENV)
333 code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t*)adp), aname, avcp,
334 (struct pathname *)0, 0,
335 (struct vnode *)0, acred);
337 code = afs_lookup(adp, aname, avcp, (struct pathname *)0, 0,
338 (struct vnode *)0, acred);
339 #endif /* AFS_SGI64_ENV */
340 #else /* SUN5 || SGI */
341 code = afs_lookup(adp, aname, avcp, acred);
342 #endif /* SUN5 || SGI */
345 #endif /* AFS_OSF_ENV */
348 ObtainWriteLock(&afs_xcbhash, 488);
349 afs_DequeueCallback(adp);
350 adp->states &= ~CStatd;
351 ReleaseWriteLock(&afs_xcbhash);
352 osi_dnlc_purgedp(adp);
354 ReleaseWriteLock(&adp->lock);
356 ReleaseSharedLock(&tdc->lock);
361 /* otherwise, we should see if we can make the change to the dir locally */
362 if (tdc) UpgradeSToWLock(&tdc->lock, 631);
363 if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
364 /* we can do it locally */
365 code = afs_dir_Create(&tdc->f.inode, aname, &newFid.Fid);
372 ReleaseWriteLock(&tdc->lock);
375 newFid.Cell = adp->fid.Cell;
376 newFid.Fid.Volume = adp->fid.Fid.Volume;
377 ReleaseWriteLock(&adp->lock);
378 volp = afs_FindVolume(&newFid, READ_LOCK);
380 /* New tricky optimistic callback handling algorithm for file creation works
381 as follows. We create the file essentially with no locks set at all. File
382 server may thus handle operations from others cache managers as well as from
383 this very own cache manager that reference the file in question before
384 we managed to create the cache entry. However, if anyone else changes
385 any of the status information for a file, we'll see afs_evenCBs increase
386 (files always have even fids). If someone on this workstation manages
387 to do something to the file, they'll end up having to create a cache
388 entry for the new file. Either we'll find it once we've got the afs_xvcache
389 lock set, or it was also *deleted* the vnode before we got there, in which case
390 we will find evenZaps has changed, too. Thus, we only assume we have the right
391 status information if no callbacks or vnode removals have occurred to even
392 numbered files from the time the call started until the time that we got the xvcache
393 lock set. Of course, this also assumes that any call that modifies a file first
394 gets a write lock on the file's vnode, but if that weren't true, the whole cache manager
395 would fail, since no call would be able to update the local vnode status after modifying
396 a file on a file server. */
397 ObtainWriteLock(&afs_xvcache,138);
398 if (adp->states & CForeign)
399 finalZaps = afs_allZaps; /* do this before calling newvcache */
401 finalZaps = afs_evenZaps; /* do this before calling newvcache */
402 /* don't need to call RemoveVCB, since only path leaving a callback is the
403 one where we pass through afs_NewVCache. Can't have queued a VCB unless
404 we created and freed an entry between file creation time and here, and the
405 freeing of the vnode will change evenZaps. Don't need to update the VLRU
406 queue, since the find will only succeed in the event of a create race, and
407 then the vcache will be at the front of the VLRU queue anyway... */
408 if (!(tvc = afs_FindVCache(&newFid, 0, WRITE_LOCK,
410 tvc = afs_NewVCache(&newFid, hostp, 0, WRITE_LOCK);
413 ObtainWriteLock(&tvc->lock,139);
415 ObtainWriteLock(&afs_xcbhash, 489);
416 finalCBs = afs_evenCBs;
417 /* add the callback in */
418 if (adp->states & CForeign) {
419 tvc->states |= CForeign;
420 finalCBs = afs_allCBs;
422 if (origCBs == finalCBs && origZaps == finalZaps) {
423 tvc->states |= CStatd; /* we've fake entire thing, so don't stat */
424 tvc->states &= ~CBulkFetching;
425 tvc->cbExpires = CallBack.ExpirationTime;
426 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
429 afs_DequeueCallback(tvc);
430 tvc->states &= ~(CStatd | CUnique);
432 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
433 osi_dnlc_purgedp(tvc);
435 ReleaseWriteLock(&afs_xcbhash);
436 afs_ProcessFS(tvc, &OutFidStatus, &treq);
437 ReleaseWriteLock(&tvc->lock);
444 /* otherwise cache entry already exists, someone else must
445 * have created it. Comments used to say: "don't need write
446 * lock to *clear* these flags" but we should do it anyway.
447 * Code used to clear stat bit and callback, but I don't see
448 * the point -- we didn't have a create race, somebody else just
449 * snuck into NewVCache before we got here, probably a racing
455 ReleaseWriteLock(&afs_xvcache);
459 afs_PutVolume(volp, READ_LOCK);
462 afs_AddMarinerName(aname, *avcp);
463 /* return the new status in vattr */
464 afs_CopyOutAttrs(*avcp, attrs);
468 if (!code && !strcmp(aname, "core"))
469 tvc->states |= CCore1;
472 code = afs_CheckCode(code, &treq, 20);
476 afs_PutVCache(adp, 0);
477 #endif /* AFS_OSF_ENV */
484 * Check to see if we can track the change locally: requires that
485 * we have sufficiently recent info in data cache. If so, we
486 * know the new DataVersion number, and place it correctly in both the
487 * data and stat cache entries. This routine returns 1 if we should
488 * do the operation locally, and 0 otherwise.
490 * This routine must be called with the stat cache entry write-locked,
491 * and dcache entry write-locked.
493 afs_LocalHero(avc, adc, astat, aincr)
494 register struct vcache *avc;
495 register AFSFetchStatus *astat;
496 register struct dcache *adc;
497 register int aincr; {
498 register afs_int32 ok;
501 AFS_STATCNT(afs_LocalHero);
502 hset64(avers, astat->dataVersionHigh, astat->DataVersion);
503 /* this *is* the version number, no matter what */
505 ok = (hsame(avc->m.DataVersion, adc->f.versionNo) && avc->callback
506 && (avc->states & CStatd) && avc->cbExpires >= osi_Time());
511 #if defined(AFS_SGI_ENV)
512 osi_Assert(avc->v.v_type == VDIR);
514 /* The bulk status code used the length as a sequence number. */
515 /* Don't update the vcache entry unless the stats are current. */
516 if (avc->states & CStatd) {
517 hset(avc->m.DataVersion, avers);
518 #ifdef AFS_64BIT_CLIENT
519 FillInt64(avc->m.Length, astat->Length_hi, astat->Length);
520 #else /* AFS_64BIT_ENV */
521 avc->m.Length = astat->Length;
522 #endif /* AFS_64BIT_ENV */
523 avc->m.Date = astat->ClientModTime;
526 /* we've been tracking things correctly */
527 adc->dflags |= DFEntryMod;
528 adc->f.versionNo = avers;
536 if (avc->states & CStatd) {
537 osi_dnlc_purgedp(avc);