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 "../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"
24 extern afs_rwlock_t afs_xvcache;
25 extern afs_rwlock_t afs_xcbhash;
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.
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 */
43 afs_create(OSI_VC_ARG(adp), aname, attrs, flags, amode, avcp, acred)
45 #else /* AFS_SGI64_ENV */
46 afs_create(OSI_VC_ARG(adp), aname, attrs, aexcl, amode, avcp, acred)
48 #endif /* AFS_SGI64_ENV */
54 struct AFS_UCRED *acred; {
55 #endif /* AFS_OSF_ENV */
56 afs_int32 origCBs, origZaps, finalZaps;
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;
67 afs_int32 offset, len;
68 struct server *hostp=0;
70 struct volume* volp = 0;
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);
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.
86 AFS_RELE((struct vnode*)(*avcp));
91 if (!afs_ENameOK(aname)) {
95 #if defined(AFS_SUN5_ENV)
96 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR)) {
98 if ((attrs->va_type == VBLK) || (attrs->va_type == VCHR) || (attrs->va_type == VSOCK)) {
100 /* We don't support special devices */
105 code = afs_VerifyVCache(adp, &treq);
108 /** If the volume is read-only, return error without making an RPC to the
111 if ( adp->states & CRO ) {
116 tdc = afs_GetDCache(adp, 0, &treq, &offset, &len, 1);
117 ObtainWriteLock(&adp->lock,135);
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.
123 if (!(adp->states & CStatd)
124 || (tdc && !hsame(adp->m.DataVersion, tdc->f.versionNo))) {
125 ReleaseWriteLock(&adp->lock);
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 */
136 ReleaseWriteLock(&adp->lock);
140 if (aexcl != NONEXCL) {
142 code = EEXIST; /* file exists in excl mode open */
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);
153 if (!tvc) /* lookup failed or wasn't called */
154 tvc = afs_GetVCache(&newFid, &treq, (afs_int32 *)0,
155 (struct vcache*)0, WRITE_LOCK);
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 */
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.
167 if ((amode & VREAD) &&
168 !afs_AccessOK(tvc, PRSFS_READ, &treq, CHECK_MODE_BITS)) {
169 afs_PutVCache(tvc, READ_LOCK);
174 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
175 if ((amode & VWRITE) || (attrs->va_mask & AT_SIZE))
177 if ((amode & VWRITE) || len != 0xffffffff)
180 /* need write mode for these guys */
181 if (!afs_AccessOK(tvc, PRSFS_WRITE, &treq, CHECK_MODE_BITS)) {
182 afs_PutVCache(tvc, READ_LOCK);
187 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
188 if (attrs->va_mask & AT_SIZE)
190 if (len != 0xffffffff)
193 if (vType(tvc) != VREG) {
194 afs_PutVCache(tvc, READ_LOCK);
199 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
200 attrs->va_mask = AT_SIZE;
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),
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);
222 afs_PutVCache(tvc, 0);
228 else code = ENOENT; /* shouldn't get here */
229 /* make sure vrefCount bumped only if code == 0 */
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;
240 origCBs = afs_evenCBs; /* if changes, we don't really have a callback */
241 origZaps = afs_evenZaps; /* number of even numbered vnodes discarded */
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)) {
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
252 #if defined(AFS_AIX_ENV)
253 if (attrs->va_mode != -1) {
255 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
256 if (attrs->va_mask & AT_MODE) {
258 if (attrs->va_mode != ((unsigned short)-1)) {
262 attrs->va_mode = 0x1b6; /* XXX default mode: rw-rw-rw XXX */
265 InStatus.UnixModeBits = attrs->va_mode & 0xffff; /* only care about protection bits */
267 tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
269 hostp = tc->srvr->server; /* remember for callback processing */
271 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_CREATEFILE);
272 #ifdef RX_ENABLE_LOCKS
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
281 #endif /* RX_ENABLE_LOCKS */
283 CallBack.ExpirationTime += now;
287 (afs_Analyze(tc, code, &adp->fid, &treq,
288 AFS_STATS_FS_RPCIDX_CREATEFILE, SHARED_LOCK, (struct cell *)0));
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
294 if (tdc) afs_PutDCache(tdc);
295 ReleaseWriteLock(&adp->lock);
298 #else /* AFS_OSF_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);
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 */
321 #endif /* AFS_OSF_ENV */
324 ObtainWriteLock(&afs_xcbhash, 488);
325 afs_DequeueCallback(adp);
326 adp->states &= ~CStatd;
327 ReleaseWriteLock(&afs_xcbhash);
328 osi_dnlc_purgedp(adp);
330 ReleaseWriteLock(&adp->lock);
331 if (tdc) afs_PutDCache(tdc);
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);
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);
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 */
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,
381 tvc = afs_NewVCache(&newFid, hostp, 0, WRITE_LOCK);
384 ObtainWriteLock(&tvc->lock,139);
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;
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);
400 afs_DequeueCallback(tvc);
401 tvc->states &= ~(CStatd | CUnique);
403 if (tvc->fid.Fid.Vnode & 1 || (vType(tvc) == VDIR))
404 osi_dnlc_purgedp(tvc);
406 ReleaseWriteLock(&afs_xcbhash);
407 afs_ProcessFS(tvc, &OutFidStatus, &treq);
408 ReleaseWriteLock(&tvc->lock);
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
426 ReleaseWriteLock(&afs_xvcache);
430 afs_PutVolume(volp, READ_LOCK);
433 afs_AddMarinerName(aname, *avcp);
434 /* return the new status in vattr */
435 afs_CopyOutAttrs(*avcp, attrs);
439 if (!code && !strcmp(aname, "core"))
440 tvc->states |= CCore1;
441 afs_PutVCache(adp, 0);
442 #endif /* AFS_OSF_ENV */
444 code = afs_CheckCode(code, &treq, 20);
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.
456 * This routine must be called with the stat cache entry write-locked.
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;
466 AFS_STATCNT(afs_LocalHero);
467 hset64(avers, astat->dataVersionHigh, astat->DataVersion);
468 /* this *is* the version number, no matter what */
470 ok = (hsame(avc->m.DataVersion, adc->f.versionNo) && avc->callback
471 && (avc->states & CStatd) && avc->cbExpires >= osi_Time());
476 #if defined(AFS_SGI_ENV)
477 osi_Assert(avc->v.v_type == VDIR);
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;
487 /* we've been tracking things correctly */
488 adc->flags |= DFEntryMod;
489 adc->f.versionNo = avers;
497 if (avc->states & CStatd) {
498 osi_dnlc_purgedp(avc);