]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/volfs/volfs_vfsops.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / miscfs / volfs / volfs_vfsops.c
1 /*
2 * Copyright (c) 1998-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
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/namei.h>
27 #include <sys/proc.h>
28 #include <sys/kernel.h>
29 #include <mach/machine/vm_types.h>
30 #include <sys/vnode.h>
31 #include <sys/socket.h>
32 #include <sys/mount_internal.h>
33 #include <sys/mbuf.h>
34 #include <sys/file.h>
35 #include <sys/disk.h>
36 #include <sys/ioctl.h>
37 #include <sys/errno.h>
38 #include <sys/malloc.h>
39 #include <dev/ldd.h>
40
41 #include <miscfs/specfs/specdev.h>
42 #include "volfs.h"
43
44 static int volfs_mount(struct mount *, vnode_t , user_addr_t, vfs_context_t);
45 static int volfs_start(struct mount *, int, vfs_context_t);
46 static int volfs_unmount(struct mount *, int, vfs_context_t);
47 static int volfs_root(struct mount *, struct vnode **, vfs_context_t);
48 static int volfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context);
49 static int volfs_sync(struct mount *, int, vfs_context_t);
50 static int volfs_vget(struct mount *, ino64_t, struct vnode **, vfs_context_t);
51 static int volfs_fhtovp(struct mount *, int, unsigned char *, struct vnode **, vfs_context_t);
52 static int volfs_vptofh(struct vnode *, int *, unsigned char *, vfs_context_t);
53 static int volfs_init(struct vfsconf *);
54 static int volfs_sysctl(int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, vfs_context_t);
55 void volfs_load(int loadArgument);
56
57
58 struct vfsops volfs_vfsops = {
59 volfs_mount,
60 volfs_start,
61 volfs_unmount,
62 volfs_root,
63 NULL, /* quotactl */
64 volfs_vfs_getattr,
65 volfs_sync,
66 volfs_vget,
67 volfs_fhtovp,
68 volfs_vptofh,
69 volfs_init,
70 volfs_sysctl
71 };
72
73 // static char volfs_fs_name[MFSNAMELEN] = "volfs";
74 extern struct vnodeopv_desc volfs_vnodeop_opv_desc;
75
76 extern int (**volfs_vnodeop_p)(void *);
77
78 /* The following refer to kernel global variables used in the loading/initialization: */
79 extern int vfs_opv_numops; /* The total number of defined vnode operations */
80 extern int kdp_flag;
81
82 void
83 volfs_load(__unused int loadArgument)
84 {
85 #if 0
86 struct vfsconf *vfsconflistentry;
87 int entriesRemaining;
88 struct vfsconf *newvfsconf = NULL;
89 struct vfsconf *lastentry = NULL;
90 int j;
91 int (***opv_desc_vector_p)();
92 int (**opv_desc_vector)();
93 struct vnodeopv_entry_desc *opve_descp;
94
95 /*
96 * This routine is responsible for all the initialization that would
97 * ordinarily be done as part of the system startup; it calls volfs_init
98 * to do the initialization that is strictly volfs-specific.
99 */
100
101 /*
102 prevvfsconf is supposed to be the entry preceding the new entry.
103 To make sure we can always get hooked in SOMEWHERE in the list,
104 start it out at the first entry of the list. This assumes the
105 first entry in the list will be non-empty and not volfs.
106
107 This becomes irrelevant when volfs is compiled into the list.
108 */
109 vfsconflistentry = vfsconf;
110 for (entriesRemaining = maxvfsslots; entriesRemaining > 0; --entriesRemaining) {
111 if (vfsconflistentry->vfc_vfsops != NULL) {
112 /*
113 * Check to see if we're reloading a new version of volfs during debugging
114 * and overwrite the previously assigned entry if we find one:
115 */
116 if (strcmp(vfsconflistentry->vfc_name, volfs_fs_name) == 0) {
117 newvfsconf = vfsconflistentry;
118 break;
119 } else {
120 lastentry = vfsconflistentry;
121 };
122 } else {
123 /*
124 * This is at least a POSSIBLE place to insert the new entry...
125 */
126 newvfsconf = vfsconflistentry;
127 };
128 ++vfsconflistentry;
129 };
130
131 if (newvfsconf) {
132 newvfsconf->vfc_vfsops = &volfs_vfsops;
133 strncpy(&newvfsconf->vfc_name[0], "volfs", MFSNAMELEN);
134 newvfsconf->vfc_typenum = maxvfsconf++;
135 newvfsconf->vfc_refcount = 0;
136 newvfsconf->vfc_flags = 0;
137 newvfsconf->vfc_mountroot = NULL; /* Can't mount root of file system [yet] */
138
139 /* Hook into the list: */
140 newvfsconf->vfc_next = NULL;
141 if (lastentry) {
142 newvfsconf->vfc_next = lastentry->vfc_next;
143 lastentry->vfc_next = newvfsconf;
144 };
145
146 /* Based on vfs_op_init and ... */
147 opv_desc_vector_p = volfs_vnodeop_opv_desc.opv_desc_vector_p;
148
149 /*
150 * Allocate and init the vector.
151 * Also handle backwards compatibility.
152 */
153 MALLOC(*opv_desc_vector_p, PFI *, vfs_opv_numops*sizeof(PFI), M_TEMP, M_WAITOK);
154
155 bzero (*opv_desc_vector_p, vfs_opv_numops*sizeof(PFI));
156
157 opv_desc_vector = *opv_desc_vector_p;
158 for (j=0; volfs_vnodeop_opv_desc.opv_desc_ops[j].opve_op; j++) {
159 opve_descp = &(volfs_vnodeop_opv_desc.opv_desc_ops[j]);
160
161 /*
162 * Sanity check: is this operation listed
163 * in the list of operations? We check this
164 * by seeing if its offest is zero. Since
165 * the default routine should always be listed
166 * first, it should be the only one with a zero
167 * offset. Any other operation with a zero
168 * offset is probably not listed in
169 * vfs_op_descs, and so is probably an error.
170 *
171 * A panic here means the layer programmer
172 * has committed the all-too common bug
173 * of adding a new operation to the layer's
174 * list of vnode operations but
175 * not adding the operation to the system-wide
176 * list of supported operations.
177 */
178 if (opve_descp->opve_op->vdesc_offset == 0 &&
179 opve_descp->opve_op->vdesc_offset != VOFFSET(vnop_default)) {
180 panic ("load_volfs: bad operation");
181 }
182 /*
183 * Fill in this entry.
184 */
185 opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
186 opve_descp->opve_impl;
187 }
188
189 /*
190 * Finally, go back and replace unfilled routines
191 * with their default. (Sigh, an O(n^3) algorithm. I
192 * could make it better, but that'd be work, and n is small.)
193 */
194 opv_desc_vector_p = volfs_vnodeop_opv_desc.opv_desc_vector_p;
195
196 /*
197 * Force every operations vector to have a default routine.
198 */
199 opv_desc_vector = *opv_desc_vector_p;
200 if (opv_desc_vector[VOFFSET(vnop_default)]==NULL) {
201 panic("load_vp;fs: operation vector without default routine.");
202 }
203 for (j = 0;j<vfs_opv_numops; j++)
204 if (opv_desc_vector[j] == NULL)
205 opv_desc_vector[j] =
206 opv_desc_vector[VOFFSET(vnop_default)];
207
208 volfs_init(newvfsconf);
209 };
210 #else
211 panic("volfs load not ported");
212 #endif
213 }
214
215 /*
216 * VFS Operations.
217 *
218 * mount system call
219 */
220 static int
221 volfs_mount(struct mount *mp, __unused vnode_t devvp, __unused user_addr_t data, __unused vfs_context_t context)
222 {
223 struct volfs_mntdata *priv_mnt_data;
224 struct vnode *root_vp;
225 struct volfs_vndata *priv_vn_data;
226 int error;
227 struct vnode_fsparam vfsp;
228
229 MALLOC(priv_mnt_data, struct volfs_mntdata *, sizeof(struct volfs_mntdata),
230 M_VOLFSMNT, M_WAITOK);
231
232 mp->mnt_data = (void *)priv_mnt_data;
233 strcpy(mp->mnt_vfsstat.f_fstypename, "volfs");
234 strcpy(mp->mnt_vfsstat.f_mntfromname, "<volfs>");
235
236 /* Set up the root vnode for fast reference in the future.
237 Note that the root is maintained unlocked but with a pos. ref count until unmount. */
238
239 MALLOC(priv_vn_data, struct volfs_vndata *, sizeof(struct volfs_vndata), M_VOLFSNODE, M_WAITOK);
240
241 priv_vn_data->vnode_type = VOLFS_ROOT;
242 priv_vn_data->nodeID = ROOT_DIRID;
243 priv_vn_data->fs_mount = mp;
244 priv_vn_data->fs_fsid = mp->mnt_vfsstat.f_fsid;
245
246 vfsp.vnfs_mp = mp;
247 vfsp.vnfs_vtype = VDIR;
248 vfsp.vnfs_str = "volfs";
249 vfsp.vnfs_dvp = 0;
250 vfsp.vnfs_fsnode = priv_vn_data;
251 vfsp.vnfs_cnp = 0;
252 vfsp.vnfs_vops = volfs_vnodeop_p;
253 vfsp.vnfs_rdev = 0;
254 vfsp.vnfs_filesize = 0;
255 vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
256 vfsp.vnfs_marksystem = 0;
257 vfsp.vnfs_markroot = 1;
258
259 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, &root_vp);
260 if (error != 0) {
261 FREE(priv_mnt_data, M_VOLFSMNT);
262 FREE(priv_vn_data, M_VOLFSNODE);
263 return(error);
264 }
265 vnode_ref(root_vp);
266 vnode_put(root_vp);
267
268 /* obtain a new fsid for the mount point */
269 vfs_getnewfsid(mp);
270
271 vnode_settag(root_vp, VT_VOLFS);
272
273 priv_mnt_data->volfs_rootvp = root_vp;
274 mp->mnt_flag &= ~MNT_RDONLY;
275
276 mp->mnt_vtable->vfc_threadsafe = TRUE;
277
278 return (0);
279 }
280
281 static int
282 volfs_start(__unused struct mount * mp, __unused int flags, __unused vfs_context_t context)
283 {
284 return (0);
285 }
286
287 /*
288 * Return the root of a filesystem. For volfs the root vnode is a directory
289 * containing the list of all filesystems volfs can work with.
290 */
291 static int
292 volfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t context)
293 {
294 struct volfs_mntdata *priv_data;
295
296 priv_data = (struct volfs_mntdata *)mp->mnt_data;
297
298 if (priv_data->volfs_rootvp) {
299 vnode_get(priv_data->volfs_rootvp);
300 *vpp = priv_data->volfs_rootvp;
301 } else {
302 panic("volfs: root vnode missing!");
303 };
304
305 return(0);
306 }
307
308 /*
309 * unmount system call
310 */
311 static int
312 volfs_unmount(struct mount *mp, __unused int mntflags, __unused vfs_context_t context)
313 {
314 struct volfs_mntdata *priv_data;
315 struct vnode *root_vp;
316 int retval;
317
318 priv_data = (struct volfs_mntdata *)mp->mnt_data;
319
320 root_vp = priv_data->volfs_rootvp;
321 retval = vflush(mp, root_vp, 0);
322 if (retval) goto Err_Exit;
323
324 /* Free the root vnode.
325 Note that there's no need to vget() or vref() it before locking it here:
326 the ref. count has been maintained at +1 ever since mount time. */
327 if (root_vp) {
328 if (vnode_isinuse(root_vp, 1)) {
329 retval = EBUSY;
330 goto Err_Exit;
331 };
332
333 priv_data->volfs_rootvp = NULL;
334 vnode_rele(root_vp); /* This drops volfs's own refcount */
335 vnode_reclaim(root_vp);
336 };
337
338 /* All vnodes should be gone, and no errors, clean up the last */
339
340 mp->mnt_data = NULL;
341 FREE(priv_data, M_VOLFSMNT);
342
343 Err_Exit:
344
345 return(retval);
346 }
347
348 /*
349 * Get file system statistics.
350 */
351 static int
352 volfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t context)
353 {
354 VFSATTR_RETURN(fsap, f_bsize, 512);
355 VFSATTR_RETURN(fsap, f_iosize, 512);
356 VFSATTR_RETURN(fsap, f_blocks, 1024);
357 VFSATTR_RETURN(fsap, f_bfree, 0);
358 VFSATTR_RETURN(fsap, f_bavail, 0);
359 VFSATTR_RETURN(fsap, f_bused, 1024);
360 VFSATTR_RETURN(fsap, f_files, 0);
361 VFSATTR_RETURN(fsap, f_ffree, 0);
362 VFSATTR_RETURN(fsap, f_fssubtype, 0);
363 return 0;
364 }
365
366 /*
367 * volfs doesn't have any data and you can't write into any of the volfs
368 * structures, so don't do anything
369 */
370 static int
371 volfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t context)
372 {
373 return 0;
374 }
375
376 /*
377 *
378 */
379 static int
380 volfs_vget(__unused struct mount *mp, __unused ino64_t ino,
381 __unused struct vnode **vpp, __unused vfs_context_t context)
382 {
383 return(ENOTSUP);
384 }
385
386 /*
387 * File handle to vnode
388 */
389 static int
390 volfs_fhtovp(__unused struct mount *mp, __unused int fhlen,
391 __unused unsigned char *fhp, __unused struct vnode **vpp,
392 __unused vfs_context_t context)
393 {
394 return(ENOTSUP);
395 }
396
397 /*
398 * Vnode pointer to File handle
399 */
400 static int
401 volfs_vptofh(__unused struct vnode *vp, __unused int *fhlenp, __unused unsigned char *fhp, __unused vfs_context_t context)
402 {
403 return(ENOTSUP);
404 }
405
406 /*
407 * Initialize the filesystem
408 */
409 static int
410 volfs_init(__unused struct vfsconf *vfsp)
411 {
412 return (0);
413 }
414
415 /*
416 * fast filesystem related variables.
417 */
418 static int
419 volfs_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp,
420 __unused size_t *oldlenp, __unused user_addr_t newp, __unused size_t newlen,
421 __unused vfs_context_t context)
422 {
423 return (ENOTSUP);
424 }
425