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