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