]> git.saurik.com Git - apple/xnu.git/blame - bsd/miscfs/synthfs/synthfs_vfsops.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_vfsops.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
29/*
30 * Change History:
31 *
32 * 17-Aug-1999 Pat Dirks New today.
33 *
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/namei.h>
39#include <sys/filedesc.h>
91447636 40#include <sys/proc_internal.h>
1c79356b
A
41#include <sys/kernel.h>
42#include <mach/machine/vm_types.h>
91447636 43#include <sys/vnode_internal.h>
1c79356b 44#include <sys/socket.h>
91447636 45#include <sys/mount_internal.h>
1c79356b
A
46#include <sys/mbuf.h>
47#include <sys/file.h>
55e303ae 48#include <sys/disk.h>
1c79356b
A
49#include <sys/ioctl.h>
50#include <sys/errno.h>
51#include <sys/malloc.h>
52#include <sys/attr.h>
91447636 53#include <sys/uio_internal.h>
1c79356b
A
54
55#include <miscfs/specfs/specdev.h>
56
57#include "synthfs.h"
58
59#define LOADABLE_FS 0
60
61typedef int (*PFI)();
62
63struct vfsops synthfs_vfsops = {
64 synthfs_mount,
65 synthfs_start,
66 synthfs_unmount,
67 synthfs_root,
91447636
A
68 NULL, /* quotactl */
69 synthfs_vfs_getattr,
1c79356b
A
70 synthfs_sync,
71 synthfs_vget,
72 synthfs_fhtovp,
73 synthfs_vptofh,
74 synthfs_init,
75 synthfs_sysctl
76};
77
78#define ROOTMPMODE 0755
79#define ROOTPLACEHOLDERMODE 0700
91447636 80static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs";
1c79356b
A
81static char synthfs_fake_mntfromname[] = "<synthfs>";
82
83
84extern struct vnodeopv_desc synthfs_vnodeop_opv_desc;
85
86/* The following refer to kernel global variables used in the loading/initialization: */
87extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
88extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
89extern int vfs_opv_numops; /* The total number of defined vnode operations */
90
91int vn_mkdir(struct proc *p, char *path, int mode);
92int vn_symlink(struct proc *p, char *path, char *link);
93
94
95
96
97#if LOADABLE_FS
98void
99synthfs_load(int loadArgument) {
91447636 100 /* Should use vfs_fsadd kpi */
1c79356b
A
101}
102
103
104
105int synthfs_unload(void) {
1c79356b 106
91447636 107 /* should use fs_fsremove kpi */
1c79356b
A
108 return 0;
109}
110#endif
111
112
113
114/*
115 * VFS Operations.
116 *
117 * mount system call
118 */
119int
91447636 120synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data, struct proc *p)
1c79356b
A
121{
122 struct synthfs_mntdata *priv_mnt_data;
123 int error;
124 size_t size;
125
126 DBG_VOP(("synthfs_mount_fs called.\n"));
127 MALLOC(priv_mnt_data, struct synthfs_mntdata *, sizeof(struct synthfs_mntdata), M_SYNTHFS, M_WAITOK);
128 DBG_VOP(("MALLOC succeeded...\n"));
129
91447636
A
130 strncpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename));
131 strncpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname));
1c79356b
A
132 priv_mnt_data->synthfs_mounteddev = (dev_t)0;
133 priv_mnt_data->synthfs_nextid = FIRST_SYNTHFS_ID;
134 priv_mnt_data->synthfs_filecount = 0;
135 priv_mnt_data->synthfs_dircount = 0;
136 priv_mnt_data->synthfs_encodingsused = 0x00000001;
137
138 /*
139 Set up the root vnode for fast reference in the future.
140 Note that synthfs_new_directory() returns the vnode with a refcount of +2.
141 The root vnode's refcount is maintained unlocked but with a pos. ref count until unmount.
142 */
143 error = synthfs_new_directory(mp, NULL, "", ROOT_DIRID, (S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH), p, &priv_mnt_data->synthfs_rootvp);
144 if (error) {
145 DBG_VOP(("Attempt to create root directory failed with error %d.\n", error));
146 return error;
147 };
148 priv_mnt_data->synthfs_rootvp->v_flag |= VROOT;
149
150 priv_mnt_data->synthfs_mp = mp;
151 mp->mnt_data = (void *)priv_mnt_data;
152
153 /* Drop the freshly acquired reference on the root, leaving v_usecount=1 to prevent
154 the vnode from beeing freed: */
91447636 155 vnode_put(priv_mnt_data->synthfs_rootvp);
1c79356b
A
156
157 return (0);
158}
159
160
161
162int
91447636 163synthfs_mount(mp, devvp, data, context)
1c79356b 164 register struct mount *mp;
91447636
A
165 vnode_t devvp;
166 user_addr_t data;
167 vfs_context_t context;
1c79356b
A
168{
169 size_t size;
170
91447636 171 return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context)));
1c79356b
A
172}
173
174
175
176
177
178
179/*
180 * Initialize the filesystem
181 */
182int
183synthfs_init(vfsp)
184 struct vfsconf *vfsp;
185{
186 DBG_VOP(("synthfs_init called.\n"));
187 return 0;
188}
189
190int
91447636 191synthfs_start(mp, flags, context)
1c79356b
A
192struct mount * mp;
193int flags;
91447636 194vfs_context_t context;
1c79356b
A
195{
196 DBG_VOP(("synthfs_start called.\n"));
197 return 0;
198}
199
200/*
201 * Return the root of a filesystem.
202 */
203int
91447636 204synthfs_root(mp, vpp, context)
1c79356b
A
205 struct mount *mp;
206 struct vnode **vpp;
91447636 207 vfs_context_t context;
1c79356b
A
208{
209 unsigned long root_nodeid = ROOT_DIRID;
210
211 DBG_VOP(("synthfs_root called.\n"));
212
213 *vpp = VFSTOSFS(mp)->synthfs_rootvp;
91447636 214 return vnode_get(VFSTOSFS(mp)->synthfs_rootvp);
1c79356b
A
215}
216
217/*
218 * unmount system call
219 */
220int
91447636 221synthfs_unmount(mp, mntflags, context)
1c79356b
A
222 struct mount *mp;
223 int mntflags;
91447636 224 vfs_context_t context;
1c79356b
A
225{
226 struct synthfs_mntdata *synth;
227 struct vnode *root_vp;
228 int retval;
229
230 DBG_VOP(("synthfs_unmount called.\n"));
231 synth = (struct synthfs_mntdata *)mp->mnt_data;
232
233 root_vp = synth->synthfs_rootvp;
234 retval = vflush(mp, root_vp, (mntflags & MNT_FORCE) ? FORCECLOSE : 0);
235 if (retval && ((mntflags & MNT_FORCE) == 0)) goto Err_Exit;
236
237 /* Free the root vnode.
1c79356b
A
238 the ref. count has been maintained at +1 ever since mount time. */
239 if (root_vp) {
1c79356b
A
240 if ((mntflags & MNT_FORCE) == 0) {
241 if (retval) goto Err_Exit;
242
243 if (root_vp->v_usecount > 1) {
244 DBG_VOP(("synthfs ERROR: root vnode = %x, usecount = %d\n", (int)root_vp, synth->synthfs_rootvp->v_usecount));
1c79356b
A
245 retval = EBUSY;
246 goto Err_Exit;
247 };
248 };
249
250 synth->synthfs_rootvp = NULL;
251
252 if (retval == 0) {
91447636
A
253 vnode_get(root_vp);
254 vnode_rele(root_vp);
255 vnode_recycle(root_vp);
256 vnode_put(root_vp); /* This drops synthfs's own refcount */
1c79356b
A
257 };
258 };
259
260 /* All vnodes should be gone, and no errors, clean up the last */
261
262 mp->mnt_data = NULL;
263 FREE(synth, M_SYNTHFS);
264
265Err_Exit:
266
267 if (mntflags & MNT_FORCE) retval = 0;
268
269 return(retval);
270}
271
272/*
273 * Get file system statistics.
274 */
275int
91447636 276synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
1c79356b 277{
91447636
A
278 struct synthfs_mntdata *synthfs_mp = VFSTOSFS(mp);
279 DBG_VOP(("synthfs_vfs_getattr called.\n"));
280
281 VFSATTR_RETURN(fsap, f_bsize, 512);
282 VFSATTR_RETURN(fsap, f_iosize, 512);
283 VFSATTR_RETURN(fsap, f_blocks, 1024);
284 VFSATTR_RETURN(fsap, f_bfree, 0);
285 VFSATTR_RETURN(fsap, f_bavail, 0);
286 VFSATTR_RETURN(fsap, f_bused, 1024);
287 VFSATTR_RETURN(fsap, f_files, synthfs_mp->synthfs_filecount + synthfs_mp->synthfs_dircount);
288 VFSATTR_RETURN(fsap, f_ffree, 0);
289 VFSATTR_RETURN(fsap, f_fssubtype, 0);
290
291 return 0;
1c79356b
A
292}
293
294/*
295 * synthfs doesn't have any data or backing store and you can't write into any of the synthfs
296 * structures, so don't do anything
297 */
298int
91447636 299synthfs_sync(mp, waitfor, context)
1c79356b
A
300 struct mount *mp;
301 int waitfor;
91447636 302 vfs_context_t context;
1c79356b
A
303{
304// DBG_VOP(("synthfs_sync called\n"));
305 return 0;
306}
307/*
308 * Look up a synthfs node by node number.
309 */
310int
91447636 311synthfs_vget(mp, ino, vpp, context)
1c79356b 312 struct mount *mp;
91447636 313 ino64_t ino;
1c79356b 314 struct vnode **vpp;
91447636 315 vfs_context_t context;
1c79356b
A
316{
317 struct vnode *vp;
91447636 318 int vid = 0;
1c79356b
A
319
320// DBG_VOP(("synthfs_vget called\n"));
321
322 /* Check for unmount in progress */
323 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
324 *vpp = NULL;
325 return (EPERM);
326 }
327
328loop:
91447636
A
329 TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
330 if (VTOS(vp)->s_nodeid == (unsigned long)ino) {
331 /*
332 * doing a vnode_getwithvid isn't technically
333 * necessary since synthfs is an unsafe filesystem
334 * and we're running behind a funnel at this point
335 * however, vnode_get always succeeds, which isn't
336 * what we want if this vnode is in the process of
337 * being terminated
338 */
339 vid = vnode_vid(vp);
340
341 if (vnode_getwithvid(vp, vid) != 0) {
342 goto loop;
343 };
1c79356b
A
344 *vpp = vp;
345 return 0;
346 };
347 };
348 *vpp = NULL;
349 return -1;
350}
351
352/*
353 * fast filesystem related variables.
354 */
355int
91447636
A
356synthfs_sysctl(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
357 user_addr_t newp, size_t newlen, vfs_context_t context)
1c79356b
A
358{
359 DBG_VOP(("synthfs_sysctl called.\n"));
91447636 360 return (ENOTSUP);
1c79356b
A
361}
362
363/*
364 * File handle to vnode
365 *
366 */
367int
91447636 368synthfs_fhtovp(mp, fhlen, fhp, vpp, context)
1c79356b 369 register struct mount *mp;
91447636
A
370 int fhlen;
371 unsigned char *fhp;
1c79356b 372 struct vnode **vpp;
91447636 373 vfs_context_t context;
1c79356b
A
374{
375 DBG_VOP(("synthfs_fhtovp called.\n"));
91447636 376 return ENOTSUP;
1c79356b
A
377}
378
379/*
380 * Vnode pointer to File handle
381 */
382/* ARGSUSED */
383int
91447636 384synthfs_vptofh(vp, fhlenp, fhp, context)
1c79356b 385 struct vnode *vp;
91447636
A
386 int *fhlenp;
387 unsigned char *fhp;
388 vfs_context_t context;
1c79356b
A
389{
390 DBG_VOP(("synthfs_vptofh called.\n"));
91447636 391 return ENOTSUP;
1c79356b
A
392}
393
394
395
396
397
398
399int
91447636
A
400vn_mkdir(struct proc *p, char *path, int mode)
401{
1c79356b
A
402 struct nameidata nd;
403 struct vnode *vp;
91447636
A
404 struct vnode_attr va;
405 struct vfs_context context;
1c79356b
A
406 int error;
407
91447636
A
408 context.vc_proc = p;
409 context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */
410
411 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), &context);
412 error = namei(&nd);
413 if (error) {
1c79356b
A
414 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
415 return (error);
416 };
417 vp = nd.ni_vp;
91447636
A
418
419 if (vp == NULL) {
420 VATTR_INIT(&va);
421 VATTR_SET(&va, va_type, VDIR);
422 VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask);
423
424 error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, &context);
425 if (error)
426 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error));
427 } else {
1c79356b 428 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
91447636 429 error = EEXIST;
1c79356b 430 }
91447636
A
431 vnode_put(nd.ni_dvp);
432 if (nd.ni_vp)
433 vnode_put(nd.ni_vp);
434 nameidone(&nd);
435
1c79356b
A
436 return (error);
437}
438
439
440
441int
442vn_symlink(struct proc *p, char *path, char *link) {
443 struct nameidata nd;
91447636
A
444 struct vnode_attr va;
445 struct vfs_context context;
1c79356b
A
446 int error;
447
91447636
A
448 context.vc_proc = p;
449 context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */
450
451 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), &context);
452 if ((error = namei(&nd))) return error;
453
454 if (nd.ni_vp == NULL) {
455 VATTR_INIT(&va);
456 VATTR_SET(&va, va_type, VLNK);
457 VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask);
458
459 error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, &context);
460 } else
461 error = EEXIST;
462
463 vnode_put(nd.ni_dvp);
464 if (nd.ni_vp)
465 vnode_put(nd.ni_vp);
466 nameidone(&nd);
467
468 return (error);
1c79356b
A
469}
470
471