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