]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/synthfs/synthfs_vfsops.c
44a64a09fad34bd3bf52474e0d94c782ed7a296d
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_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 * 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
56 typedef int (*PFI)();
57
58 struct 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
75 static char synthfs_fs_name[MFSNAMELEN] = "synthfs";
76 static char synthfs_fake_mntfromname[] = "<synthfs>";
77
78
79 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc;
80
81 /* The following refer to kernel global variables used in the loading/initialization: */
82 extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
83 extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
84 extern int vfs_opv_numops; /* The total number of defined vnode operations */
85
86 int vn_mkdir(struct proc *p, char *path, int mode);
87 int vn_symlink(struct proc *p, char *path, char *link);
88
89
90
91
92 #if LOADABLE_FS
93 void
94 synthfs_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
199 ErrExit: ;
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
206 InitFS: ;
207 DBG_VOP(("load_synthfs: calling synthfs_init()...\n"));
208 synthfs_init(newvfsconf);
209 };
210
211 StdExit: ;
212 }
213
214
215
216 int 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 */
230 int
231 synthfs_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
274 int
275 synthfs_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 */
296 int
297 synthfs_init(vfsp)
298 struct vfsconf *vfsp;
299 {
300 DBG_VOP(("synthfs_init called.\n"));
301 return 0;
302 }
303
304 int
305 synthfs_start(mp, flags, p)
306 struct mount * mp;
307 int flags;
308 struct proc * p;
309 {
310 DBG_VOP(("synthfs_start called.\n"));
311 return 0;
312 }
313
314 /*
315 * Return the root of a filesystem.
316 */
317 int
318 synthfs_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
330 int
331 synthfs_quotactl(mp, cmds, uid, arg, p)
332 struct mount *mp;
333 int cmds;
334 uid_t uid;
335 caddr_t arg;
336 struct proc * p;
337 {
338 DBG_VOP(("synthfs_quotactl called.\n"));
339 return (0);
340 }
341
342 /*
343 * unmount system call
344 */
345 int
346 synthfs_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
391 Err_Exit:
392
393 if (mntflags & MNT_FORCE) retval = 0;
394
395 return(retval);
396 }
397
398 /*
399 * Get file system statistics.
400 */
401 int
402 synthfs_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 */
426 int
427 synthfs_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 */
439 int
440 synthfs_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
455 loop:
456 LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
457 if (VTOS(vp)->s_nodeid == *((unsigned long *)ino)) {
458 if (vget(vp, LK_EXCLUSIVE, current_proc()) != 0) {
459 goto loop;
460 };
461 *vpp = vp;
462 return 0;
463 };
464 };
465 *vpp = NULL;
466 return -1;
467 }
468
469 /*
470 * fast filesystem related variables.
471 */
472 int
473 synthfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
474 int *name;
475 u_int namelen;
476 void *oldp;
477 size_t *oldlenp;
478 void *newp;
479 size_t newlen;
480 struct proc *p;
481 {
482 DBG_VOP(("synthfs_sysctl called.\n"));
483 return (EOPNOTSUPP);
484 }
485
486 /*
487 * File handle to vnode
488 *
489 */
490 int
491 synthfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
492 register struct mount *mp;
493 struct fid *fhp;
494 struct mbuf *nam;
495 struct vnode **vpp;
496 int *exflagsp;
497 struct ucred **credanonp;
498 {
499 DBG_VOP(("synthfs_fhtovp called.\n"));
500 return EOPNOTSUPP;
501 }
502
503 /*
504 * Vnode pointer to File handle
505 */
506 /* ARGSUSED */
507 int
508 synthfs_vptofh(vp, fhp)
509 struct vnode *vp;
510 struct fid *fhp;
511 {
512 DBG_VOP(("synthfs_vptofh called.\n"));
513 return EOPNOTSUPP;
514 }
515
516
517
518
519
520
521 int
522 vn_mkdir(struct proc *p, char *path, int mode) {
523 struct nameidata nd;
524 struct vnode *vp;
525 struct vattr vattr;
526 int error;
527
528 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, path, p);
529 if (error = namei(&nd)) {
530 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
531 return (error);
532 };
533 vp = nd.ni_vp;
534 if (vp != NULL) {
535 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
536 if (nd.ni_dvp == vp)
537 vrele(nd.ni_dvp);
538 else
539 vput(nd.ni_dvp);
540 vrele(vp);
541 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
542 return (EEXIST);
543 }
544 VATTR_NULL(&vattr);
545 vattr.va_type = VDIR;
546 vattr.va_mode = (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
547 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
548 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
549 if (error) {
550 DBG_VOP(("vn_mkdir: error from VOP_MKDIR (%d).\n", error));
551 } else {
552 vput(nd.ni_vp);
553 };
554 return (error);
555 }
556
557
558
559 int
560 vn_symlink(struct proc *p, char *path, char *link) {
561 struct nameidata nd;
562 struct vattr vattr;
563 int error;
564
565 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, link, p);
566 if (error = namei(&nd)) return error;
567
568 if (nd.ni_vp) {
569 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
570 if (nd.ni_dvp == nd.ni_vp)
571 vrele(nd.ni_dvp);
572 else
573 vput(nd.ni_dvp);
574 vrele(nd.ni_vp);
575 return EEXIST;
576 }
577 VATTR_NULL(&vattr);
578 vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
579 VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
580 return VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
581 }
582
583