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