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"
23 #include "afs/sysincludes.h" /* Standard vendor system headers */
24 #include "afsincludes.h" /* Afs-based standard headers */
25 #include "afs/afs_stats.h" /* statistics */
26 #include "afs/afs_cbqueue.h"
27 #include "afs/nfsclient.h"
28 #include "afs/afs_osidnlc.h"
30 extern afs_rwlock_t afs_xcbhash;
32 /* Note that we don't set CDirty here, this is OK because the rename
33 * RPC is called synchronously. */
36 afsrename(struct vcache *aodp, char *aname1, struct vcache *andp,
37 char *aname2, struct AFS_UCRED *acred, struct vrequest *areq)
39 register struct conn *tc;
40 register afs_int32 code;
42 int oneDir, doLocally;
43 afs_size_t offset, len;
44 struct VenusFid unlinkFid, fileFid;
46 struct dcache *tdc1, *tdc2;
47 struct AFSFetchStatus OutOldDirStatus, OutNewDirStatus;
48 struct AFSVolSync tsync;
50 AFS_STATCNT(afs_rename);
51 afs_Trace4(afs_iclSetp, CM_TRACE_RENAME, ICL_TYPE_POINTER, aodp,
52 ICL_TYPE_STRING, aname1, ICL_TYPE_POINTER, andp,
53 ICL_TYPE_STRING, aname2);
55 if (strlen(aname1) > AFSNAMEMAX || strlen(aname2) > AFSNAMEMAX) {
60 /* verify the latest versions of the stat cache entries */
62 code = afs_VerifyVCache(aodp, areq);
65 code = afs_VerifyVCache(andp, areq);
69 /* lock in appropriate order, after some checks */
70 if (aodp->fid.Cell != andp->fid.Cell
71 || aodp->fid.Fid.Volume != andp->fid.Fid.Volume) {
77 if (andp->fid.Fid.Vnode == aodp->fid.Fid.Vnode) {
78 if (!strcmp(aname1, aname2)) {
79 /* Same directory and same name; this is a noop and just return success
80 * to save cycles and follow posix standards */
85 ObtainWriteLock(&andp->lock, 147);
86 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
90 ObtainWriteLock(&tdc1->lock, 643);
93 oneDir = 1; /* only one dude locked */
94 } else if ((andp->states & CRO) || (aodp->states & CRO)) {
97 } else if (andp->fid.Fid.Vnode < aodp->fid.Fid.Vnode) {
98 ObtainWriteLock(&andp->lock, 148); /* lock smaller one first */
99 ObtainWriteLock(&aodp->lock, 149);
100 tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
102 ObtainWriteLock(&tdc2->lock, 644);
103 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
105 ObtainWriteLock(&tdc1->lock, 645);
109 ObtainWriteLock(&aodp->lock, 150); /* lock smaller one first */
110 ObtainWriteLock(&andp->lock, 557);
111 tdc1 = afs_GetDCache(aodp, (afs_size_t) 0, areq, &offset, &len, 0);
113 ObtainWriteLock(&tdc1->lock, 646);
116 tdc2 = afs_FindDCache(andp, (afs_size_t) 0);
118 ObtainWriteLock(&tdc2->lock, 647);
121 osi_dnlc_remove(aodp, aname1, 0);
122 osi_dnlc_remove(andp, aname2, 0);
123 afs_symhint_inval(aodp);
124 afs_symhint_inval(andp);
127 * Make sure that the data in the cache is current. We may have
128 * received a callback while we were waiting for the write lock.
131 if (!(aodp->states & CStatd)
132 || !hsame(aodp->m.DataVersion, tdc1->f.versionNo)) {
134 ReleaseWriteLock(&aodp->lock);
137 ReleaseWriteLock(&tdc2->lock);
140 ReleaseWriteLock(&andp->lock);
142 ReleaseWriteLock(&tdc1->lock);
149 code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
152 ReleaseWriteLock(&tdc1->lock);
155 ReleaseWriteLock(&aodp->lock);
158 ReleaseWriteLock(&tdc2->lock);
161 ReleaseWriteLock(&andp->lock);
166 /* locks are now set, proceed to do the real work */
168 tc = afs_Conn(&aodp->fid, areq, SHARED_LOCK);
170 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_RENAME);
173 RXAFS_Rename(tc->id, (struct AFSFid *)&aodp->fid.Fid, aname1,
174 (struct AFSFid *)&andp->fid.Fid, aname2,
175 &OutOldDirStatus, &OutNewDirStatus, &tsync);
182 (tc, code, &andp->fid, areq, AFS_STATS_FS_RPCIDX_RENAME,
185 returnCode = code; /* remember for later */
187 /* Now we try to do things locally. This is really loathsome code. */
188 unlinkFid.Fid.Vnode = 0;
190 /* In any event, we don't really care if the data (tdc2) is not
191 * in the cache; if it isn't, we won't do the update locally. */
192 /* see if version numbers increased properly */
195 /* number increases by 1 for whole rename operation */
196 if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1)) {
200 /* two separate dirs, each increasing by 1 */
201 if (!afs_LocalHero(aodp, tdc1, &OutOldDirStatus, 1))
203 if (!afs_LocalHero(andp, tdc2, &OutNewDirStatus, 1))
216 /* now really do the work */
218 /* first lookup the fid of the dude we're moving */
219 code = afs_dir_Lookup(tdc1, aname1, &fileFid.Fid);
221 /* delete the source */
222 code = afs_dir_Delete(tdc1, aname1);
224 /* first see if target is there */
226 && afs_dir_Lookup(tdc2, aname2,
227 &unlinkFid.Fid) == 0) {
228 /* target already exists, and will be unlinked by server */
229 code = afs_dir_Delete(tdc2, aname2);
232 code = afs_dir_Create(tdc2, aname2, &fileFid.Fid);
244 /* update dir link counts */
245 aodp->m.LinkCount = OutOldDirStatus.LinkCount;
247 andp->m.LinkCount = OutNewDirStatus.LinkCount;
249 } else { /* operation failed (code != 0) */
251 /* if failed, server might have done something anyway, and
252 * assume that we know about it */
253 ObtainWriteLock(&afs_xcbhash, 498);
254 afs_DequeueCallback(aodp);
255 afs_DequeueCallback(andp);
256 andp->states &= ~CStatd;
257 aodp->states &= ~CStatd;
258 ReleaseWriteLock(&afs_xcbhash);
259 osi_dnlc_purgedp(andp);
260 osi_dnlc_purgedp(aodp);
266 ReleaseWriteLock(&tdc1->lock);
270 if ((!oneDir) && tdc2) {
271 ReleaseWriteLock(&tdc2->lock);
275 ReleaseWriteLock(&aodp->lock);
277 ReleaseWriteLock(&andp->lock);
284 /* now, some more details. if unlinkFid.Fid.Vnode then we should decrement
285 * the link count on this file. Note that if fileFid is a dir, then we don't
286 * have to invalidate its ".." entry, since its DataVersion # should have
287 * changed. However, interface is not good enough to tell us the
288 * *file*'s new DataVersion, so we're stuck. Our hack: delete mark
289 * the data as having an "unknown" version (effectively discarding the ".."
291 if (unlinkFid.Fid.Vnode) {
292 unlinkFid.Fid.Volume = aodp->fid.Fid.Volume;
293 unlinkFid.Cell = aodp->fid.Cell;
295 if (!unlinkFid.Fid.Unique) {
296 tvc = afs_LookupVCache(&unlinkFid, areq, NULL, aodp, aname1);
298 if (!tvc) /* lookup failed or wasn't called */
299 tvc = afs_GetVCache(&unlinkFid, areq, NULL, NULL);
302 #ifdef AFS_BOZONLOCK_ENV
303 afs_BozonLock(&tvc->pvnLock, tvc); /* Since afs_TryToSmush will do a pvn_vptrunc */
305 ObtainWriteLock(&tvc->lock, 151);
307 tvc->states &= ~CUnique; /* For the dfs xlator */
308 if (tvc->m.LinkCount == 0 && !osi_Active(tvc)) {
309 /* if this was last guy (probably) discard from cache.
310 * We have to be careful to not get rid of the stat
311 * information, since otherwise operations will start
312 * failing even if the file was still open (or
313 * otherwise active), and the server no longer has the
314 * info. If the file still has valid links, we'll get
315 * a break-callback msg from the server, so it doesn't
316 * matter that we don't discard the status info */
317 if (!AFS_NFSXLATORREQ(acred))
318 afs_TryToSmush(tvc, acred, 0);
320 ReleaseWriteLock(&tvc->lock);
321 #ifdef AFS_BOZONLOCK_ENV
322 afs_BozonUnlock(&tvc->pvnLock, tvc);
328 /* now handle ".." invalidation */
330 fileFid.Fid.Volume = aodp->fid.Fid.Volume;
331 fileFid.Cell = aodp->fid.Cell;
332 if (!fileFid.Fid.Unique)
333 tvc = afs_LookupVCache(&fileFid, areq, NULL, andp, aname2);
335 tvc = afs_GetVCache(&fileFid, areq, NULL, (struct vcache *)0);
336 if (tvc && (vType(tvc) == VDIR)) {
337 ObtainWriteLock(&tvc->lock, 152);
338 tdc1 = afs_FindDCache(tvc, (afs_size_t) 0);
340 ObtainWriteLock(&tdc1->lock, 648);
341 ZapDCE(tdc1); /* mark as unknown */
343 ReleaseWriteLock(&tdc1->lock);
344 afs_PutDCache(tdc1); /* put it back */
346 osi_dnlc_remove(tvc, "..", 0);
347 ReleaseWriteLock(&tvc->lock);
350 /* True we shouldn't come here since tvc SHOULD be a dir, but we
351 * 'syntactically' need to unless we change the 'if' above...
362 #if defined(AFS_SGI_ENV)
363 afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, achar *name2, struct pathname *npnp, struct AFS_UCRED *acred)
365 afs_rename(OSI_VC_DECL(aodp), char *aname1, struct vcache *andp, char *aname2, struct AFS_UCRED *acred)
368 register afs_int32 code;
369 struct afs_fakestat_state ofakestate;
370 struct afs_fakestat_state nfakestate;
371 struct vrequest treq;
372 OSI_VC_CONVERT(aodp);
374 code = afs_InitReq(&treq, acred);
377 afs_InitFakeStat(&ofakestate);
378 afs_InitFakeStat(&nfakestate);
379 code = afs_EvalFakeStat(&aodp, &ofakestate, &treq);
382 code = afs_EvalFakeStat(&andp, &nfakestate, &treq);
385 code = afsrename(aodp, aname1, andp, aname2, acred, &treq);
387 afs_PutFakeStat(&ofakestate);
388 afs_PutFakeStat(&nfakestate);
389 code = afs_CheckCode(code, &treq, 25);