]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/synthfs/synthfs_vfsops.c
xnu-1228.tar.gz
[apple/xnu.git] / bsd / miscfs / synthfs / synthfs_vfsops.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. 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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
40 #include <sys/proc_internal.h>
41 #include <sys/kernel.h>
42 #include <mach/machine/vm_types.h>
43 #include <sys/vnode_internal.h>
44 #include <sys/socket.h>
45 #include <sys/mount_internal.h>
46 #include <sys/mbuf.h>
47 #include <sys/file.h>
48 #include <sys/disk.h>
49 #include <sys/ioctl.h>
50 #include <sys/errno.h>
51 #include <sys/malloc.h>
52 #include <sys/attr.h>
53 #include <sys/uio_internal.h>
54
55 #include <miscfs/specfs/specdev.h>
56
57 #include "synthfs.h"
58
59 #define LOADABLE_FS 0
60
61 typedef int (*PFI)();
62
63 struct vfsops synthfs_vfsops = {
64 synthfs_mount,
65 synthfs_start,
66 synthfs_unmount,
67 synthfs_root,
68 NULL, /* quotactl */
69 synthfs_vfs_getattr,
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
80 static char synthfs_fs_name[MFSTYPENAMELEN] = "synthfs";
81 static char synthfs_fake_mntfromname[] = "<synthfs>";
82
83
84 extern struct vnodeopv_desc synthfs_vnodeop_opv_desc;
85
86 /* The following refer to kernel global variables used in the loading/initialization: */
87 extern int maxvfsslots; /* Total number of slots in the system's vfsconf table */
88 extern int maxvfsconf; /* The highest fs type number [old-style ID] in use [dispite its name] */
89 extern int vfs_opv_numops; /* The total number of defined vnode operations */
90
91 int vn_mkdir(struct proc *p, char *path, int mode);
92 int vn_symlink(struct proc *p, char *path, char *link);
93
94
95
96
97 #if LOADABLE_FS
98 void
99 synthfs_load(int loadArgument) {
100 /* Should use vfs_fsadd kpi */
101 }
102
103
104
105 int synthfs_unload(void) {
106
107 /* should use fs_fsremove kpi */
108 return 0;
109 }
110 #endif
111
112
113
114 /*
115 * VFS Operations.
116 *
117 * mount system call
118 */
119 int
120 synthfs_mount_fs(struct mount *mp, vnode_t devvp, __unused user_addr_t data, struct proc *p)
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
130 strlcpy(mp->mnt_vfsstat.f_fstypename, synthfs_fs_name, sizeof(mp->mnt_vfsstat.f_fstypename));
131 strlcpy(mp->mnt_vfsstat.f_mntfromname, synthfs_fake_mntfromname, sizeof(mp->mnt_vfsstat.f_mntfromname));
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: */
155 vnode_put(priv_mnt_data->synthfs_rootvp);
156
157 return (0);
158 }
159
160
161
162 int
163 synthfs_mount(mp, devvp, data, context)
164 register struct mount *mp;
165 vnode_t devvp;
166 user_addr_t data;
167 vfs_context_t context;
168 {
169 size_t size;
170
171 return (synthfs_mount_fs(mp, devvp, data, vfs_context_proc(context)));
172 }
173
174
175
176
177
178
179 /*
180 * Initialize the filesystem
181 */
182 int
183 synthfs_init(vfsp)
184 struct vfsconf *vfsp;
185 {
186 DBG_VOP(("synthfs_init called.\n"));
187 return 0;
188 }
189
190 int
191 synthfs_start(mp, flags, context)
192 struct mount * mp;
193 int flags;
194 vfs_context_t context;
195 {
196 DBG_VOP(("synthfs_start called.\n"));
197 return 0;
198 }
199
200 /*
201 * Return the root of a filesystem.
202 */
203 int
204 synthfs_root(mp, vpp, context)
205 struct mount *mp;
206 struct vnode **vpp;
207 vfs_context_t context;
208 {
209 unsigned long root_nodeid = ROOT_DIRID;
210
211 DBG_VOP(("synthfs_root called.\n"));
212
213 *vpp = VFSTOSFS(mp)->synthfs_rootvp;
214 return vnode_get(VFSTOSFS(mp)->synthfs_rootvp);
215 }
216
217 /*
218 * unmount system call
219 */
220 int
221 synthfs_unmount(mp, mntflags, context)
222 struct mount *mp;
223 int mntflags;
224 vfs_context_t context;
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.
238 the ref. count has been maintained at +1 ever since mount time. */
239 if (root_vp) {
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));
245 retval = EBUSY;
246 goto Err_Exit;
247 };
248 };
249
250 synth->synthfs_rootvp = NULL;
251
252 if (retval == 0) {
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 */
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
265 Err_Exit:
266
267 if (mntflags & MNT_FORCE) retval = 0;
268
269 return(retval);
270 }
271
272 /*
273 * Get file system statistics.
274 */
275 int
276 synthfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
277 {
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;
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 */
298 int
299 synthfs_sync(mp, waitfor, context)
300 struct mount *mp;
301 int waitfor;
302 vfs_context_t context;
303 {
304 // DBG_VOP(("synthfs_sync called\n"));
305 return 0;
306 }
307 /*
308 * Look up a synthfs node by node number.
309 */
310 int
311 synthfs_vget(mp, ino, vpp, context)
312 struct mount *mp;
313 ino64_t ino;
314 struct vnode **vpp;
315 vfs_context_t context;
316 {
317 struct vnode *vp;
318 int vid = 0;
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
328 loop:
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 };
344 *vpp = vp;
345 return 0;
346 };
347 };
348 *vpp = NULL;
349 return -1;
350 }
351
352 /*
353 * fast filesystem related variables.
354 */
355 int
356 synthfs_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)
358 {
359 DBG_VOP(("synthfs_sysctl called.\n"));
360 return (ENOTSUP);
361 }
362
363 /*
364 * File handle to vnode
365 *
366 */
367 int
368 synthfs_fhtovp(mp, fhlen, fhp, vpp, context)
369 register struct mount *mp;
370 int fhlen;
371 unsigned char *fhp;
372 struct vnode **vpp;
373 vfs_context_t context;
374 {
375 DBG_VOP(("synthfs_fhtovp called.\n"));
376 return ENOTSUP;
377 }
378
379 /*
380 * Vnode pointer to File handle
381 */
382 /* ARGSUSED */
383 int
384 synthfs_vptofh(vp, fhlenp, fhp, context)
385 struct vnode *vp;
386 int *fhlenp;
387 unsigned char *fhp;
388 vfs_context_t context;
389 {
390 DBG_VOP(("synthfs_vptofh called.\n"));
391 return ENOTSUP;
392 }
393
394
395
396
397
398
399 int
400 vn_mkdir(struct proc *p, char *path, int mode)
401 {
402 struct nameidata nd;
403 struct vnode *vp;
404 struct vnode_attr va;
405 vfs_context_t ctx = vfs_context_kernel();
406 int error;
407
408
409 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), ctx);
410 error = namei(&nd);
411 if (error) {
412 DBG_VOP(("vn_mkdir: error from namei, error = %d.\n", error));
413 return (error);
414 };
415 vp = nd.ni_vp;
416
417 if (vp == NULL) {
418 VATTR_INIT(&va);
419 VATTR_SET(&va, va_type, VDIR);
420 VATTR_SET(&va, va_mode, (mode & ACCESSPERMS) &~ p->p_fd->fd_cmask);
421
422 error = vn_create(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, 0, ctx);
423 if (error)
424 DBG_VOP(("vn_mkdir: error from vnop_mkdir (%d).\n", error));
425 } else {
426 DBG_VOP(("vn_mkdir: target already exists; returning EEXIST.\n"));
427 error = EEXIST;
428 }
429 vnode_put(nd.ni_dvp);
430 if (nd.ni_vp)
431 vnode_put(nd.ni_vp);
432 nameidone(&nd);
433
434 return (error);
435 }
436
437
438
439 int
440 vn_symlink(struct proc *p, char *path, char *link) {
441 struct nameidata nd;
442 struct vnode_attr va;
443 vfs_context_t ctx = vfs_context_kernel();
444 int error;
445
446 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE32, CAST_USER_ADDR_T(link), ctx);
447 if ((error = namei(&nd))) {
448 return error;
449 }
450
451 if (nd.ni_vp == NULL) {
452 VATTR_INIT(&va);
453 VATTR_SET(&va, va_type, VLNK);
454 VATTR_SET(&va, va_mode, ACCESSPERMS &~ p->p_fd->fd_cmask);
455
456 error = VNOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, path, ctx);
457 } else
458 error = EEXIST;
459
460 vnode_put(nd.ni_dvp);
461 if (nd.ni_vp)
462 vnode_put(nd.ni_vp);
463 nameidone(&nd);
464
465 return (error);
466 }
467
468