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
17 #include <afsconfig.h>
18 #include "afs/param.h"
21 #include "afs/sysincludes.h" /* Standard vendor system headers */
22 #include "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_xcbhash;
30 /* Note that we don't set CDirty here, this is OK because the rename
31 * RPC is called synchronously. */
34 afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
35 char *aname2, AFS_UCRED *acred, struct vrequest *areq)
37 register struct afs_conn *tc;
38 register afs_int32 code = 0;
40 int oneDir, doLocally;
41 afs_size_t offset, len;
42 struct VenusFid unlinkFid, fileFid;
44 struct dcache *tdc1, *tdc2;
45 struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
46 struct AFSVolSync tsync;
48 AFS_STATCNT(afs_rename);
49 afs_Trace4(afs_iclSetp, CM_TRACE_RENAME, ICL_TYPE_POINTER, aodp,
50 ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
51 ICL_TYPE_STRING, aname2);
53 if (strlen(aname1) > AFSNAMEMAX || strlen(aname2) > AFSNAMEMAX) {
58 /* verify the latest versions of the stat cache entries */
60 code = afs_VerifyVCache(aodp, areq);
63 code = afs_VerifyVCache(andp, areq);
67 /* lock in appropriate order, after some checks */
68 if (aodp->f.fid.Cell != andp->f.fid.Cell
69 || aodp->f.fid.Fid.Volume != andp->f.fid.Fid.Volume) {
75 if (andp->f.fid.Fid.Vnode == aodp->f.fid.Fid.Vnode) {
76 if (!strcmp(aname1, aname2)) {
77 /* Same directory and same name; this is a noop and just return success
78 * to save cycles and follow posix standards */
84 if (AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
89 ObtainWriteLock(&andp->lock, 147);
90 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
94 ObtainWriteLock(&tdc1->lock, 643);
97 oneDir = 1; /* only one dude locked */
98 } else if ((andp->f.states & CRO) || (aodp->f.states & CRO)) {
101 } else if (andp->f.fid.Fid.Vnode < aodp->f.fid.Fid.Vnode) {
102 ObtainWriteLock(&andp->lock, 148); /* lock smaller one first */
103 ObtainWriteLock(&aodp->lock, 149);
104 tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
106 ObtainWriteLock(&tdc2->lock, 644);
107 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
109 ObtainWriteLock(&tdc1->lock, 645);
113 ObtainWriteLock(&aodp->lock, 150); /* lock smaller one first */
114 ObtainWriteLock(&andp->lock, 557);
115 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
117 ObtainWriteLock(&tdc1->lock, 646);
120 tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
122 ObtainWriteLock(&tdc2->lock, 647);
125 osi_dnlc_remove(aodp, aname1, 0);
126 osi_dnlc_remove(andp, aname2, 0);
129 * Make sure that the data in the cache is current. We may have
130 * received a callback while we were waiting for the write lock.
133 if (!(aodp->f.states & CStatd)
134 || !hsame(aodp->f.m.DataVersion, tdc1->f.versionNo)) {
136 ReleaseWriteLock(&aodp->lock);
139 ReleaseWriteLock(&tdc2->lock);
142 ReleaseWriteLock(&andp->lock);
144 ReleaseWriteLock(&tdc1->lock);
151 code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
154 ReleaseWriteLock(&tdc1->lock);
157 ReleaseWriteLock(&aodp->lock);
160 ReleaseWriteLock(&tdc2->lock);
163 ReleaseWriteLock(&andp->lock);
168 if (!AFS_IS_DISCON_RW) {
171 tc = afs_Conn(&aodp->f.fid, areq, SHARED_LOCK);
173 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
177 (struct AFSFid *)&aodp->f.fid.Fid,
179 (struct AFSFid *)&andp->f.fid.Fid,
190 (tc, code, &andp->f.fid, areq, AFS_STATS_FS_RPCIDX_RENAME,
194 #if defined(AFS_DISCON_ENV)
197 /* Seek moved file vcache. */
198 fileFid.Cell = aodp->f.fid.Cell;
199 fileFid.Fid.Volume = aodp->f.fid.Fid.Volume;
200 ObtainSharedLock(&afs_xvcache, 754);
201 tvc = afs_FindVCache(&fileFid, 0 , 1);
202 ReleaseSharedLock(&afs_xvcache);
205 /* XXX - We're locking this vcache whilst holding dcaches. Ooops */
206 ObtainWriteLock(&tvc->lock, 750);
207 if (!(tvc->f.ddirty_flags & (VDisconRename|VDisconCreate))) {
208 /* If the vnode was created locally, then we don't care
209 * about recording the rename - we'll do it automatically
210 * on replay. If we've already renamed, we've already stored
211 * the required information about where we came from.
214 if (!aodp->f.shadow.vnode) {
215 /* Make shadow copy of parent dir only. */
216 afs_MakeShadowDir(aodp, tdc1);
219 /* Save old parent dir fid so it will be searchable
222 tvc->f.oldParent.vnode = aodp->f.fid.Fid.Vnode;
223 tvc->f.oldParent.unique = aodp->f.fid.Fid.Unique;
225 afs_DisconAddDirty(tvc,
227 | (oneDir ? VDisconRenameSameDir:0),
231 ReleaseWriteLock(&tvc->lock);
237 } /* if !(AFS_IS_DISCON_RW)*/
238 returnCode = code; /* remember for later */
240 /* Now we try to do things locally. This is really loathsome code. */
241 unlinkFid.Fid.Vnode = 0;
243 /* In any event, we don't really care if the data (tdc2) is not
244 * in the cache; if it isn't, we won't do the update locally. */
245 /* see if version numbers increased properly */
247 if (!AFS_IS_DISCON_RW) {
249 /* number increases by 1 for whole rename operation */
250 if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1)) {
254 /* two separate dirs, each increasing by 1 */
255 if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1))
257 if (!afs_LocalHero(andp, tdc2, &OutNewDirStatus, 1))
270 } /* if (!AFS_IS_DISCON_RW) */
272 /* now really do the work */
274 /* first lookup the fid of the dude we're moving */
275 code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
277 /* delete the source */
278 code = afs_dir_Delete(tdc1, aname1);
280 /* first see if target is there */
282 && afs_dir_Lookup(tdc2, aname2,
283 &unlinkFid.Fid) == 0) {
284 /* target already exists, and will be unlinked by server */
285 code = afs_dir_Delete(tdc2, aname2);
288 ObtainWriteLock(&afs_xdcache, 292);
289 code = afs_dir_Create(tdc2, aname2, &fileFid.Fid);
290 ReleaseWriteLock(&afs_xdcache);
303 /* update dir link counts */
304 if (AFS_IS_DISCON_RW) {
306 aodp->f.m.LinkCount--;
307 andp->f.m.LinkCount++;
309 /* If we're in the same directory, link count doesn't change */
311 aodp->f.m.LinkCount = OutOldDirStatus.LinkCount;
313 andp->f.m.LinkCount = OutNewDirStatus.LinkCount;
316 } else { /* operation failed (code != 0) */
318 /* if failed, server might have done something anyway, and
319 * assume that we know about it */
320 ObtainWriteLock(&afs_xcbhash, 498);
321 afs_DequeueCallback(aodp);
322 afs_DequeueCallback(andp);
323 andp->f.states &= ~CStatd;
324 aodp->f.states &= ~CStatd;
325 ReleaseWriteLock(&afs_xcbhash);
326 osi_dnlc_purgedp(andp);
327 osi_dnlc_purgedp(aodp);
333 ReleaseWriteLock(&tdc1->lock);
337 if ((!oneDir) && tdc2) {
338 ReleaseWriteLock(&tdc2->lock);
342 ReleaseWriteLock(&aodp->lock);
345 ReleaseWriteLock(&andp->lock);
353 /* now, some more details. if unlinkFid.Fid.Vnode then we should decrement
354 * the link count on this file. Note that if fileFid is a dir, then we don't
355 * have to invalidate its ".." entry, since its DataVersion # should have
356 * changed. However, interface is not good enough to tell us the
357 * *file*'s new DataVersion, so we're stuck. Our hack: delete mark
358 * the data as having an "unknown" version (effectively discarding the ".."
360 if (unlinkFid.Fid.Vnode) {
362 unlinkFid.Fid.Volume = aodp->f.fid.Fid.Volume;
363 unlinkFid.Cell = aodp->f.fid.Cell;
365 if (!unlinkFid.Fid.Unique) {
366 tvc = afs_LookupVCache(&unlinkFid, areq, NULL, aodp, aname1);
368 if (!tvc) /* lookup failed or wasn't called */
369 tvc = afs_GetVCache(&unlinkFid, areq, NULL, NULL);
372 #ifdef AFS_BOZONLOCK_ENV
373 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
375 ObtainWriteLock(&tvc->lock, 151);
376 tvc->f.m.LinkCount--;
377 tvc->f.states &= ~CUnique; /* For the dfs xlator */
378 if (tvc->f.m.LinkCount == 0 && !osi_Active(tvc)) {
379 /* if this was last guy (probably) discard from cache.
380 * We have to be careful to not get rid of the stat
381 * information, since otherwise operations will start
382 * failing even if the file was still open (or
383 * otherwise active), and the server no longer has the
384 * info. If the file still has valid links, we'll get
385 * a break-callback msg from the server, so it doesn't
386 * matter that we don't discard the status info */
387 if (!AFS_NFSXLATORREQ(acred))
388 afs_TryToSmush(tvc, acred, 0);
390 ReleaseWriteLock(&tvc->lock);
391 #ifdef AFS_BOZONLOCK_ENV
392 afs_BozonUnlock(&tvc->pvnLock, tvc);
398 /* now handle ".." invalidation */
400 fileFid.Fid.Volume = aodp->f.fid.Fid.Volume;
401 fileFid.Cell = aodp->f.fid.Cell;
402 if (!fileFid.Fid.Unique)
403 tvc = afs_LookupVCache(&fileFid, areq, NULL, andp, aname2);
405 tvc = afs_GetVCache(&fileFid, areq, NULL, (struct vcache *)0);
406 if (tvc && (vType(tvc) == VDIR)) {
407 ObtainWriteLock(&tvc->lock, 152);
408 tdc1 = afs_FindDCache(tvc, (afs_size_t) 0);
410 if (AFS_IS_DISCON_RW) {
411 #if defined(AFS_DISCON_ENV)
412 /* If disconnected, we need to fix (not discard) the "..".*/
413 afs_dir_ChangeFid(tdc1,
415 &aodp->f.fid.Fid.Vnode,
416 &andp->f.fid.Fid.Vnode);
419 ObtainWriteLock(&tdc1->lock, 648);
420 ZapDCE(tdc1); /* mark as unknown */
422 ReleaseWriteLock(&tdc1->lock);
423 afs_PutDCache(tdc1); /* put it back */
426 osi_dnlc_remove(tvc, "..", 0);
427 ReleaseWriteLock(&tvc->lock);
429 } else if (AFS_IS_DISCON_RW && tvc && (vType(tvc) == VREG)) {
430 /* XXX - Should tvc not get locked here? */
431 tvc->f.parent.vnode = andp->f.fid.Fid.Vnode;
432 tvc->f.parent.unique = andp->f.fid.Fid.Unique;
434 /* True we shouldn't come here since tvc SHOULD be a dir, but we
435 * 'syntactically' need to unless we change the 'if' above...
446 #if defined(AFS_SGI_ENV)
447 afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, struct pathname *npnp, AFS_UCRED *acred)
449 afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, AFS_UCRED *acred)
452 register afs_int32 code;
453 struct afs_fakestat_state ofakestate;
454 struct afs_fakestat_state nfakestate;
455 struct vrequest treq;
456 OSI_VC_CONVERT(aodp);
458 code = afs_InitReq(&treq, acred);
461 afs_InitFakeStat(&ofakestate);
462 afs_InitFakeStat(&nfakestate);
466 code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
469 code = afs_EvalFakeStat(&andp, &nfakestate, &treq);
472 code = afsrename(aodp, aname1, andp, aname2, acred, &treq);
474 afs_PutFakeStat(&ofakestate);
475 afs_PutFakeStat(&nfakestate);
479 code = afs_CheckCode(code, &treq, 25);