vcache-cleanup-20050529
[openafs.git] / src / afs / VNOPS / afs_vnop_dirops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 /*
11  * afs_vnop_dirops.c - make and remove directories
12  *
13  * Implements:
14  *
15  * afs_mkdir
16  * afs_rmdir
17  *
18  */
19
20 #include <afsconfig.h>
21 #include "afs/param.h"
22
23 RCSID
24     ("$Header$");
25
26 #include "afs/sysincludes.h"    /* Standard vendor system headers */
27 #include "afsincludes.h"        /* Afs-based standard headers */
28 #include "afs/afs_stats.h"      /* statistics */
29 #include "afs/afs_cbqueue.h"
30 #include "afs/nfsclient.h"
31 #include "afs/afs_osidnlc.h"
32
33 extern afs_rwlock_t afs_xvcache;
34 extern afs_rwlock_t afs_xcbhash;
35
36 /* don't set CDirty in here because RPC is called synchronously */
37
38 int
39 afs_mkdir(OSI_VC_DECL(adp), char *aname, struct vattr *attrs, 
40      register struct vcache **avcp, struct AFS_UCRED *acred)
41 {
42     struct vrequest treq;
43     register afs_int32 code;
44     register struct conn *tc;
45     struct VenusFid newFid;
46     register struct dcache *tdc;
47     afs_size_t offset, len;
48     register struct vcache *tvc;
49     struct AFSStoreStatus InStatus;
50     struct AFSFetchStatus OutFidStatus, OutDirStatus;
51     struct AFSCallBack CallBack;
52     struct AFSVolSync tsync;
53     afs_int32 now;
54     struct afs_fakestat_state fakestate;
55     XSTATS_DECLS;
56     OSI_VC_CONVERT(adp);
57
58     AFS_STATCNT(afs_mkdir);
59     afs_Trace2(afs_iclSetp, CM_TRACE_MKDIR, ICL_TYPE_POINTER, adp,
60                ICL_TYPE_STRING, aname);
61
62     if ((code = afs_InitReq(&treq, acred)))
63         goto done2;
64     afs_InitFakeStat(&fakestate);
65
66     if (strlen(aname) > AFSNAMEMAX) {
67         code = ENAMETOOLONG;
68         goto done;
69     }
70
71     if (!afs_ENameOK(aname)) {
72         code = EINVAL;
73         goto done;
74     }
75     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
76     if (code)
77         goto done;
78     code = afs_VerifyVCache(adp, &treq);
79     if (code)
80         goto done;
81
82     /** If the volume is read-only, return error without making an RPC to the
83       * fileserver
84       */
85     if (adp->states & CRO) {
86         code = EROFS;
87         goto done;
88     }
89
90     InStatus.Mask = AFS_SETMODTIME | AFS_SETMODE | AFS_SETGROUP;
91     InStatus.ClientModTime = osi_Time();
92     InStatus.UnixModeBits = attrs->va_mode & 0xffff;    /* only care about protection bits */
93     InStatus.Group = (afs_int32) acred->cr_gid;
94     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);
95     ObtainWriteLock(&adp->lock, 153);
96     do {
97         tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
98         if (tc) {
99             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_MAKEDIR);
100             now = osi_Time();
101             RX_AFS_GUNLOCK();
102             code =
103                 RXAFS_MakeDir(tc->id, (struct AFSFid *)&adp->fid.Fid, aname,
104                               &InStatus, (struct AFSFid *)&newFid.Fid,
105                               &OutFidStatus, &OutDirStatus, &CallBack,
106                               &tsync);
107             RX_AFS_GLOCK();
108             XSTATS_END_TIME;
109             CallBack.ExpirationTime += now;
110             /* DON'T forget to Set the callback value... */
111         } else
112             code = -1;
113     } while (afs_Analyze
114              (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_MAKEDIR,
115               SHARED_LOCK, NULL));
116
117     if (code) {
118         if (code < 0) {
119             ObtainWriteLock(&afs_xcbhash, 490);
120             afs_DequeueCallback(adp);
121             adp->states &= ~CStatd;
122             ReleaseWriteLock(&afs_xcbhash);
123             osi_dnlc_purgedp(adp);
124         }
125         ReleaseWriteLock(&adp->lock);
126         if (tdc)
127             afs_PutDCache(tdc);
128         goto done;
129     }
130     /* otherwise, we should see if we can make the change to the dir locally */
131     if (tdc)
132         ObtainWriteLock(&tdc->lock, 632);
133     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
134         /* we can do it locally */
135         code = afs_dir_Create(tdc, aname, &newFid.Fid);
136         if (code) {
137             ZapDCE(tdc);        /* surprise error -- use invalid value */
138             DZap(tdc);
139         }
140     }
141     if (tdc) {
142         ReleaseWriteLock(&tdc->lock);
143         afs_PutDCache(tdc);
144     }
145     adp->m.LinkCount = OutDirStatus.LinkCount;
146     newFid.Cell = adp->fid.Cell;
147     newFid.Fid.Volume = adp->fid.Fid.Volume;
148     ReleaseWriteLock(&adp->lock);
149     /* now we're done with parent dir, create the real dir's cache entry */
150     tvc = afs_GetVCache(&newFid, &treq, NULL, NULL);
151     if (tvc) {
152         code = 0;
153         *avcp = tvc;
154     } else
155         code = ENOENT;
156   done:
157     afs_PutFakeStat(&fakestate);
158     code = afs_CheckCode(code, &treq, 26);
159   done2:
160     return code;
161 }
162
163
164 int
165 /* don't set CDirty in here because RPC is called synchronously */
166 #if     defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
167 afs_rmdir(OSI_VC_DECL(adp), char *aname, struct vnode *cdirp, 
168           struct AFS_UCRED *acred)
169 #else
170 afs_rmdir(OSI_VC_DECL(adp), char *aname, struct AFS_UCRED *acred)
171 #endif
172 {
173     struct vrequest treq;
174     register struct dcache *tdc;
175     register struct vcache *tvc = NULL;
176     register afs_int32 code;
177     register struct conn *tc;
178     afs_size_t offset, len;
179     struct AFSFetchStatus OutDirStatus;
180     struct AFSVolSync tsync;
181     struct afs_fakestat_state fakestate;
182     XSTATS_DECLS;
183     OSI_VC_CONVERT(adp);
184
185     AFS_STATCNT(afs_rmdir);
186
187     afs_Trace2(afs_iclSetp, CM_TRACE_RMDIR, ICL_TYPE_POINTER, adp,
188                ICL_TYPE_STRING, aname);
189
190     if ((code = afs_InitReq(&treq, acred)))
191         goto done2;
192     afs_InitFakeStat(&fakestate);
193
194     if (strlen(aname) > AFSNAMEMAX) {
195         code = ENAMETOOLONG;
196         goto done;
197     }
198
199     code = afs_EvalFakeStat(&adp, &fakestate, &treq);
200     if (code)
201         goto done;
202
203     code = afs_VerifyVCache(adp, &treq);
204     if (code)
205         goto done;
206
207     /** If the volume is read-only, return error without making an RPC to the
208       * fileserver
209       */
210     if (adp->states & CRO) {
211         code = EROFS;
212         goto done;
213     }
214
215     tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &offset, &len, 1);  /* test for error below */
216     ObtainWriteLock(&adp->lock, 154);
217     if (tdc)
218         ObtainSharedLock(&tdc->lock, 633);
219     if (tdc && (adp->states & CForeign)) {
220         struct VenusFid unlinkFid;
221
222         unlinkFid.Fid.Vnode = 0;
223         code = afs_dir_Lookup(tdc, aname, &unlinkFid.Fid);
224         if (code == 0) {
225             afs_int32 cached = 0;
226
227             unlinkFid.Cell = adp->fid.Cell;
228             unlinkFid.Fid.Volume = adp->fid.Fid.Volume;
229             if (unlinkFid.Fid.Unique == 0) {
230                 tvc =
231                     afs_LookupVCache(&unlinkFid, &treq, &cached, adp, aname);
232             } else {
233                 ObtainReadLock(&afs_xvcache);
234                 tvc = afs_FindVCache(&unlinkFid, 0, 1 /* do xstats */ );
235                 ReleaseReadLock(&afs_xvcache);
236             }
237         }
238     }
239
240     do {
241         tc = afs_Conn(&adp->fid, &treq, SHARED_LOCK);
242         if (tc) {
243             XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_REMOVEDIR);
244             RX_AFS_GUNLOCK();
245             code =
246                 RXAFS_RemoveDir(tc->id, (struct AFSFid *)&adp->fid.Fid, aname,
247                                 &OutDirStatus, &tsync);
248             RX_AFS_GLOCK();
249             XSTATS_END_TIME;
250         } else
251             code = -1;
252     } while (afs_Analyze
253              (tc, code, &adp->fid, &treq, AFS_STATS_FS_RPCIDX_REMOVEDIR,
254               SHARED_LOCK, NULL));
255
256     if (code) {
257         if (tdc) {
258             ReleaseSharedLock(&tdc->lock);
259             afs_PutDCache(tdc);
260         }
261         if (code < 0) {
262             ObtainWriteLock(&afs_xcbhash, 491);
263             afs_DequeueCallback(adp);
264             adp->states &= ~CStatd;
265             ReleaseWriteLock(&afs_xcbhash);
266             osi_dnlc_purgedp(adp);
267         }
268         ReleaseWriteLock(&adp->lock);
269         goto done;
270     }
271     /* here if rpc worked; update the in-core link count */
272     adp->m.LinkCount = OutDirStatus.LinkCount;
273     if (tdc)
274         UpgradeSToWLock(&tdc->lock, 634);
275     if (afs_LocalHero(adp, tdc, &OutDirStatus, 1)) {
276         /* we can do it locally */
277         code = afs_dir_Delete(tdc, aname);
278         if (code) {
279             ZapDCE(tdc);        /* surprise error -- invalid value */
280             DZap(tdc);
281         }
282     }
283     if (tdc) {
284         ReleaseWriteLock(&tdc->lock);
285         afs_PutDCache(tdc);     /* drop ref count */
286     }
287
288
289     if (tvc)
290         osi_dnlc_purgedp(tvc);  /* get rid of any entries for this directory */
291     else
292         osi_dnlc_remove(adp, aname, 0);
293
294     if (tvc) {
295         ObtainWriteLock(&tvc->lock, 155);
296         tvc->states &= ~CUnique;        /* For the dfs xlator */
297         ReleaseWriteLock(&tvc->lock);
298         afs_PutVCache(tvc);
299     }
300     ReleaseWriteLock(&adp->lock);
301     /* don't worry about link count since dirs can not be hardlinked */
302     code = 0;
303
304   done:
305     afs_PutFakeStat(&fakestate);
306     code = afs_CheckCode(code, &treq, 27);
307   done2:
308     return code;
309 }