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"
20 #include "afs/sysincludes.h" /* Standard vendor system headers */
21 #include "afsincludes.h" /* Afs-based standard headers */
22 #include "afs/afs_stats.h" /* statistics */
23 #include "afs/afs_cbqueue.h"
24 #include "afs/nfsclient.h"
25 #include "afs/afs_osidnlc.h"
27 extern afs_rwlock_t afs_xcbhash
;
29 /* Note that we don't set CDirty here, this is OK because the link
30 * RPC is called synchronously. */
33 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
34 afs_link(OSI_VC_DECL(adp
), struct vcache
*avc
, char *aname
,
37 afs_link(struct vcache
*avc
, OSI_VC_DECL(adp
), char *aname
,
41 struct vrequest
*treq
= NULL
;
45 afs_size_t offset
, len
;
46 struct AFSFetchStatus
*OutFidStatus
, *OutDirStatus
;
47 struct AFSVolSync tsync
;
48 struct afs_fakestat_state vfakestate
, dfakestate
;
49 struct rx_connection
*rxconn
;
53 AFS_STATCNT(afs_link
);
54 afs_Trace3(afs_iclSetp
, CM_TRACE_LINK
, ICL_TYPE_POINTER
, adp
,
55 ICL_TYPE_POINTER
, avc
, ICL_TYPE_STRING
, aname
);
57 OutFidStatus
= osi_AllocSmallSpace(sizeof(struct AFSFetchStatus
));
58 OutDirStatus
= osi_AllocSmallSpace(sizeof(struct AFSFetchStatus
));
60 /* create a hard link; new entry is aname in dir adp */
61 if ((code
= afs_CreateReq(&treq
, acred
)))
64 afs_InitFakeStat(&vfakestate
);
65 afs_InitFakeStat(&dfakestate
);
69 code
= afs_EvalFakeStat(&avc
, &vfakestate
, treq
);
72 code
= afs_EvalFakeStat(&adp
, &dfakestate
, treq
);
76 if (avc
->f
.fid
.Cell
!= adp
->f
.fid
.Cell
77 || avc
->f
.fid
.Fid
.Volume
!= adp
->f
.fid
.Fid
.Volume
) {
81 if (strlen(aname
) > AFSNAMEMAX
) {
85 code
= afs_VerifyVCache(adp
, treq
);
89 /** If the volume is read-only, return error without making an RPC to the
92 if (adp
->f
.states
& CRO
) {
97 if (AFS_IS_DISCONNECTED
) {
102 tdc
= afs_GetDCache(adp
, (afs_size_t
) 0, treq
, &offset
, &len
, 1); /* test for error below */
103 ObtainWriteLock(&adp
->lock
, 145);
105 tc
= afs_Conn(&adp
->f
.fid
, treq
, SHARED_LOCK
, &rxconn
);
107 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_LINK
);
110 RXAFS_Link(rxconn
, (struct AFSFid
*)&adp
->f
.fid
.Fid
, aname
,
111 (struct AFSFid
*)&avc
->f
.fid
.Fid
, OutFidStatus
,
112 OutDirStatus
, &tsync
);
119 (tc
, rxconn
, code
, &adp
->f
.fid
, treq
, AFS_STATS_FS_RPCIDX_LINK
,
126 afs_StaleVCache(adp
);
128 ReleaseWriteLock(&adp
->lock
);
132 ObtainWriteLock(&tdc
->lock
, 635);
133 if (afs_LocalHero(adp
, tdc
, OutDirStatus
, 1)) {
134 /* we can do it locally */
135 ObtainWriteLock(&afs_xdcache
, 290);
136 code
= afs_dir_Create(tdc
, aname
, &avc
->f
.fid
.Fid
);
137 ReleaseWriteLock(&afs_xdcache
);
139 ZapDCE(tdc
); /* surprise error -- invalid value */
144 ReleaseWriteLock(&tdc
->lock
);
145 afs_PutDCache(tdc
); /* drop ref count */
147 ReleaseWriteLock(&adp
->lock
);
148 ObtainWriteLock(&avc
->lock
, 146); /* correct link count */
150 /* we could lock both dir and file; since we get the new fid
151 * status back, you'd think we could put it in the cache status
152 * entry at that point. Note that if we don't lock the file over
153 * the rpc call, we have no guarantee that the status info
154 * returned in ustat is the most recent to store in the file's
157 afs_StaleVCache(avc
); /* don't really know new link count */
158 ReleaseWriteLock(&avc
->lock
);
161 code
= afs_CheckCode(code
, treq
, 24);
162 afs_DestroyReq(treq
);
163 afs_PutFakeStat(&vfakestate
);
164 afs_PutFakeStat(&dfakestate
);
167 osi_FreeSmallSpace(OutFidStatus
);
168 osi_FreeSmallSpace(OutDirStatus
);