]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/devfs/devfs_vfsops.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_vfsops.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*-
26 * Copyright 1997,1998 Julian Elischer. All rights reserved.
27 * julian@freebsd.org
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions are
31 * met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright notice,
35 * this list of conditions and the following disclaimer in the documentation
36 * and/or other materials provided with the distribution.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
39 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
40 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
42 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
44 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
45 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 * devfs_vfsops.c
51 *
52 */
53 /*
54 * HISTORY
55 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999
56 * - modified devfs_statfs() to use devfs_stats to calculate the
57 * amount of memory used by devfs
58 */
59
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/kernel.h>
64 #include <sys/vnode.h>
65 #include <sys/proc.h>
66 #include <sys/mount.h>
67 #include <sys/malloc.h>
68
69 #include "devfs.h"
70 #include "devfsdefs.h"
71
72 static int devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p);
73
74 static struct vfsconf * devfs_vfsp = 0;
75 static int kernel_mount = 0;
76
77
78 /*-
79 * Called from the generic VFS startups.
80 * This is the second stage of DEVFS initialisation.
81 * The probed devices have already been loaded and the
82 * basic structure of the DEVFS created.
83 * We take the oportunity to mount the hidden DEVFS layer, so that
84 * devices from devfs get sync'd.
85 */
86 static int
87 devfs_init(struct vfsconf *vfsp)
88 {
89 devfs_vfsp = vfsp; /* remember this for devfs_kernel_mount below */
90
91 if (devfs_sinit())
92 return (EOPNOTSUPP);
93 printf("devfs enabled\n");
94 devfs_make_node(makedev(0, 0), DEVFS_CHAR,
95 UID_ROOT, GID_WHEEL, 0622, "console");
96 devfs_make_node(makedev(2, 0), DEVFS_CHAR,
97 UID_ROOT, GID_WHEEL, 0666, "tty");
98 devfs_make_node(makedev(3, 0), DEVFS_CHAR,
99 UID_ROOT, GID_KMEM, 0640, "mem");
100 devfs_make_node(makedev(3, 1), DEVFS_CHAR,
101 UID_ROOT, GID_KMEM, 0640, "kmem");
102 devfs_make_node(makedev(3, 2), DEVFS_CHAR,
103 UID_ROOT, GID_WHEEL, 0666, "null");
104 devfs_make_node(makedev(3, 3), DEVFS_CHAR,
105 UID_ROOT, GID_WHEEL, 0666, "zero");
106 devfs_make_node(makedev(6, 0), DEVFS_CHAR,
107 UID_ROOT, GID_WHEEL, 0600, "klog");
108 return 0;
109 }
110
111 /*-
112 * mp - pointer to 'mount' structure
113 * path - addr in user space of mount point (ie /usr or whatever)
114 * data - addr in user space of mount params including the
115 * name of the block special file to treat as a filesystem.
116 * (NOT USED)
117 * ndp - namei data pointer (NOT USED)
118 * p - proc pointer
119 * devfs is special in that it doesn't require any device to be mounted..
120 * It makes up its data as it goes along.
121 * it must be mounted during single user.. until it is, only std{in/out/err}
122 * and the root filesystem are available.
123 */
124 /*proto*/
125 int
126 devfs_mount(struct mount *mp, char *path, caddr_t data,
127 struct nameidata *ndp, struct proc *p)
128 {
129 struct devfsmount *devfs_mp_p; /* devfs specific mount info */
130 int error;
131 size_t size;
132
133 /*-
134 * If they just want to update, we don't need to do anything.
135 */
136 if (mp->mnt_flag & MNT_UPDATE)
137 {
138 return 0;
139 }
140
141 /*-
142 * Well, it's not an update, it's a real mount request.
143 * Time to get dirty.
144 * HERE we should check to see if we are already mounted here.
145 */
146
147 MALLOC(devfs_mp_p, struct devfsmount *, sizeof(struct devfsmount),
148 M_DEVFSMNT, M_WAITOK);
149 if (devfs_mp_p == NULL)
150 return (ENOMEM);
151 bzero(devfs_mp_p,sizeof(*devfs_mp_p));
152 devfs_mp_p->mount = mp;
153
154 /*-
155 * Fill out some fields
156 */
157 mp->mnt_data = (qaddr_t)devfs_mp_p;
158 mp->mnt_stat.f_type = mp->mnt_vfc->vfc_typenum;
159 mp->mnt_stat.f_fsid.val[0] = (int32_t)(void *)devfs_mp_p;
160 mp->mnt_stat.f_fsid.val[1] = mp->mnt_stat.f_type;
161 mp->mnt_flag |= MNT_LOCAL;
162
163 DEVFS_LOCK(p);
164 error = dev_dup_plane(devfs_mp_p);
165 DEVFS_UNLOCK(p);
166 if (error) {
167 mp->mnt_data = (qaddr_t)0;
168 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT);
169 return (error);
170 }
171
172 /*-
173 * Copy in the name of the directory the filesystem
174 * is to be mounted on.
175 * And we clear the remainder of the character strings
176 * to be tidy.
177 */
178
179 if (!kernel_mount) {
180 copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
181 sizeof(mp->mnt_stat.f_mntonname)-1, &size);
182 bzero(mp->mnt_stat.f_mntonname + size,
183 sizeof(mp->mnt_stat.f_mntonname) - size);
184 }
185 bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
186 bcopy("devfs",mp->mnt_stat.f_mntfromname, 5);
187 DEVFS_INCR_MOUNTS();
188 (void)devfs_statfs(mp, &mp->mnt_stat, p);
189 return 0;
190 }
191
192
193 static int
194 devfs_start(struct mount *mp, int flags, struct proc *p)
195 {
196 return 0;
197 }
198
199 /*-
200 * Unmount the filesystem described by mp.
201 */
202 static int
203 devfs_unmount( struct mount *mp, int mntflags, struct proc *p)
204 {
205 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
206 int flags = 0;
207 int force = 0;
208 int error;
209
210 if (mntflags & MNT_FORCE) {
211 flags |= FORCECLOSE;
212 force = 1;
213 }
214 error = vflush(mp, NULLVP, flags);
215 if (error && !force)
216 return error;
217
218 DEVFS_LOCK(p);
219 devfs_free_plane(devfs_mp_p);
220 DEVFS_UNLOCK(p);
221 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT);
222 DEVFS_DECR_MOUNTS();
223 mp->mnt_data = (qaddr_t)0;
224 mp->mnt_flag &= ~MNT_LOCAL;
225
226 return 0;
227 }
228
229 /* return the address of the root vnode in *vpp */
230 static int
231 devfs_root(struct mount *mp, struct vnode **vpp)
232 {
233 struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data);
234 int error;
235
236 error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp,vpp,
237 current_proc());
238 return error;
239 }
240
241 static int
242 devfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
243 struct proc *p)
244 {
245 return EOPNOTSUPP;
246 }
247
248 static int
249 devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p)
250 {
251 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
252
253 /*-
254 * Fill in the stat block.
255 */
256 sbp->f_type = mp->mnt_stat.f_type;
257 sbp->f_flags = 0; /* XXX */
258 sbp->f_bsize = 512;
259 sbp->f_iosize = 512;
260 sbp->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount)
261 + devfs_stats.nodes * sizeof(devnode_t)
262 + devfs_stats.entries * sizeof(devdirent_t)
263 + devfs_stats.stringspace
264 ) / sbp->f_bsize;
265 sbp->f_bfree = 0;
266 sbp->f_bavail = 0;
267 sbp->f_files = devfs_stats.nodes;
268 sbp->f_ffree = 0;
269 sbp->f_fsid.val[0] = (int32_t)(void *)devfs_mp_p;
270 sbp->f_fsid.val[1] = mp->mnt_stat.f_type;
271
272 /*-
273 * Copy the mounted on and mounted from names into
274 * the passed in stat block, if it is not the one
275 * in the mount structure.
276 */
277 if (sbp != &mp->mnt_stat) {
278 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
279 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
280 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
281 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
282 }
283 return 0;
284 }
285
286 static int
287 devfs_sync(struct mount *mp, int waitfor,struct ucred *cred,struct proc *p)
288 {
289 return (0);
290 }
291
292
293 static int
294 devfs_vget(struct mount *mp, void * ino,struct vnode **vpp)
295 {
296 return EOPNOTSUPP;
297 }
298
299 /*************************************************************
300 * The concept of exporting a kernel generated devfs is stupid
301 * So don't handle filehandles
302 */
303
304 static int
305 devfs_fhtovp (struct mount *mp, struct fid *fhp, struct mbuf *nam,
306 struct vnode **vpp, int *exflagsp, struct ucred **credanonp)
307 {
308 return (EINVAL);
309 }
310
311
312 static int
313 devfs_vptofh (struct vnode *vp, struct fid *fhp)
314 {
315 return (EINVAL);
316 }
317
318 static int
319 devfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
320 int *name;
321 u_int namelen;
322 void *oldp;
323 size_t *oldlenp;
324 void *newp;
325 size_t newlen;
326 struct proc *p;
327 {
328 return (EOPNOTSUPP);
329 }
330
331 #include <sys/namei.h>
332
333 /*
334 * Function: devfs_kernel_mount
335 * Purpose:
336 * Mount devfs at the given mount point from within the kernel.
337 */
338 int
339 devfs_kernel_mount(char * mntname)
340 {
341 struct mount *mp;
342 int error;
343 struct proc *procp;
344 struct nameidata nd;
345 struct vnode * vp;
346
347 if (devfs_vfsp == NULL) {
348 printf("devfs_kernel_mount: devfs_vfsp is NULL\n");
349 return (EINVAL);
350 }
351 procp = current_proc();
352
353 /*
354 * Get vnode to be covered
355 */
356 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
357 mntname, procp);
358 if ((error = namei(&nd))) {
359 printf("devfs_kernel_mount: failed to find directory '%s', %d",
360 mntname, error);
361 return (error);
362 }
363 vp = nd.ni_vp;
364 if ((error = vinvalbuf(vp, V_SAVE, procp->p_ucred, procp, 0, 0))) {
365 printf("devfs_kernel_mount: vinval failed: %d\n", error);
366 vput(vp);
367 return (error);
368 }
369 if (vp->v_type != VDIR) {
370 printf("devfs_kernel_mount: '%s' is not a directory\n", mntname);
371 vput(vp);
372 return (ENOTDIR);
373 }
374 if (vp->v_mountedhere != NULL) {
375 vput(vp);
376 return (EBUSY);
377 }
378
379 /*
380 * Allocate and initialize the filesystem.
381 */
382 mp = _MALLOC_ZONE((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
383 bzero((char *)mp, (u_long)sizeof(struct mount));
384
385 /* Initialize the default IO constraints */
386 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
387 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
388
389 lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
390 (void)vfs_busy(mp, LK_NOWAIT, 0, procp);
391 LIST_INIT(&mp->mnt_vnodelist);
392 mp->mnt_op = devfs_vfsp->vfc_vfsops;
393 mp->mnt_vfc = devfs_vfsp;
394 devfs_vfsp->vfc_refcount++;
395 mp->mnt_flag = 0;
396 mp->mnt_flag |= devfs_vfsp->vfc_flags & MNT_VISFLAGMASK;
397 strncpy(mp->mnt_stat.f_fstypename, devfs_vfsp->vfc_name, MFSNAMELEN);
398 vp->v_mountedhere = mp;
399 mp->mnt_vnodecovered = vp;
400 mp->mnt_stat.f_owner = procp->p_ucred->cr_uid;
401 (void) copystr(mntname, mp->mnt_stat.f_mntonname, MNAMELEN - 1, 0);
402
403 kernel_mount = 1;
404 error = devfs_mount(mp, mntname, NULL, NULL, procp);
405 kernel_mount = 0;
406 if (error) {
407 printf("devfs_kernel_mount: mount %s failed: %d", mntname, error);
408 mp->mnt_vfc->vfc_refcount--;
409 vfs_unbusy(mp, procp);
410 _FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
411 vput(vp);
412 return (error);
413 }
414 printf("devfs on %s\n", mntname);
415 simple_lock(&mountlist_slock);
416 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
417 simple_unlock(&mountlist_slock);
418 VOP_UNLOCK(vp, 0, procp);
419 vfs_unbusy(mp, procp);
420 return (0);
421 }
422
423 struct vfsops devfs_vfsops = {
424 devfs_mount,
425 devfs_start,
426 devfs_unmount,
427 devfs_root,
428 devfs_quotactl,
429 devfs_statfs,
430 devfs_sync,
431 devfs_vget,
432 devfs_fhtovp,
433 devfs_vptofh,
434 devfs_init,
435 devfs_sysctl,
436 };