Fix a vcache refcount leak in afs_root() on all platforms.
[openafs.git] / src / afs / DARWIN / osi_vfsops.c
1 #include <afsconfig.h>
2 #include <afs/param.h>
3
4 RCSID("$Header$");
5
6 #include <afs/sysincludes.h>            /* Standard vendor system headers */
7 #include <afs/afsincludes.h>            /* Afs-based standard headers */
8 #include <afs/afs_stats.h>              /* statistics */
9 #include <sys/malloc.h>
10 #include <sys/namei.h>
11 #include <sys/conf.h>
12 #include <sys/syscall.h>
13
14 struct vcache *afs_globalVp = 0;
15 struct mount *afs_globalVFS = 0;
16
17 int
18 afs_quotactl()
19 {
20         return EOPNOTSUPP;
21 }
22
23 int
24 afs_fhtovp(mp, fhp, vpp)
25 struct mount *mp;
26 struct fid *fhp;
27 struct vnode **vpp;
28 {
29
30         return (EINVAL);
31 }
32
33 int
34 afs_vptofh(vp, fhp)
35 struct vnode *vp;
36 struct fid *fhp;
37 {
38
39         return (EINVAL);
40 }
41
42 int
43 afs_start(mp, flags, p)
44 struct mount *mp;
45 int flags;
46 struct proc *p;
47 {
48     return (0);                         /* nothing to do. ? */
49 }
50
51 int
52 afs_mount(mp, path, data, ndp, p)
53 register struct mount *mp;
54 char *path;
55 caddr_t data;
56 struct nameidata *ndp;
57 struct proc *p;
58 {
59     /* ndp contains the mounted-from device.  Just ignore it.
60        we also don't care about our proc struct. */
61     size_t size;
62     int error;
63
64     if (mp->mnt_flag & MNT_UPDATE)
65         return EINVAL;
66
67     AFS_GLOCK();
68     AFS_STATCNT(afs_mount);
69
70     if (afs_globalVFS) { /* Don't allow remounts. */
71         AFS_GUNLOCK();
72         return (EBUSY);
73     }
74
75     afs_globalVFS = mp;
76     mp->vfs_bsize = 8192;
77     vfs_getnewfsid(mp);
78     mp->mnt_stat.f_iosize=8192;
79     
80     (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN-1, &size);
81     memset(mp->mnt_stat.f_mntonname + size, 0, MNAMELEN - size);
82     memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN);
83     strcpy(mp->mnt_stat.f_mntfromname, "AFS");
84     /* null terminated string "AFS" will fit, just leave it be. */
85     strcpy(mp->mnt_stat.f_fstypename, "afs");
86     AFS_GUNLOCK();
87     (void) afs_statfs(mp, &mp->mnt_stat, p);
88     return 0;
89 }
90
91 int
92 afs_unmount(mp, flags, p)
93 struct mount *mp;
94 int flags;
95 struct proc *p;
96 {
97     
98     AFS_GLOCK();
99     AFS_STATCNT(afs_unmount);
100     afs_globalVFS = 0;
101     afs_shutdown();
102     AFS_GUNLOCK();
103
104     return 0;
105 }
106
107 int
108 afs_root(struct mount *mp,
109               struct vnode **vpp)
110 {
111     int error;
112     struct vrequest treq;
113     register struct vcache *tvp=0;
114     struct proc *p=current_proc();
115     struct ucred cr;
116
117     pcred_readlock(p);
118     cr=*p->p_cred->pc_ucred;
119     pcred_unlock(p);
120     AFS_GLOCK();
121     AFS_STATCNT(afs_root);
122     if (afs_globalVp && (afs_globalVp->states & CStatd)) {
123         tvp = afs_globalVp;
124         error=0;
125     } else {
126         if (afs_globalVp) {
127             afs_PutVCache(afs_globalVp);
128             afs_globalVp = NULL;
129         }
130
131         if (!(error = afs_InitReq(&treq, &cr)) &&
132             !(error = afs_CheckInit())) {
133             tvp = afs_GetVCache(&afs_rootFid, &treq, (afs_int32 *)0,
134                                 (struct vcache*)0, WRITE_LOCK);
135             /* we really want this to stay around */
136             if (tvp) {
137                 afs_globalVp = tvp;
138             } else
139                 error = ENOENT;
140         }
141     }
142     if (tvp) {
143         osi_vnhold(tvp,0);
144     AFS_GUNLOCK();
145         vn_lock(AFSTOV(tvp), LK_EXCLUSIVE | LK_RETRY, p);
146     AFS_GLOCK();
147         afs_globalVFS = mp;
148         *vpp = AFSTOV(tvp);
149         AFSTOV(tvp)->v_flag |= VROOT;
150     }
151
152     afs_Trace2(afs_iclSetp, CM_TRACE_VFSROOT, ICL_TYPE_POINTER, *vpp,
153                ICL_TYPE_INT32, error);
154     AFS_GUNLOCK();
155     return error;
156 }
157
158 int
159 afs_vget(mp, lfl, vp)
160 struct mount *mp;
161 struct vnode *vp;
162 int lfl;
163 {
164     int error;
165     printf("vget called. help!\n");
166     if (vp->v_usecount < 0) {
167         vprint("bad usecount", vp);
168         panic("afs_vget");
169     }
170     error = vget(vp, lfl, current_proc());
171     if (!error)
172         insmntque(vp, afs_globalVFS);   /* take off free list */
173     return error;
174 }
175
176 int afs_statfs(struct mount *mp, struct statfs *abp, struct proc *p)
177 {
178     AFS_GLOCK();
179     AFS_STATCNT(afs_statfs);
180
181 #if 0
182     abp->f_type = MOUNT_AFS;
183 #endif
184     abp->f_bsize = mp->vfs_bsize;
185     abp->f_iosize = mp->vfs_bsize;
186
187     /* Fake a high number below to satisfy programs that use the statfs call
188      * to make sure that there's enough space in the device partition before
189      * storing something there.
190      */
191     abp->f_blocks = abp->f_bfree = abp->f_bavail = abp->f_files =
192         abp->f_ffree  = 2000000;
193
194     abp->f_fsid.val[0] = mp->mnt_stat.f_fsid.val[0];
195     abp->f_fsid.val[1] = mp->mnt_stat.f_fsid.val[1];
196     if (abp != &mp->mnt_stat) {
197         abp->f_type = mp->mnt_vfc->vfc_typenum;
198         memcpy((caddr_t)&abp->f_mntonname[0], (caddr_t)mp->mnt_stat.f_mntonname, MNAMELEN);
199         memcpy((caddr_t)&abp->f_mntfromname[0], (caddr_t)mp->mnt_stat.f_mntfromname, MNAMELEN);
200     }
201
202     AFS_GUNLOCK();
203     return 0;
204 }
205
206 int afs_sync(mp, waitfor, cred, p) 
207 struct mount *mp;
208 int waitfor;
209 struct ucred *cred;
210 struct prioc *p;
211 {
212 return 0;
213 }
214
215 int afs_sysctl() {
216    return EOPNOTSUPP;
217 }
218
219
220 typedef (*PFI)();
221 extern int vfs_opv_numops; /* The total number of defined vnode operations */
222 extern struct vnodeopv_desc afs_vnodeop_opv_desc;
223 int afs_init(struct vfsconf *vfc) {
224         int j;
225         int (**opv_desc_vector)();
226         struct vnodeopv_entry_desc *opve_descp;
227  
228
229
230         MALLOC(afs_vnodeop_p, PFI *, vfs_opv_numops*sizeof(PFI), M_TEMP, M_WAITOK);
231
232         memset(afs_vnodeop_p, 0, vfs_opv_numops*sizeof(PFI));
233
234         opv_desc_vector = afs_vnodeop_p;
235         for (j=0; afs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
236             opve_descp = &(afs_vnodeop_opv_desc.opv_desc_ops[j]);
237
238             /*
239              * Sanity check:  is this operation listed
240              * in the list of operations?  We check this
241              * by seeing if its offest is zero.  Since
242              * the default routine should always be listed
243              * first, it should be the only one with a zero
244              * offset.  Any other operation with a zero
245              * offset is probably not listed in
246              * vfs_op_descs, and so is probably an error.
247              *
248              * A panic here means the layer programmer
249              * has committed the all-too common bug
250              * of adding a new operation to the layer's
251              * list of vnode operations but
252              * not adding the operation to the system-wide
253              * list of supported operations.
254              */
255             if (opve_descp->opve_op->vdesc_offset == 0 &&
256                 opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
257                 printf("afs_init: operation %s not listed in %s.\n",
258                        opve_descp->opve_op->vdesc_name,
259                        "vfs_op_descs");
260                panic ("load_afs: bad operation");
261                 }
262             /*
263              * Fill in this entry.
264              */
265             opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
266                 opve_descp->opve_impl;
267             }
268
269         /*
270          * Finally, go back and replace unfilled routines
271          * with their default.  (Sigh, an O(n^3) algorithm.  I
272                                  * could make it better, but that'd be work, and n is small.)
273          */
274
275         /*
276          * Force every operations vector to have a default routine.
277          */
278         opv_desc_vector = afs_vnodeop_p;
279         if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
280             panic("afs_init: operation vector without default routine.");
281             }
282         for (j = 0;j<vfs_opv_numops; j++)
283             if (opv_desc_vector[j] == NULL)
284                 opv_desc_vector[j] =
285                     opv_desc_vector[VOFFSET(vop_default)];
286 }
287
288 struct vfsops afs_vfsops = {
289   afs_mount,
290   afs_start,
291   afs_unmount,
292   afs_root,
293   afs_quotactl,
294   afs_statfs,
295   afs_sync,
296   afs_vget,
297   afs_fhtovp,
298   afs_vptofh,
299   afs_init,
300   afs_sysctl
301 };