]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/devfs/devfs_vfsops.c
xnu-344.21.73.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_vfsops.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
A
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d7e50217
A
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.
1c79356b
A
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
72static int devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p);
73
74static struct vfsconf * devfs_vfsp = 0;
75static 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 */
86static int
87devfs_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*/
125int
126devfs_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
193static int
194devfs_start(struct mount *mp, int flags, struct proc *p)
195{
196 return 0;
197}
198
199/*-
200 * Unmount the filesystem described by mp.
201 */
202static int
203devfs_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;
9bccf70c 207 int force = 0;
1c79356b
A
208 int error;
209
210 if (mntflags & MNT_FORCE) {
211 flags |= FORCECLOSE;
9bccf70c 212 force = 1;
1c79356b
A
213 }
214 error = vflush(mp, NULLVP, flags);
9bccf70c 215 if (error && !force)
1c79356b
A
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 */
230static int
231devfs_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
241static int
242devfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
243 struct proc *p)
244{
245 return EOPNOTSUPP;
246}
247
248static int
249devfs_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
286static int
287devfs_sync(struct mount *mp, int waitfor,struct ucred *cred,struct proc *p)
288{
289 return (0);
290}
291
292
293static int
294devfs_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
304static int
305devfs_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
312static int
313devfs_vptofh (struct vnode *vp, struct fid *fhp)
314{
315 return (EINVAL);
316}
317
318static int
319devfs_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 */
338int
339devfs_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));
0b4e3aa0
A
384
385 /* Initialize the default IO constraints */
386 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
387 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
388
1c79356b
A
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
423struct 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};