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