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