]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/synthfs/synthfs_vfsops.c
525a0a3ee27bbf8b9854b4f3dbec37d3617aaa7f
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_vfsops.c
1 /*
2 * Copyright (c) 2000-2001 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 * 17-Aug-1999 Pat Dirks New today.
30 *
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/namei.h>
36 #include <sys/filedesc.h>
37 #include <sys/proc.h>
38 #include <sys/kernel.h>
39 #include <mach/machine/vm_types.h>
40 #include <sys/vnode.h>
41 #include <sys/socket.h>
42 #include <sys/mount.h>
43 #include <sys/buf.h>
44 #include <sys/mbuf.h>
45 #include <sys/file.h>
46 #include <dev/disk.h>
47 #include <sys/ioctl.h>
48 #include <sys/errno.h>
49 #include <sys/malloc.h>
50 #include <sys/attr.h>
51
52 #include <miscfs/specfs/specdev.h>
53
54 #include "synthfs.h"
55
56 #define LOADABLE_FS 0
57
58 typedef int (*PFI)();
59
60 struct vfsops synthfs_vfsops = {
61 synthfs_mount,
62 synthfs_start,
63 synthfs_unmount,
64 synthfs_root,
65 synthfs_quotactl,
66 synthfs_statfs,
67 synthfs_sync,
68 synthfs_vget,
69 synthfs_fhtovp,
70 synthfs_vptofh,
71 synthfs_init,
72 synthfs_sysctl
73 };
74
75 #define ROOTMPMODE 0755
76 #define ROOTPLACEHOLDERMODE 0700
77 static char synthfs_fs_name[MFSNAMELEN] = "synthfs";
78 static char synthfs_fake_mntfromname[] = "<synthfs>";
79
80
81 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc;
82
83 /* The following refer to kernel global variables used in the loading/initialization: */
84 extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
85 extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
86 extern int vfs_opv_numops; /* The total number of defined vnode operations */
87
88 int vn_mkdir(struct proc *p, char *path, int mode);
89 int vn_symlink(struct proc *p, char *path, char *link);
90
91
92
93
94 #if LOADABLE_FS
95 void
96 synthfs_load(int loadArgument) {
97 struct vfsconf *newvfsconf = NULL;
98 int j;
99 int (***opv_desc_vector_p)() = NULL;
100 int (**opv_desc_vector)();
101 struct vnodeopv_entry_desc *opve_descp;
102 int error = 0;
103
104 #pragma unused(loadArgument)
105
106 /*
107 * This routine is responsible for all the initialization that would
108 * ordinarily be done as part of the system startup; it calls synthfs_init
109 * to do the initialization that is strictly synthfs-specific.
110 */
111
112 DBG_VOP(("load_synthfs: starting ...\n"));
113
114 MALLOC(newvfsconf, void *, sizeof(struct vfsconf), M_SYNTHFS, M_WAITOK);
115 DBG_VOP(("load_synthfs: Allocated new vfsconf list entry, newvfsconf = 0x%08lx.\n", (unsigned long)newvfsconf));
116 bzero(newvfsconf, sizeof(struct vfsconf));
117
118 if (newvfsconf) {
119 DBG_VOP(("load_synthfs: filling in newly allocated vfsconf entry at 0x%08lX.\n", (long)newvfsconf));
120 newvfsconf->vfc_vfsops = &synthfs_vfsops;
121 strncpy(&newvfsconf->vfc_name[0], synthfs_fs_name, MFSNAMELEN);
122 newvfsconf->vfc_typenum = maxvfsconf++;
123 newvfsconf->vfc_refcount = 0;
124 newvfsconf->vfc_flags = 0;
125 newvfsconf->vfc_mountroot = NULL; /* Can't mount root of file system [yet] */
126
127 newvfsconf->vfc_next = NULL;
128
129 /* Based on vfs_op_init and ... */
130 opv_desc_vector_p = synthfs_vnodeop_opv_desc.opv_desc_vector_p;
131
132 DBG_VOP(("load_synthfs: Allocating and initializing VNode ops vector...\n"));
133
134 /*
135 * Allocate and init the vector.
136 * Also handle backwards compatibility.
137 */
138
139 MALLOC(*opv_desc_vector_p, PFI *, vfs_opv_numops*sizeof(PFI), M_SYNTHFS, M_WAITOK);
140 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
141 opv_desc_vector = *opv_desc_vector_p;
142 for (j=0; synthfs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
143 opve_descp = &(synthfs_vnodeop_opv_desc.opv_desc_ops[j]);
144
145 /*
146 * Sanity check: is this operation listed
147 * in the list of operations? We check this
148 * by seeing if its offest is zero. Since
149 * the default routine should always be listed
150 * first, it should be the only one with a zero
151 * offset. Any other operation with a zero
152 * offset is probably not listed in
153 * vfs_op_descs, and so is probably an error.
154 *
155 * A panic here means the layer programmer
156 * has committed the all-too common bug
157 * of adding a new operation to the layer's
158 * list of vnode operations but
159 * not adding the operation to the system-wide
160 * list of supported operations.
161 */
162 if (opve_descp->opve_op->vdesc_offset == 0 &&
163 opve_descp->opve_op->vdesc_offset != VOFFSET(vop_default)) {
164 DBG_VOP(("load_synthfs: operation %s not listed in %s.\n",
165 opve_descp->opve_op->vdesc_name,
166 "vfs_op_descs"));
167 panic ("load_synthfs: bad operation");
168 }
169 /*
170 * Fill in this entry.
171 */
172 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
173 opve_descp->opve_impl;
174 }
175
176 /*
177 * Finally, go back and replace unfilled routines
178 * with their default. (Sigh, an O(n^3) algorithm. I
179 * could make it better, but that'd be work, and n is small.)
180 */
181 opv_desc_vector_p = synthfs_vnodeop_opv_desc.opv_desc_vector_p;
182
183 /*
184 * Force every operations vector to have a default routine.
185 */
186 opv_desc_vector = *opv_desc_vector_p;
187 if (opv_desc_vector[VOFFSET(vop_default)]==NULL) {
188 panic("load_vp;fs: operation vector without default routine.");
189 }
190 for (j = 0;j<vfs_opv_numops; j++)
191 if (opv_desc_vector[j] == NULL)
192 opv_desc_vector[j] =
193 opv_desc_vector[VOFFSET(vop_default)];
194
195 if (error = vfsconf_add(newvfsconf)) {
196 goto ErrExit;
197 };
198 goto InitFS;
199
200
201 ErrExit: ;
202 if (opv_desc_vector_p && *opv_desc_vector_p) FREE(*opv_desc_vector_p, M_SYNTHFS);
203
204 if (newvfsconf) FREE (newvfsconf, M_SYNTHFS);
205 goto StdExit;
206
207
208 InitFS: ;
209 DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
210 synthfs_init(newvfsconf);
211 };
212
213 StdExit: ;
214 }
215
216
217
218 int synthfs_unload(void) {
219 DBG_VOP(("synthfs: Entering synthfs_unload...\n"));
220
221 return 0;
222 }
223 #endif
224
225
226
227 /*
228 * VFS Operations.
229 *
230 * mount system call
231 */
232 int
233 synthfs_mount_fs(struct mount *mp, char *path, caddr_t data, struct nameidata *ndp, struct proc *p)
234 {
235 struct synthfs_mntdata *priv_mnt_data;
236 int error;
237 size_t size;
238
239 DBG_VOP(("synthfs_mount_fs called.\n"));
240 MALLOC(priv_mnt_data, struct synthfs_mntdata *, sizeof(struct synthfs_mntdata), M_SYNTHFS, M_WAITOK);
241 DBG_VOP(("MALLOC succeeded...\n"));
242
243 strncpy(mp->mnt_stat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_stat.f_fstypename));
244 (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
245 strncpy(mp->mnt_stat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_stat.f_mntfromname));
246 priv_mnt_data->synthfs_mounteddev = (dev_t)0;
247 priv_mnt_data->synthfs_nextid = FIRST_SYNTHFS_ID;
248 priv_mnt_data->synthfs_filecount = 0;
249 priv_mnt_data->synthfs_dircount = 0;
250 priv_mnt_data->synthfs_encodingsused = 0x00000001;
251
252 /*
253 Set up the root vnode for fast reference in the future.
254 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
255 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
256 */
257 error = synthfs_new_directory(mp, NULL, "", ROOT_DIRID, (S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH), p, &priv_mnt_data->synthfs_rootvp);
258 if (error) {
259 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error));
260 return error;
261 };
262 priv_mnt_data->synthfs_rootvp->v_flag |= VROOT;
263
264 priv_mnt_data->synthfs_mp = mp;
265 mp->mnt_data = (void *)priv_mnt_data;
266
267 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
268 the vnode from beeing freed: */
269 vput(priv_mnt_data->synthfs_rootvp);
270
271 return (0);
272 }
273
274
275
276 int
277 synthfs_mount(mp, path, data, ndp, p)
278 register struct mount *mp;
279 char *path;
280 caddr_t data;
281 struct nameidata *ndp;
282 struct proc *p;
283 {
284 size_t size;
285
286 (void) copyinstr(path, mp->mnt_stat.f_mntonname, sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
287 return (synthfs_mount_fs(mp, path, data, ndp, p));
288 }
289
290
291
292
293
294
295 /*
296 * Initialize the filesystem
297 */
298 int
299 synthfs_init(vfsp)
300 struct vfsconf *vfsp;
301 {
302 DBG_VOP(("synthfs_init called.\n"));
303 return 0;
304 }
305
306 int
307 synthfs_start(mp, flags, p)
308 struct mount * mp;
309 int flags;
310 struct proc * p;
311 {
312 DBG_VOP(("synthfs_start called.\n"));
313 return 0;
314 }
315
316 /*
317 * Return the root of a filesystem.
318 */
319 int
320 synthfs_root(mp, vpp)
321 struct mount *mp;
322 struct vnode **vpp;
323 {
324 unsigned long root_nodeid = ROOT_DIRID;
325
326 DBG_VOP(("synthfs_root called.\n"));
327
328 *vpp = VFSTOSFS(mp)->synthfs_rootvp;
329 return vget(VFSTOSFS(mp)->synthfs_rootvp, LK_EXCLUSIVE | LK_RETRY, current_proc());
330 }
331
332 int
333 synthfs_quotactl(mp, cmds, uid, arg, p)
334 struct mount *mp;
335 int cmds;
336 uid_t uid;
337 caddr_t arg;
338 struct proc * p;
339 {
340 DBG_VOP(("synthfs_quotactl called.\n"));
341 return (0);
342 }
343
344 /*
345 * unmount system call
346 */
347 int
348 synthfs_unmount(mp, mntflags, p)
349 struct mount *mp;
350 int mntflags;
351 struct proc *p;
352 {
353 struct synthfs_mntdata *synth;
354 struct vnode *root_vp;
355 int retval;
356
357 DBG_VOP(("synthfs_unmount called.\n"));
358 synth = (struct synthfs_mntdata *)mp->mnt_data;
359
360 root_vp = synth->synthfs_rootvp;
361 retval = vflush(mp, root_vp, (mntflags & MNT_FORCE) ? FORCECLOSE : 0);
362 if (retval && ((mntflags & MNT_FORCE) == 0)) goto Err_Exit;
363
364 /* Free the root vnode.
365 Note that there's no need to vget() or vref() it before locking it here:
366 the ref. count has been maintained at +1 ever since mount time. */
367 if (root_vp) {
368 retval = vn_lock(root_vp, LK_EXCLUSIVE | LK_RETRY, p);
369 if ((mntflags & MNT_FORCE) == 0) {
370 if (retval) goto Err_Exit;
371
372 if (root_vp->v_usecount > 1) {
373 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, synth->synthfs_rootvp->v_usecount));
374 VOP_UNLOCK(root_vp, 0, p);
375 retval = EBUSY;
376 goto Err_Exit;
377 };
378 };
379
380 synth->synthfs_rootvp = NULL;
381
382 if (retval == 0) {
383 vput(root_vp); /* This drops synthfs's own refcount */
384 vgone(root_vp);
385 };
386 };
387
388 /* All vnodes should be gone, and no errors, clean up the last */
389
390 mp->mnt_data = NULL;
391 FREE(synth, M_SYNTHFS);
392
393 Err_Exit:
394
395 if (mntflags & MNT_FORCE) retval = 0;
396
397 return(retval);
398 }
399
400 /*
401 * Get file system statistics.
402 */
403 int
404 synthfs_statfs(mp, sbp, p)
405 struct mount *mp;
406 register struct statfs *sbp;
407 struct proc *p;
408 {
409 DBG_VOP(("synthfs_statfs called.\n"));
410
411 sbp->f_bsize = 512;
412 sbp->f_iosize = 512;
413 sbp->f_blocks = 1024; // lies, darn lies and virtual file systems
414 sbp->f_bfree = 0; // Nope, can't write here!
415 sbp->f_bavail = 0;
416 sbp->f_files = VFSTOSFS(mp)->synthfs_filecount + VFSTOSFS(mp)->synthfs_dircount;
417 sbp->f_ffree = 0;
418 strncpy(sbp->f_mntonname, mp->mnt_stat.f_mntonname, sizeof(sbp->f_mntonname));
419 strncpy(sbp->f_mntfromname, mp->mnt_stat.f_mntfromname, sizeof(sbp->f_mntfromname));
420
421 return (0);
422 }
423
424 /*
425 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
426 * structures, so don't do anything
427 */
428 int
429 synthfs_sync(mp, waitfor, cred, p)
430 struct mount *mp;
431 int waitfor;
432 struct ucred *cred;
433 struct proc *p;
434 {
435 // DBG_VOP(("synthfs_sync called\n"));
436 return 0;
437 }
438 /*
439 * Look up a synthfs node by node number.
440 */
441 int
442 synthfs_vget(mp, ino, vpp)
443 struct mount *mp;
444 void *ino;
445 struct vnode **vpp;
446 {
447 struct vnode *vp;
448
449 // DBG_VOP(("synthfs_vget called\n"));
450
451 /* Check for unmount in progress */
452 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
453 *vpp = NULL;
454 return (EPERM);
455 }
456
457 loop:
458 simple_lock(&mntvnode_slock);
459 LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
460 if (VTOS(vp)->s_nodeid == *((unsigned long *)ino)) {
461 if (vget(vp, LK_EXCLUSIVE, current_proc()) != 0) {
462 simple_unlock(&mntvnode_slock);
463 goto loop;
464 };
465 simple_unlock(&mntvnode_slock);
466 *vpp = vp;
467 return 0;
468 };
469 };
470 simple_unlock(&mntvnode_slock);
471 *vpp = NULL;
472 return -1;
473 }
474
475 /*
476 * fast filesystem related variables.
477 */
478 int
479 synthfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
480 int *name;
481 u_int namelen;
482 void *oldp;
483 size_t *oldlenp;
484 void *newp;
485 size_t newlen;
486 struct proc *p;
487 {
488 DBG_VOP(("synthfs_sysctl called.\n"));
489 return (EOPNOTSUPP);
490 }
491
492 /*
493 * File handle to vnode
494 *
495 */
496 int
497 synthfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
498 register struct mount *mp;
499 struct fid *fhp;
500 struct mbuf *nam;
501 struct vnode **vpp;
502 int *exflagsp;
503 struct ucred **credanonp;
504 {
505 DBG_VOP(("synthfs_fhtovp called.\n"));
506 return EOPNOTSUPP;
507 }
508
509 /*
510 * Vnode pointer to File handle
511 */
512 /* ARGSUSED */
513 int
514 synthfs_vptofh(vp, fhp)
515 struct vnode *vp;
516 struct fid *fhp;
517 {
518 DBG_VOP(("synthfs_vptofh called.\n"));
519 return EOPNOTSUPP;
520 }
521
522
523
524
525
526
527 int
528 vn_mkdir(struct proc *p, char *path, int mode) {
529 struct nameidata nd;
530 struct vnode *vp;
531 struct vattr vattr;
532 int error;
533
534 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, path, p);
535 if (error = namei(&nd)) {
536 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
537 return (error);
538 };
539 vp = nd.ni_vp;
540 if (vp != NULL) {
541 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
542 if (nd.ni_dvp == vp)
543 vrele(nd.ni_dvp);
544 else
545 vput(nd.ni_dvp);
546 vrele(vp);
547 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
548 return (EEXIST);
549 }
550 VATTR_NULL(&vattr);
551 vattr.va_type = VDIR;
552 vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
553 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
554 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
555 if (error) {
556 DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error));
557 } else {
558 vput(nd.ni_vp);
559 };
560 return (error);
561 }
562
563
564
565 int
566 vn_symlink(struct proc *p, char *path, char *link) {
567 struct nameidata nd;
568 struct vattr vattr;
569 int error;
570
571 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, link, p);
572 if (error = namei(&nd)) return error;
573
574 if (nd.ni_vp) {
575 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
576 if (nd.ni_dvp == nd.ni_vp)
577 vrele(nd.ni_dvp);
578 else
579 vput(nd.ni_dvp);
580 vrele(nd.ni_vp);
581 return EEXIST;
582 }
583 VATTR_NULL(&vattr);
584 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
585 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
586 return VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
587 }
588
589