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