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