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