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 = (struct vcache *)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)) return code;
81 afs_Trace3(afs_iclSetp, CM_TRACE_CREATE, ICL_TYPE_POINTER, adp,
82 ICL_TYPE_STRING, aname, ICL_TYPE_INT32, amode);
85 /* If avcp is passed not null, it's the old reference to this file.
86 * We can use this to avoid create races. For now, just decrement
87 * the reference count on it.
90 AFS_RELE((struct vnode*)(*avcp));
95 if (!afs_ENameOK(aname)) {
99 #if defined(AFS_SUN5_ENV)
100 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR)) {
102 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR) || (attrs->va_type == VSOCK)) {
104 /* We don't support special devices */
109 code = afs_VerifyVCache(adp, &treq);
112 /** If the volume is read-only, return error without making an RPC to the
115 if ( adp->states & CRO ) {
120 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
121 ObtainWriteLock(&adp->lock,135);
122 if (tdc) ObtainSharedLock(&tdc->lock,630);
125 * Make sure that the data in the cache is current. We may have
126 * received a callback while we were waiting for the write lock.
128 if (!(adp->states & CStatd)
129 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
130 ReleaseWriteLock(&adp->lock);
132 ReleaseSharedLock(&tdc->lock);
138 /* see if file already exists. If it does, we only set
139 * the size attributes (to handle O_TRUNC) */
140 code = afs_dir_Lookup(&tdc->f.inode, aname, &newFid.Fid); /* use dnlc first xxx */
142 ReleaseSharedLock(&tdc->lock);
144 ReleaseWriteLock(&adp->lock);
148 if (aexcl != NONEXCL) {
150 code = EEXIST; /* file exists in excl mode open */
153 /* found the file, so use it */
154 newFid.Cell = adp->fid.Cell;
155 newFid.Fid.Volume = adp->fid.Fid.Volume;
156 tvc = (struct vcache *)0;
157 if (newFid.Fid.Unique == 0) {
158 tvc = afs_LookupVCache(&newFid, &treq, (afs_int32 *)0,
159 WRITE_LOCK, adp, aname);
161 if (!tvc) /* lookup failed or wasn't called */
162 tvc = afs_GetVCache(&newFid, &treq, (afs_int32 *)0,
163 (struct vcache*)0, WRITE_LOCK);
166 /* if the thing exists, we need the right access to open it.
167 * we must check that here, since no other checks are
168 * made by the open system call */
169 len = attrs->va_size; /* only do the truncate */
171 * We used to check always for READ access before; the
172 * problem is that we will fail if the existing file
173 * has mode -w-w-w, which is wrong.
175 if ((amode & VREAD) &&
176 !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
177 afs_PutVCache(tvc, READ_LOCK);
182 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
183 if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
185 if ((amode & VWRITE) || len != 0xffffffff)
188 /* needed for write access check */
189 tvc->parentVnode = adp->fid.Fid.Vnode;
190 tvc->parentUnique = adp->fid.Fid.Unique;
191 /* need write mode for these guys */
192 if (!afs_AccessOK(tvc, PRSFS_WRITE, &treq, CHECK_MODE_BITS)) {
193 afs_PutVCache(tvc, READ_LOCK);
198 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
199 if (attrs->va_mask & AT_SIZE)
201 if (len != 0xffffffff)
204 if (vType(tvc) != VREG) {
205 afs_PutVCache(tvc, READ_LOCK);
210 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
211 attrs->va_mask = AT_SIZE;
215 attrs->va_size = len;
216 ObtainWriteLock(&tvc->lock,136);
217 tvc->states |= CCreating;
218 ReleaseWriteLock(&tvc->lock);
219 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
220 #if defined(AFS_SGI64_ENV)
221 code = afs_setattr(VNODE_TO_FIRST_BHV((vnode_t*)tvc),
224 code = afs_setattr(tvc, attrs, 0, acred);
225 #endif /* AFS_SGI64_ENV */
226 #else /* SUN5 || SGI */
227 code = afs_setattr(tvc, attrs, acred);
228 #endif /* SUN5 || SGI */
229 ObtainWriteLock(&tvc->lock,137);
230 tvc->states &= ~CCreating;
231 ReleaseWriteLock(&tvc->lock);
233 afs_PutVCache(tvc, 0);
239 else code = ENOENT; /* shouldn't get here */
240 /* make sure vrefCount bumped only if code == 0 */
245 /* if we create the file, we don't do any access checks, since
246 * that's how O_CREAT is supposed to work */
247 if (adp->states & CForeign) {
248 origCBs = afs_allCBs;
249 origZaps = afs_allZaps;
251 origCBs = afs_evenCBs; /* if changes, we don't really have a callback */
252 origZaps = afs_evenZaps; /* number of even numbered vnodes discarded */
254 InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
255 InStatus.ClientModTime = osi_Time();
256 InStatus.Group = (afs_int32)acred->cr_gid;
257 if (AFS_NFSXLATORREQ(acred)) {
259 * XXX The following is mainly used to fix a bug in the HP-UX
260 * nfs client where they create files with mode of 0 without
261 * doing any setattr later on to fix it. * XXX
263 #if defined(AFS_AIX_ENV)
264 if (attrs->va_mode != -1) {
266 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
267 if (attrs->va_mask & AT_MODE) {
269 if (attrs->va_mode != ((unsigned short)-1)) {
273 attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
276 InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
278 tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
280 hostp = tc->srvr->server; /* remember for callback processing */
282 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
283 #ifdef RX_ENABLE_LOCKS
285 #endif /* RX_ENABLE_LOCKS */
286 code = RXAFS_CreateFile(tc->id, (struct AFSFid *) &adp->fid.Fid,
287 aname, &InStatus, (struct AFSFid *)
288 &newFid.Fid, &OutFidStatus,
289 &OutDirStatus, &CallBack, &tsync);
290 #ifdef RX_ENABLE_LOCKS
292 #endif /* RX_ENABLE_LOCKS */
294 CallBack.ExpirationTime += now;
298 (afs_Analyze(tc, code, &adp->fid, &treq,
299 AFS_STATS_FS_RPCIDX_CREATEFILE, SHARED_LOCK, (struct cell *)0));
301 #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV)
302 if (code == EEXIST && aexcl == NONEXCL) {
303 /* This lookup was handled in the common vn_open code in the
306 ReleaseSharedLock(&tdc->lock);
309 ReleaseWriteLock(&adp->lock);
312 #else /* AFS_OSF_ENV */
314 if (code == EEXIST && !(flags & VEXCL)) {
315 #else /* AFS_SGI64_ENV */
316 if (code == EEXIST && aexcl == NONEXCL) {
317 #endif /* AFS_SGI64_ENV */
318 /* if we get an EEXIST in nonexcl mode, just do a lookup */
320 ReleaseSharedLock(&tdc->lock);
323 ReleaseWriteLock(&adp->lock);
324 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
325 #if defined(AFS_SGI64_ENV)
326 code = afs_lookup(VNODE_TO_FIRST_BHV((vnode_t*)adp), aname, avcp,
327 (struct pathname *)0, 0,
328 (struct vnode *)0, acred);
330 code = afs_lookup(adp, aname, avcp, (struct pathname *)0, 0,
331 (struct vnode *)0, acred);
332 #endif /* AFS_SGI64_ENV */
333 #else /* SUN5 || SGI */
334 code = afs_lookup(adp, aname, avcp, acred);
335 #endif /* SUN5 || SGI */
338 #endif /* AFS_OSF_ENV */
341 ObtainWriteLock(&afs_xcbhash, 488);
342 afs_DequeueCallback(adp);
343 adp->states &= ~CStatd;
344 ReleaseWriteLock(&afs_xcbhash);
345 osi_dnlc_purgedp(adp);
347 ReleaseWriteLock(&adp->lock);
349 ReleaseSharedLock(&tdc->lock);
354 /* otherwise, we should see if we can make the change to the dir locally */
355 if (tdc) UpgradeSToWLock(&tdc->lock, 631);
356 if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
357 /* we can do it locally */
358 code = afs_dir_Create(&tdc->f.inode, aname, &newFid.Fid);
365 ReleaseWriteLock(&tdc->lock);
368 newFid.Cell = adp->fid.Cell;
369 newFid.Fid.Volume = adp->fid.Fid.Volume;
370 ReleaseWriteLock(&adp->lock);
371 volp = afs_FindVolume(&newFid, READ_LOCK);
373 /* New tricky optimistic callback handling algorithm for file creation works
374 as follows. We create the file essentially with no locks set at all. File
375 server may thus handle operations from others cache managers as well as from
376 this very own cache manager that reference the file in question before
377 we managed to create the cache entry. However, if anyone else changes
378 any of the status information for a file, we'll see afs_evenCBs increase
379 (files always have even fids). If someone on this workstation manages
380 to do something to the file, they'll end up having to create a cache
381 entry for the new file. Either we'll find it once we've got the afs_xvcache
382 lock set, or it was also *deleted* the vnode before we got there, in which case
383 we will find evenZaps has changed, too. Thus, we only assume we have the right
384 status information if no callbacks or vnode removals have occurred to even
385 numbered files from the time the call started until the time that we got the xvcache
386 lock set. Of course, this also assumes that any call that modifies a file first
387 gets a write lock on the file's vnode, but if that weren't true, the whole cache manager
388 would fail, since no call would be able to update the local vnode status after modifying
389 a file on a file server. */
390 ObtainWriteLock(&afs_xvcache,138);
391 if (adp->states & CForeign)
392 finalZaps = afs_allZaps; /* do this before calling newvcache */
394 finalZaps = afs_evenZaps; /* do this before calling newvcache */
395 /* don't need to call RemoveVCB, since only path leaving a callback is the
396 one where we pass through afs_NewVCache. Can't have queued a VCB unless
397 we created and freed an entry between file creation time and here, and the
398 freeing of the vnode will change evenZaps. Don't need to update the VLRU
399 queue, since the find will only succeed in the event of a create race, and
400 then the vcache will be at the front of the VLRU queue anyway... */
401 if (!(tvc = afs_FindVCache(&newFid, 0, WRITE_LOCK,
403 tvc = afs_NewVCache(&newFid, hostp, 0, WRITE_LOCK);
406 ObtainWriteLock(&tvc->lock,139);
408 ObtainWriteLock(&afs_xcbhash, 489);
409 finalCBs = afs_evenCBs;
410 /* add the callback in */
411 if (adp->states & CForeign) {
412 tvc->states |= CForeign;
413 finalCBs = afs_allCBs;
415 if (origCBs == finalCBs && origZaps == finalZaps) {
416 tvc->states |= CStatd; /* we've fake entire thing, so don't stat */
417 tvc->states &= ~CBulkFetching;
418 tvc->cbExpires = CallBack.ExpirationTime;
419 afs_QueueCallback(tvc, CBHash(CallBack.ExpirationTime), volp);
422 afs_DequeueCallback(tvc);
423 tvc->states &= ~(CStatd | CUnique);
425 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
426 osi_dnlc_purgedp(tvc);
428 ReleaseWriteLock(&afs_xcbhash);
429 afs_ProcessFS(tvc, &OutFidStatus, &treq);
430 ReleaseWriteLock(&tvc->lock);
437 /* otherwise cache entry already exists, someone else must
438 * have created it. Comments used to say: "don't need write
439 * lock to *clear* these flags" but we should do it anyway.
440 * Code used to clear stat bit and callback, but I don't see
441 * the point -- we didn't have a create race, somebody else just
442 * snuck into NewVCache before we got here, probably a racing
448 ReleaseWriteLock(&afs_xvcache);
452 afs_PutVolume(volp, READ_LOCK);
455 afs_AddMarinerName(aname, *avcp);
456 /* return the new status in vattr */
457 afs_CopyOutAttrs(*avcp, attrs);
461 if (!code && !strcmp(aname, "core"))
462 tvc->states |= CCore1;
463 afs_PutVCache(adp, 0);
464 #endif /* AFS_OSF_ENV */
466 code = afs_CheckCode(code, &treq, 20);
472 * Check to see if we can track the change locally: requires that
473 * we have sufficiently recent info in data cache. If so, we
474 * know the new DataVersion number, and place it correctly in both the
475 * data and stat cache entries. This routine returns 1 if we should
476 * do the operation locally, and 0 otherwise.
478 * This routine must be called with the stat cache entry write-locked,
479 * and dcache entry write-locked.
481 afs_LocalHero(avc, adc, astat, aincr)
482 register struct vcache *avc;
483 register AFSFetchStatus *astat;
484 register struct dcache *adc;
485 register int aincr; {
486 register afs_int32 ok;
489 AFS_STATCNT(afs_LocalHero);
490 hset64(avers, astat->dataVersionHigh, astat->DataVersion);
491 /* this *is* the version number, no matter what */
493 ok = (hsame(avc->m.DataVersion, adc->f.versionNo) && avc->callback
494 && (avc->states & CStatd) && avc->cbExpires >= osi_Time());
499 #if defined(AFS_SGI_ENV)
500 osi_Assert(avc->v.v_type == VDIR);
502 /* The bulk status code used the length as a sequence number. */
503 /* Don't update the vcache entry unless the stats are current. */
504 if (avc->states & CStatd) {
505 hset(avc->m.DataVersion, avers);
506 #ifdef AFS_64BIT_CLIENT
507 FillInt64(avc->m.Length, astat->Length_hi, astat->Length);
508 #else /* AFS_64BIT_ENV */
509 avc->m.Length = astat->Length;
510 #endif /* AFS_64BIT_ENV */
511 avc->m.Date = astat->ClientModTime;
514 /* we've been tracking things correctly */
515 adc->dflags |= DFEntryMod;
516 adc->f.versionNo = avers;
524 if (avc->states & CStatd) {
525 osi_dnlc_purgedp(avc);