]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/volfs/volfs_vfsops.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / miscfs / volfs / volfs_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 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
26 /*
27 * Change History:
28 *
29 * 29-May-1998 Pat Dirks Changed to cache pointer to root vnode until unmount.
30 *
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/namei.h>
36 #include <sys/proc.h>
37 #include <sys/kernel.h>
38 #include <mach/machine/vm_types.h>
39 #include <sys/vnode.h>
40 #include <sys/socket.h>
41 #include <sys/mount.h>
42 #include <sys/buf.h>
43 #include <sys/mbuf.h>
44 #include <sys/file.h>
45 #include <sys/disk.h>
46 #include <sys/ioctl.h>
47 #include <sys/errno.h>
48 #include <sys/malloc.h>
49 #include <dev/ldd.h>
50
51 #include <miscfs/specfs/specdev.h>
52 #include "volfs.h"
53
54 struct vfsops volfs_vfsops = {
55 volfs_mount,
56 volfs_start,
57 volfs_unmount,
58 volfs_root,
59 volfs_quotactl,
60 volfs_statfs,
61 volfs_sync,
62 volfs_vget,
63 volfs_fhtovp,
64 volfs_vptofh,
65 volfs_init,
66 volfs_sysctl
67 };
68
69 static char volfs_fs_name[MFSNAMELEN] = "volfs";
70 extern struct vnodeopv_desc volfs_vnodeop_opv_desc;
71
72 /* The following refer to kernel global variables used in the loading/initialization: */
73 extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
74 extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
75 extern int vfs_opv_numops; /* The total number of defined vnode operations */
76 extern int kdp_flag;
77
78 void
79 volfs_load(int loadArgument) {
80 struct vfsconf *vfsconflistentry;
81 int entriesRemaining;
82 struct vfsconf *newvfsconf = NULL;
83 struct vfsconf *lastentry = NULL;
84 int j;
85 int (***opv_desc_vector_p)();
86 int (**opv_desc_vector)();
87 struct vnodeopv_entry_desc *opve_descp;
88
89 #pragma unused(loadArgument)
90
91 /*
92 * This routine is responsible for all the initialization that would
93 * ordinarily be done as part of the system startup; it calls volfs_init
94 * to do the initialization that is strictly volfs-specific.
95 */
96
97 /*
98 prevvfsconf is supposed to be the entry preceding the new entry.
99 To make sure we can always get hooked in SOMEWHERE in the list,
100 start it out at the first entry of the list. This assumes the
101 first entry in the list will be non-empty and not volfs.
102
103 This becomes irrelevant when volfs is compiled into the list.
104 */
105 DBG_VOP(("load_volfs: Scanning vfsconf list...\n"));
106 vfsconflistentry = vfsconf;
107 for (entriesRemaining = maxvfsslots; entriesRemaining > 0; --entriesRemaining) {
108 if (vfsconflistentry->vfc_vfsops != NULL) {
109 /*
110 * Check to see if we're reloading a new version of volfs during debugging
111 * and overwrite the previously assigned entry if we find one:
112 */
113 if (strcmp(vfsconflistentry->vfc_name, volfs_fs_name) == 0) {
114 newvfsconf = vfsconflistentry;
115 break;
116 } else {
117 lastentry = vfsconflistentry;
118 };
119 } else {
120 /*
121 * This is at least a POSSIBLE place to insert the new entry...
122 */
123 newvfsconf = vfsconflistentry;
124 };
125 ++vfsconflistentry;
126 };
127
128 if (newvfsconf) {
129 DBG_VOP(("load_volfs: filling in vfsconf entry at 0x%08lX; lastentry = 0x%08lX.\n", (long)newvfsconf, (long)lastentry));
130 newvfsconf->vfc_vfsops = &volfs_vfsops;
131 strncpy(&newvfsconf->vfc_name[0], "volfs", MFSNAMELEN);
132 newvfsconf->vfc_typenum = maxvfsconf++;
133 newvfsconf->vfc_refcount = 0;
134 newvfsconf->vfc_flags = 0;
135 newvfsconf->vfc_mountroot = NULL; /* Can't mount root of file system [yet] */
136
137 /* Hook into the list: */
138 newvfsconf->vfc_next = NULL;
139 if (lastentry) {
140 newvfsconf->vfc_next = lastentry->vfc_next;
141 lastentry->vfc_next = newvfsconf;
142 };
143
144 /* Based on vfs_op_init and ... */
145 opv_desc_vector_p = volfs_vnodeop_opv_desc.opv_desc_vector_p;
146
147 DBG_VOP(("load_volfs: Allocating and initializing VNode ops vector...\n"));
148
149 /*
150 * Allocate and init the vector.
151 * Also handle backwards compatibility.
152 */
153 MALLOC(*opv_desc_vector_p, PFI *, vfs_opv_numops*sizeof(PFI), M_TEMP, M_WAITOK);
154
155 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
156
157 opv_desc_vector = *opv_desc_vector_p;
158 for (j=0; volfs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
159 opve_descp = &(volfs_vnodeop_opv_desc.opv_desc_ops[j]);
160
161 /*
162 * Sanity check: is this operation listed
163 * in the list of operations? We check this
164 * by seeing if its offest is zero. Since
165 * the default routine should always be listed
166 * first, it should be the only one with a zero
167 * offset. Any other operation with a zero
168 * offset is probably not listed in
169 * vfs_op_descs, and so is probably an error.
170 *
171 * A panic here means the layer programmer
172 * has committed the all-too common bug
173 * of adding a new operation to the layer's
174 * list of vnode operations but
175 * not adding the operation to the system-wide
176 * list of supported operations.
177 */
178 if (opve_descp->opve_op->vdesc_offset == 0 &&
179 opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
180 DBG_VOP(("load_volfs: operation %s not listed in %s.\n",
181 opve_descp->opve_op->vdesc_name,
182 "vfs_op_descs"));
183 panic ("load_volfs: bad operation");
184 }
185 /*
186 * Fill in this entry.
187 */
188 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
189 opve_descp->opve_impl;
190 }
191
192 /*
193 * Finally, go back and replace unfilled routines
194 * with their default. (Sigh, an O(n^3) algorithm. I
195 * could make it better, but that'd be work, and n is small.)
196 */
197 opv_desc_vector_p = volfs_vnodeop_opv_desc.opv_desc_vector_p;
198
199 /*
200 * Force every operations vector to have a default routine.
201 */
202 opv_desc_vector = *opv_desc_vector_p;
203 if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
204 panic("load_vp;fs: operation vector without default routine.");
205 }
206 for (j = 0;j<vfs_opv_numops; j++)
207 if (opv_desc_vector[j] == NULL)
208 opv_desc_vector[j] =
209 opv_desc_vector[VOFFSET(vop_default)];
210
211 DBG_VOP(("load_volfs: calling volfs_init()...\n"));
212 volfs_init(newvfsconf);
213 };
214 }
215
216 /*
217 * VFS Operations.
218 *
219 * mount system call
220 */
221 int
222 volfs_mount(mp, path, data, ndp, p)
223 register struct mount *mp;
224 char *path;
225 caddr_t data;
226 struct nameidata *ndp;
227 struct proc *p;
228 {
229 struct volfs_mntdata *priv_mnt_data;
230 struct vnode *root_vp;
231 struct volfs_vndata *priv_vn_data;
232 int error;
233 size_t size;
234
235 DBG_VOP(("volfs_mount called\n"));
236 MALLOC(priv_mnt_data, struct volfs_mntdata *, sizeof(struct volfs_mntdata),
237 M_VOLFSMNT, M_WAITOK);
238 DBG_VOP(("MALLOC succeeded\n"));
239 LIST_INIT(&priv_mnt_data->volfs_fsvnodes);
240 DBG_VOP(("LIST_INIT succeeded\n"));
241
242 mp->mnt_data = (void *)priv_mnt_data;
243 strcpy(mp->mnt_stat.f_fstypename, "volfs");
244 (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
245 strcpy(mp->mnt_stat.f_mntfromname, "<volfs>");
246
247 /* Set up the root vnode for fast reference in the future.
248 Note that the root is maintained unlocked but with a pos. ref count until unmount. */
249
250 MALLOC(priv_vn_data, struct volfs_vndata *, sizeof(struct volfs_vndata), M_VOLFSNODE, M_WAITOK);
251 error = getnewvnode(VT_VOLFS, mp, volfs_vnodeop_p, &root_vp);
252 if (error != 0)
253 {
254 FREE(priv_mnt_data, M_VOLFSMNT);
255 FREE(priv_vn_data, M_VOLFSNODE);
256 DBG_VOP(("getnewvnode failed with error code %d\n", error));
257 return(error);
258 }
259 root_vp->v_type = VDIR;
260 root_vp->v_flag |= VROOT;
261 lockinit(&priv_vn_data->lock, PINOD, "volfsnode", 0, 0);
262 priv_vn_data->vnode_type = VOLFS_ROOT;
263 priv_vn_data->nodeID = 0;
264 priv_vn_data->fs_mount = mp;
265 root_vp->v_data = priv_vn_data;
266
267 priv_mnt_data->volfs_rootvp = root_vp;
268
269 mp->mnt_flag &= ~MNT_RDONLY;
270
271 return (0);
272 }
273
274 int
275 volfs_start(mp, flags, p)
276 struct mount * mp;
277 int flags;
278 struct proc * p;
279 {
280 DBG_VOP(("volfs_start called\n"));
281 return (0);
282 }
283
284 /*
285 * Return the root of a filesystem. For volfs the root vnode is a directory
286 * containing the list of all filesystems volfs can work with.
287 */
288 int
289 volfs_root(mp, vpp)
290 struct mount *mp;
291 struct vnode **vpp;
292 {
293 struct volfs_mntdata *priv_data;
294 // struct volfs_vndata *priv_vn_data;
295 // int error;
296
297 DBG_VOP(("volfs_root called\n"));
298 priv_data = (struct volfs_mntdata *)mp->mnt_data;
299
300 if (priv_data->volfs_rootvp) {
301 vref(priv_data->volfs_rootvp);
302 VOP_LOCK(priv_data->volfs_rootvp, LK_EXCLUSIVE, current_proc());
303 *vpp = priv_data->volfs_rootvp;
304 } else {
305 panic("volfs: root vnode missing!");
306 };
307
308 DBG_VOP(("volfs_root returned with "));
309 DBG_VOP_PRINT_VNODE_INFO(*vpp);DBG_VOP(("\n"));
310
311 return(0);
312 }
313
314 int
315 volfs_quotactl(mp, cmds, uid, arg, p)
316 struct mount *mp;
317 int cmds;
318 uid_t uid;
319 caddr_t arg;
320 struct proc * p;
321 {
322 DBG_VOP(("volfs_quotactl called\n"));
323 return (0);
324 }
325
326 /*
327 * unmount system call
328 */
329 int
330 volfs_unmount(mp, mntflags, p)
331 struct mount *mp;
332 int mntflags;
333 struct proc *p;
334 {
335 struct volfs_mntdata *priv_data;
336 struct vnode *root_vp;
337 int retval;
338
339 DBG_VOP(("volfs_unmount called\n"));
340 priv_data = (struct volfs_mntdata *)mp->mnt_data;
341
342 root_vp = priv_data->volfs_rootvp;
343 retval = vflush(mp, root_vp, 0);
344 if (retval) goto Err_Exit;
345
346 /* Free the root vnode.
347 Note that there's no need to vget() or vref() it before locking it here:
348 the ref. count has been maintained at +1 ever since mount time. */
349 if (root_vp) {
350 retval = vn_lock(root_vp, LK_EXCLUSIVE, p);
351 if (retval) goto Err_Exit;
352 if (root_vp->v_usecount > 1) {
353 DBG_VOP(("VOLFS ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, priv_data->volfs_rootvp->v_usecount));
354 VOP_UNLOCK(root_vp, 0, p);
355 retval = EBUSY;
356 goto Err_Exit;
357 };
358
359 priv_data->volfs_rootvp = NULL;
360 vput(root_vp); /* This drops volfs's own refcount */
361 vgone(root_vp);
362 };
363
364 /* All vnodes should be gone, and no errors, clean up the last */
365 /* XXX DBG_ASSERT(mp->mnt_vnodelist.lh_first == NULL); */
366 /* XXX DBG_ASSERT(retval == 0); */
367
368 mp->mnt_data = NULL;
369 FREE(priv_data, M_VOLFSMNT);
370
371 Err_Exit:
372
373 return(retval);
374 }
375
376 /*
377 * Get file system statistics.
378 */
379 int
380 volfs_statfs(mp, sbp, p)
381 struct mount *mp;
382 register struct statfs *sbp;
383 struct proc *p;
384 {
385 DBG_VOP(("volfs_statfs called\n"));
386 sbp->f_bsize = 512;
387 sbp->f_iosize = 512;
388 sbp->f_blocks = 1024; // lies, darn lies and virtual file systems
389 sbp->f_bfree = 0; // Nope, can't write here!
390 sbp->f_bavail = 0;
391 sbp->f_files = 0; // Hmmm...maybe later
392 sbp->f_ffree = 0;
393 return (0);
394 }
395
396 /*
397 * volfs doesn't have any data and you can't write into any of the volfs
398 * structures, so don't do anything
399 */
400 int
401 volfs_sync(mp, waitfor, cred, p)
402 struct mount *mp;
403 int waitfor;
404 struct ucred *cred;
405 struct proc *p;
406 {
407 // DBG_VOP(("volfs_sync called\n"));
408
409 /* Release a few entries from the permissions cache to keep them from getting stale.
410 * Since sync is called at least every 30 seconds or so, releasing 1/20 of the cache
411 * every time through should free all entries in no less than 10 minutes, which should
412 * be adequate to prevent pid-wrapping from mis-associating PLC entries:
413 */
414 volfs_PLC_reclaim_entries(MAXPLCENTRIES / 20);
415
416 return 0;
417 }
418 /*
419 * Look up a FFS dinode number to find its incore vnode, otherwise read it
420 * in from disk. If it is in core, wait for the lock bit to clear, then
421 * return the inode locked. Detection and handling of mount points must be
422 * done by the calling routine.
423 */
424 int
425 volfs_vget(mp, ino, vpp)
426 struct mount *mp;
427 void *ino;
428 struct vnode **vpp;
429 {
430 // DBG_VOP(("volfs_vget called\n"));
431 return(0);
432 }
433 /*
434 * File handle to vnode
435 *
436 * Have to be really careful about stale file handles:
437 * - check that the inode number is valid
438 * - call ffs_vget() to get the locked inode
439 * - check for an unallocated inode (i_mode == 0)
440 * - check that the given client host has export rights and return
441 * those rights via. exflagsp and credanonp
442 */
443 int
444 volfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
445 register struct mount *mp;
446 struct fid *fhp;
447 struct mbuf *nam;
448 struct vnode **vpp;
449 int *exflagsp;
450 struct ucred **credanonp;
451 {
452 DBG_VOP(("volfs_fhtovp called\n"));
453 return(0);
454 }
455 /*
456 * Vnode pointer to File handle
457 */
458 /* ARGSUSED */
459 int
460 volfs_vptofh(vp, fhp)
461 struct vnode *vp;
462 struct fid *fhp;
463 {
464 DBG_VOP(("volfs_vptofh called\n"));
465 return(0);
466 }
467 /*
468 * Initialize the filesystem
469 */
470 int
471 volfs_init(vfsp)
472 struct vfsconf *vfsp;
473 {
474 DBG_VOP(("volfs_init called\n"));
475
476 volfs_PLChashinit();
477
478 return (0);
479 }
480
481 /*
482 * fast filesystem related variables.
483 */
484 int
485 volfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
486 int *name;
487 u_int namelen;
488 void *oldp;
489 size_t *oldlenp;
490 void *newp;
491 size_t newlen;
492 struct proc *p;
493 {
494 DBG_VOP(("volfs_sysctl called\n"));
495 return (EOPNOTSUPP);
496 }
497