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