]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/devfs/devfs_vfsops.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_vfsops.c
1 /*
2 * Copyright (c) 2000-2002 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 devfs_make_node(makedev(0, 0), DEVFS_CHAR,
94 UID_ROOT, GID_WHEEL, 0622, "console");
95 devfs_make_node(makedev(2, 0), DEVFS_CHAR,
96 UID_ROOT, GID_WHEEL, 0666, "tty");
97 devfs_make_node(makedev(3, 0), DEVFS_CHAR,
98 UID_ROOT, GID_KMEM, 0640, "mem");
99 devfs_make_node(makedev(3, 1), DEVFS_CHAR,
100 UID_ROOT, GID_KMEM, 0640, "kmem");
101 devfs_make_node(makedev(3, 2), DEVFS_CHAR,
102 UID_ROOT, GID_WHEEL, 0666, "null");
103 devfs_make_node(makedev(3, 3), DEVFS_CHAR,
104 UID_ROOT, GID_WHEEL, 0666, "zero");
105 devfs_make_node(makedev(6, 0), DEVFS_CHAR,
106 UID_ROOT, GID_WHEEL, 0600, "klog");
107 return 0;
108 }
109
110 /*-
111 * mp - pointer to 'mount' structure
112 * path - addr in user space of mount point (ie /usr or whatever)
113 * data - addr in user space of mount params including the
114 * name of the block special file to treat as a filesystem.
115 * (NOT USED)
116 * ndp - namei data pointer (NOT USED)
117 * p - proc pointer
118 * devfs is special in that it doesn't require any device to be mounted..
119 * It makes up its data as it goes along.
120 * it must be mounted during single user.. until it is, only std{in/out/err}
121 * and the root filesystem are available.
122 */
123 /*proto*/
124 int
125 devfs_mount(struct mount *mp, char *path, caddr_t data,
126 struct nameidata *ndp, struct proc *p)
127 {
128 struct devfsmount *devfs_mp_p; /* devfs specific mount info */
129 int error;
130 size_t size;
131
132 /*-
133 * If they just want to update, we don't need to do anything.
134 */
135 if (mp->mnt_flag & MNT_UPDATE)
136 {
137 return 0;
138 }
139
140 /*-
141 * Well, it's not an update, it's a real mount request.
142 * Time to get dirty.
143 * HERE we should check to see if we are already mounted here.
144 */
145
146 MALLOC(devfs_mp_p, struct devfsmount *, sizeof(struct devfsmount),
147 M_DEVFSMNT, M_WAITOK);
148 if (devfs_mp_p == NULL)
149 return (ENOMEM);
150 bzero(devfs_mp_p,sizeof(*devfs_mp_p));
151 devfs_mp_p->mount = mp;
152
153 /*-
154 * Fill out some fields
155 */
156 mp->mnt_data = (qaddr_t)devfs_mp_p;
157 mp->mnt_stat.f_type = mp->mnt_vfc->vfc_typenum;
158 mp->mnt_stat.f_fsid.val[0] = (int32_t)(void *)devfs_mp_p;
159 mp->mnt_stat.f_fsid.val[1] = mp->mnt_stat.f_type;
160 mp->mnt_flag |= MNT_LOCAL;
161
162 DEVFS_LOCK(p);
163 error = dev_dup_plane(devfs_mp_p);
164 DEVFS_UNLOCK(p);
165 if (error) {
166 mp->mnt_data = (qaddr_t)0;
167 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT);
168 return (error);
169 }
170
171 /*-
172 * Copy in the name of the directory the filesystem
173 * is to be mounted on.
174 * And we clear the remainder of the character strings
175 * to be tidy.
176 */
177
178 if (!kernel_mount) {
179 copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
180 sizeof(mp->mnt_stat.f_mntonname)-1, &size);
181 bzero(mp->mnt_stat.f_mntonname + size,
182 sizeof(mp->mnt_stat.f_mntonname) - size);
183 }
184 bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
185 bcopy("devfs",mp->mnt_stat.f_mntfromname, 5);
186 DEVFS_INCR_MOUNTS();
187 (void)devfs_statfs(mp, &mp->mnt_stat, p);
188 return 0;
189 }
190
191
192 static int
193 devfs_start(struct mount *mp, int flags, struct proc *p)
194 {
195 return 0;
196 }
197
198 /*-
199 * Unmount the filesystem described by mp.
200 */
201 static int
202 devfs_unmount( struct mount *mp, int mntflags, struct proc *p)
203 {
204 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
205 int flags = 0;
206 int force = 0;
207 int error;
208
209 if (mntflags & MNT_FORCE) {
210 flags |= FORCECLOSE;
211 force = 1;
212 }
213 error = vflush(mp, NULLVP, flags);
214 if (error && !force)
215 return error;
216
217 DEVFS_LOCK(p);
218 devfs_free_plane(devfs_mp_p);
219 DEVFS_UNLOCK(p);
220 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT);
221 DEVFS_DECR_MOUNTS();
222 mp->mnt_data = (qaddr_t)0;
223 mp->mnt_flag &= ~MNT_LOCAL;
224
225 return 0;
226 }
227
228 /* return the address of the root vnode in *vpp */
229 static int
230 devfs_root(struct mount *mp, struct vnode **vpp)
231 {
232 struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data);
233 int error;
234
235 error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp,vpp,
236 current_proc());
237 return error;
238 }
239
240 static int
241 devfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
242 struct proc *p)
243 {
244 return EOPNOTSUPP;
245 }
246
247 static int
248 devfs_statfs( struct mount *mp, struct statfs *sbp, struct proc *p)
249 {
250 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data;
251
252 /*-
253 * Fill in the stat block.
254 */
255 sbp->f_type = mp->mnt_stat.f_type;
256 sbp->f_flags = 0; /* XXX */
257 sbp->f_bsize = 512;
258 sbp->f_iosize = 512;
259 sbp->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount)
260 + devfs_stats.nodes * sizeof(devnode_t)
261 + devfs_stats.entries * sizeof(devdirent_t)
262 + devfs_stats.stringspace
263 ) / sbp->f_bsize;
264 sbp->f_bfree = 0;
265 sbp->f_bavail = 0;
266 sbp->f_files = devfs_stats.nodes;
267 sbp->f_ffree = 0;
268 sbp->f_fsid.val[0] = (int32_t)(void *)devfs_mp_p;
269 sbp->f_fsid.val[1] = mp->mnt_stat.f_type;
270
271 /*-
272 * Copy the mounted on and mounted from names into
273 * the passed in stat block, if it is not the one
274 * in the mount structure.
275 */
276 if (sbp != &mp->mnt_stat) {
277 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
278 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
279 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
280 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
281 }
282 return 0;
283 }
284
285 static int
286 devfs_sync(struct mount *mp, int waitfor,struct ucred *cred,struct proc *p)
287 {
288 return (0);
289 }
290
291
292 static int
293 devfs_vget(struct mount *mp, void * ino,struct vnode **vpp)
294 {
295 return EOPNOTSUPP;
296 }
297
298 /*************************************************************
299 * The concept of exporting a kernel generated devfs is stupid
300 * So don't handle filehandles
301 */
302
303 static int
304 devfs_fhtovp (struct mount *mp, struct fid *fhp, struct mbuf *nam,
305 struct vnode **vpp, int *exflagsp, struct ucred **credanonp)
306 {
307 return (EINVAL);
308 }
309
310
311 static int
312 devfs_vptofh (struct vnode *vp, struct fid *fhp)
313 {
314 return (EINVAL);
315 }
316
317 static int
318 devfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
319 int *name;
320 u_int namelen;
321 void *oldp;
322 size_t *oldlenp;
323 void *newp;
324 size_t newlen;
325 struct proc *p;
326 {
327 return (EOPNOTSUPP);
328 }
329
330 #include <sys/namei.h>
331
332 /*
333 * Function: devfs_kernel_mount
334 * Purpose:
335 * Mount devfs at the given mount point from within the kernel.
336 */
337 int
338 devfs_kernel_mount(char * mntname)
339 {
340 struct mount *mp;
341 int error;
342 struct proc *procp;
343 struct nameidata nd;
344 struct vnode * vp;
345
346 if (devfs_vfsp == NULL) {
347 printf("devfs_kernel_mount: devfs_vfsp is NULL\n");
348 return (EINVAL);
349 }
350 procp = current_proc();
351
352 /*
353 * Get vnode to be covered
354 */
355 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
356 mntname, procp);
357 if ((error = namei(&nd))) {
358 printf("devfs_kernel_mount: failed to find directory '%s', %d",
359 mntname, error);
360 return (error);
361 }
362 vp = nd.ni_vp;
363 if ((error = vinvalbuf(vp, V_SAVE, procp->p_ucred, procp, 0, 0))) {
364 printf("devfs_kernel_mount: vinval failed: %d\n", error);
365 vput(vp);
366 return (error);
367 }
368 if (vp->v_type != VDIR) {
369 printf("devfs_kernel_mount: '%s' is not a directory\n", mntname);
370 vput(vp);
371 return (ENOTDIR);
372 }
373 if (vp->v_mountedhere != NULL) {
374 vput(vp);
375 return (EBUSY);
376 }
377
378 /*
379 * Allocate and initialize the filesystem.
380 */
381 MALLOC_ZONE(mp, struct mount *, (u_long)sizeof(struct mount),
382 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
410 if (mp->mnt_kern_flag & MNTK_IO_XINFO)
411 FREE(mp->mnt_xinfo_ptr, M_TEMP);
412 vfs_unbusy(mp, procp);
413
414 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
415 vput(vp);
416 return (error);
417 }
418 simple_lock(&mountlist_slock);
419 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
420 simple_unlock(&mountlist_slock);
421 VOP_UNLOCK(vp, 0, procp);
422 vfs_unbusy(mp, procp);
423 return (0);
424 }
425
426 struct vfsops devfs_vfsops = {
427 devfs_mount,
428 devfs_start,
429 devfs_unmount,
430 devfs_root,
431 devfs_quotactl,
432 devfs_statfs,
433 devfs_sync,
434 devfs_vget,
435 devfs_fhtovp,
436 devfs_vptofh,
437 devfs_init,
438 devfs_sysctl,
439 };