1 /*
2 * Copyright (c) 1989, 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)mfs_vfsops.c 8.11 (Berkeley) 6/19/95
34 * $FreeBSD$
35 */
36
37
38 #include "opt_mfs.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/conf.h>
43 #include <sys/kernel.h>
44 #include <sys/proc.h>
45 #include <sys/buf.h>
46 #include <sys/mount.h>
47 #include <sys/signalvar.h>
48 #include <sys/vnode.h>
49 #include <sys/malloc.h>
50 #include <sys/linker.h>
51
52 #include <ufs/ufs/quota.h>
53 #include <ufs/ufs/inode.h>
54 #include <ufs/ufs/ufsmount.h>
55 #include <ufs/ufs/ufs_extern.h>
56
57 #include <ufs/ffs/fs.h>
58 #include <ufs/ffs/ffs_extern.h>
59
60 #include <ufs/mfs/mfsnode.h>
61 #include <ufs/mfs/mfs_extern.h>
62
63 MALLOC_DEFINE(M_MFSNODE, "MFS node", "MFS vnode private part");
64
65 u_char * mfs_getimage __P((void));
66
67 static caddr_t mfs_rootbase; /* address of mini-root in kernel virtual memory */
68 static u_long mfs_rootsize; /* size of mini-root in bytes */
69
70 static int mfs_minor; /* used for building internal dev_t */
71
72 extern vop_t **mfs_vnodeop_p;
73
74 static int mfs_mount __P((struct mount *mp,
75 char *path, caddr_t data, struct nameidata *ndp,
76 struct proc *p));
77 static int mfs_start __P((struct mount *mp, int flags, struct proc *p));
78 static int mfs_statfs __P((struct mount *mp, struct statfs *sbp,
79 struct proc *p));
80 static int mfs_init __P((struct vfsconf *));
81
82 /*
83 * mfs vfs operations.
84 */
85 static struct vfsops mfs_vfsops = {
86 mfs_mount,
87 mfs_start,
88 ffs_unmount,
89 ufs_root,
90 ufs_quotactl,
91 mfs_statfs,
92 ffs_sync,
93 ffs_vget,
94 ffs_fhtovp,
95 ffs_vptofh,
96 mfs_init,
97 };
98
99 VFS_SET(mfs_vfsops, mfs, 0);
100
101 #ifdef MFS_ROOT
102
103 #ifdef MFS_ROOT_SIZE
104 /* Image was already written into mfs_root */
105 static u_char mfs_root[MFS_ROOT_SIZE*1024] = "MFS Filesystem goes here";
106 static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
107 #endif
108
109 u_char *
110 mfs_getimage(void)
111 {
112 #ifdef MFS_ROOT_SIZE
113 /* Get it from compiled-in code */
114 return mfs_root;
115 #else
116 caddr_t p;
117 vm_offset_t *q;
118
119 p = preload_search_by_type("mfs_root");
120 if (!p)
121 return NULL;
122 q = (vm_offset_t *)preload_search_info(p, MODINFO_ADDR);
123 if (!q)
124 return NULL;
125 return (u_char *)*q;
126 #endif
127 }
128
129 #endif /* MFS_ROOT */
130
131 /*
132 * mfs_mount
133 *
134 * Called when mounting local physical media
135 *
136 * PARAMETERS:
137 * mountroot
138 * mp mount point structure
139 * path NULL (flag for root mount!!!)
140 * data <unused>
141 * ndp <unused>
142 * p process (user credentials check [statfs])
143 *
144 * mount
145 * mp mount point structure
146 * path path to mount point
147 * data pointer to argument struct in user space
148 * ndp mount point namei() return (used for
149 * credentials on reload), reused to look
150 * up block device.
151 * p process (user credentials check)
152 *
153 * RETURNS: 0 Success
154 * !0 error number (errno.h)
155 *
156 * LOCK STATE:
157 *
158 * ENTRY
159 * mount point is locked
160 * EXIT
161 * mount point is locked
162 *
163 * NOTES:
164 * A NULL path can be used for a flag since the mount
165 * system call will fail with EFAULT in copyinstr in
166 * namei() if it is a genuine NULL from the user.
167 */
168 /* ARGSUSED */
169 static int
170 mfs_mount(mp, path, data, ndp, p)
171 register struct mount *mp;
172 char *path;
173 caddr_t data;
174 struct nameidata *ndp;
175 struct proc *p;
176 {
177 struct vnode *devvp;
178 struct mfs_args args;
179 struct ufsmount *ump;
180 struct fs *fs;
181 u_char *base;
182 struct mfsnode *mfsp;
183 u_int size;
184 int flags, err;
185
186 /*
187 * Use NULL path to flag a root mount
188 */
189 if( path == NULL) {
190 /*
191 ***
192 * Mounting root file system
193 ***
194 */
195
196 #ifdef MFS_ROOT
197 /* Get it from preload area */
198 base = mfs_getimage();
199 if (!base)
200 panic("No mfs_root image loaded; can't continue!");
201 fs = (struct fs *)(base + SBOFF);
202 /* check for valid super block */
203 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
204 fs->fs_bsize < sizeof(struct fs)) {
205 panic("MFS image is invalid!!");
206 }
207
208 mfs_rootbase = base;
209 mfs_rootsize = fs->fs_fsize * fs->fs_size;
210 rootdev = makedev(255, mfs_minor++);
211 printf("rootfs is %ld Kbyte compiled in MFS\n",
212 mfs_rootsize/1024);
213 if ((err = bdevvp(rootdev, &rootvp))) {
214 printf("mfs_mountroot: can't find rootvp");
215 return (err);
216 }
217
218 /*
219 * FS specific handling
220 */
221 MALLOC(mfsp, struct mfsnode *, sizeof *mfsp, M_MFSNODE, M_WAITOK);
222 rootvp->v_data = mfsp;
223 rootvp->v_op = mfs_vnodeop_p;
224 rootvp->v_tag = VT_MFS;
225 mfsp->mfs_baseoff = mfs_rootbase;
226 mfsp->mfs_size = mfs_rootsize;
227 mfsp->mfs_vnode = rootvp;
228 mfsp->mfs_pid = p->p_pid;
229 mfsp->mfs_active = 1;
230 bufq_init(&mfsp->buf_queue);
231
232 /* MFS wants to be read/write */
233 mp->mnt_flag &= ~MNT_RDONLY;
234
235 /*
236 * Attempt mount
237 */
238 if( (err = ffs_mountfs(rootvp, mp, p, M_MFSNODE)) != 0 ) {
239 /* fs specific cleanup (if any)*/
240 rootvp->v_data = NULL;
241 FREE(mfsp, M_MFSNODE);
242 goto error_1;
243 }
244
245 goto dostatfs; /* success*/
246 #else /* !MFS_ROOT */
247 /* you loose */
248 panic("mfs_mount: mount MFS as root: not configured!");
249 #endif /* MFS_ROOT */
250 }
251
252 /*
253 ***
254 * Mounting non-root file system or updating a file system
255 ***
256 */
257
258 /* copy in user arguments*/
259 if (err = copyin(data, (caddr_t)&args, sizeof (struct mfs_args)))
260 goto error_1;
261
262 /*
263 * If updating, check whether changing from read-only to
264 * read/write; if there is no device name, that's all we do.
265 */
266 if (mp->mnt_flag & MNT_UPDATE) {
267 /*
268 ********************
269 * UPDATE
270 ********************
271 */
272 ump = VFSTOUFS(mp);
273 fs = ump->um_fs;
274 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
275 flags = WRITECLOSE;
276 if (mp->mnt_flag & MNT_FORCE)
277 flags |= FORCECLOSE;
278 err = ffs_flushfiles(mp, flags, p);
279 if (err)
280 goto error_1;
281 }
282 if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR))
283 fs->fs_ronly = 0;
284 #ifdef EXPORTMFS
285 /* if not updating name...*/
286 if (args.fspec == 0) {
287 /*
288 * Process export requests. Jumping to "success"
289 * will return the vfs_export() error code.
290 */
291 err = vfs_export(mp, &ump->um_export, &args.export);
292 goto success;
293 }
294 #endif
295
296 /* XXX MFS does not support name updating*/
297 goto success;
298 }
299 /*
300 * Do the MALLOC before the getnewvnode since doing so afterward
301 * might cause a bogus v_data pointer to get dereferenced
302 * elsewhere if MALLOC should block.
303 */
304 MALLOC(mfsp, struct mfsnode *, sizeof *mfsp, M_MFSNODE, M_WAITOK);
305
306 err = getnewvnode(VT_MFS, (struct mount *)0, mfs_vnodeop_p, &devvp);
307 if (err) {
308 FREE(mfsp, M_MFSNODE);
309 goto error_1;
310 }
311 devvp->v_type = VBLK;
312 if (checkalias(devvp, makedev(255, mfs_minor++), (struct mount *)0))
313 panic("mfs_mount: dup dev");
314 devvp->v_data = mfsp;
315 mfsp->mfs_baseoff = args.base;
316 mfsp->mfs_size = args.size;
317 mfsp->mfs_vnode = devvp;
318 mfsp->mfs_pid = p->p_pid;
319 mfsp->mfs_active = 1;
320 bufq_init(&mfsp->buf_queue);
321
322 /*
323 * Since this is a new mount, we want the names for
324 * the device and the mount point copied in. If an
325 * error occurs, the mountpoint is discarded by the
326 * upper level code.
327 */
328 /* Save "last mounted on" info for mount point (NULL pad)*/
329 copyinstr( path, /* mount point*/
330 mp->mnt_stat.f_mntonname, /* save area*/
331 MNAMELEN - 1, /* max size*/
332 &size); /* real size*/
333 bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
334
335 /* Save "mounted from" info for mount point (NULL pad)*/
336 copyinstr( args.fspec, /* device name*/
337 mp->mnt_stat.f_mntfromname, /* save area*/
338 MNAMELEN - 1, /* max size*/
339 &size); /* real size*/
340 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
341
342 if (err = ffs_mountfs(devvp, mp, p, M_MFSNODE)) {
343 mfsp->mfs_active = 0;
344 goto error_2;
345 }
346
347 dostatfs:
348 /*
349 * Initialize FS stat information in mount struct; uses both
350 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
351 *
352 * This code is common to root and non-root mounts
353 */
354 (void) VFS_STATFS(mp, &mp->mnt_stat, p);
355
356 goto success;
357
358 error_2: /* error with devvp held*/
359
360 /* release devvp before failing*/
361 vrele(devvp);
362
363 error_1: /* no state to back out*/
364
365 success:
366 return( err);
367 }
368
369
370 static int mfs_pri = PWAIT | PCATCH; /* XXX prob. temp */
371
372 /*
373 * Used to grab the process and keep it in the kernel to service
374 * memory filesystem I/O requests.
375 *
376 * Loop servicing I/O requests.
377 * Copy the requested data into or out of the memory filesystem
378 * address space.
379 */
380 /* ARGSUSED */
381 static int
382 mfs_start(mp, flags, p)
383 struct mount *mp;
384 int flags;
385 struct proc *p;
386 {
387 register struct vnode *vp = VFSTOUFS(mp)->um_devvp;
388 register struct mfsnode *mfsp = VTOMFS(vp);
389 register struct buf *bp;
390 register caddr_t base;
391 register int gotsig = 0;
392
393 base = mfsp->mfs_baseoff;
394
395 /*
396 * We must set P_NOSWAP to prevent the system from trying to swap
397 * out or kill ( when swap space is low, see vm/pageout.c ) the
398 * process. A deadlock can occur if the process is swapped out,
399 * and the system can loop trying to kill the unkillable ( while
400 * references exist ) MFS process when swap space is low.
401 */
402 curproc->p_flag |= P_NOSWAP;
403
404 while (mfsp->mfs_active) {
405 int s;
406
407 s = splbio();
408 while (bp = bufq_first(&mfsp->buf_queue)) {
409 bufq_remove(&mfsp->buf_queue, bp);
410 splx(s);
411 mfs_doio(bp, base);
412 wakeup((caddr_t)bp);
413 s = splbio();
414 }
415 splx(s);
416
417 /*
418 * If a non-ignored signal is received, try to unmount.
419 * If that fails, clear the signal (it has been "processed"),
420 * otherwise we will loop here, as tsleep will always return
421 * EINTR/ERESTART.
422 */
423 /*
424 * Note that dounmount() may fail if work was queued after
425 * we slept. We have to jump hoops here to make sure that we
426 * process any buffers after the sleep, before we dounmount()
427 */
428 if (gotsig) {
429 gotsig = 0;
430 if (dounmount(mp, 0, p) != 0)
431 CLRSIG(p, CURSIG(p)); /* try sleep again.. */
432 }
433 else if (tsleep((caddr_t)vp, mfs_pri, "mfsidl", 0))
434 gotsig++; /* try to unmount in next pass */
435 }
436 return (0);
437 }
438
439 /*
440 * Get file system statistics.
441 */
442 static int
443 mfs_statfs(mp, sbp, p)
444 struct mount *mp;
445 struct statfs *sbp;
446 struct proc *p;
447 {
448 int error;
449
450 error = ffs_statfs(mp, sbp, p);
451 sbp->f_type = mp->mnt_vfc->vfc_typenum;
452 return (error);
453 }
454
455 /*
456 * Memory based filesystem initialization.
457 */
458 static int
459 mfs_init(vfsp)
460 struct vfsconf *vfsp;
461 {
462 return (0);
463 }
Cache object: f4d0ca6af33611987ba2bea84414149d
|