mfs_vfsops.c revision 1.39
1/* $NetBSD: mfs_vfsops.c,v 1.39 2002/07/19 16:26:01 hannken Exp $ */ 2 3/* 4 * Copyright (c) 1989, 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)mfs_vfsops.c 8.11 (Berkeley) 6/19/95 36 */ 37 38#include <sys/cdefs.h> 39__KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.39 2002/07/19 16:26:01 hannken Exp $"); 40 41#if defined(_KERNEL_OPT) 42#include "opt_compat_netbsd.h" 43#endif 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/time.h> 48#include <sys/kernel.h> 49#include <sys/proc.h> 50#include <sys/buf.h> 51#include <sys/mount.h> 52#include <sys/signalvar.h> 53#include <sys/vnode.h> 54#include <sys/malloc.h> 55 56#include <miscfs/syncfs/syncfs.h> 57 58#include <ufs/ufs/quota.h> 59#include <ufs/ufs/inode.h> 60#include <ufs/ufs/ufsmount.h> 61#include <ufs/ufs/ufs_extern.h> 62 63#include <ufs/ffs/fs.h> 64#include <ufs/ffs/ffs_extern.h> 65 66#include <ufs/mfs/mfsnode.h> 67#include <ufs/mfs/mfs_extern.h> 68 69caddr_t mfs_rootbase; /* address of mini-root in kernel virtual memory */ 70u_long mfs_rootsize; /* size of mini-root in bytes */ 71 72static int mfs_minor; /* used for building internal dev_t */ 73 74extern int (**mfs_vnodeop_p) __P((void *)); 75 76/* 77 * mfs vfs operations. 78 */ 79 80extern const struct vnodeopv_desc mfs_vnodeop_opv_desc; 81 82const struct vnodeopv_desc * const mfs_vnodeopv_descs[] = { 83 &mfs_vnodeop_opv_desc, 84 NULL, 85}; 86 87struct vfsops mfs_vfsops = { 88 MOUNT_MFS, 89 mfs_mount, 90 mfs_start, 91 ffs_unmount, 92 ufs_root, 93 ufs_quotactl, 94 mfs_statfs, 95 ffs_sync, 96 ffs_vget, 97 ffs_fhtovp, 98 ffs_vptofh, 99 mfs_init, 100 mfs_reinit, 101 mfs_done, 102 ffs_sysctl, 103 NULL, 104 ufs_check_export, 105 mfs_vnodeopv_descs, 106}; 107 108/* 109 * Memory based filesystem initialization. 110 */ 111void 112mfs_init() 113{ 114 /* 115 * ffs_init() ensures to initialize necessary resources 116 * only once. 117 */ 118 ffs_init(); 119} 120 121void 122mfs_reinit() 123{ 124 ffs_reinit(); 125} 126 127void 128mfs_done() 129{ 130 /* 131 * ffs_done() ensures to free necessary resources 132 * only once, when it's no more needed. 133 */ 134 ffs_done(); 135} 136 137/* 138 * Called by main() when mfs is going to be mounted as root. 139 */ 140 141int 142mfs_mountroot() 143{ 144 struct fs *fs; 145 struct mount *mp; 146 struct proc *p = curproc; /* XXX */ 147 struct ufsmount *ump; 148 struct mfsnode *mfsp; 149 int error = 0; 150 151 /* 152 * Get vnodes for rootdev. 153 */ 154 if (bdevvp(rootdev, &rootvp)) { 155 printf("mfs_mountroot: can't setup bdevvp's"); 156 return (error); 157 } 158 159 if ((error = vfs_rootmountalloc(MOUNT_MFS, "mfs_root", &mp))) { 160 vrele(rootvp); 161 return (error); 162 } 163 164 mfsp = malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK); 165 rootvp->v_data = mfsp; 166 rootvp->v_op = mfs_vnodeop_p; 167 rootvp->v_tag = VT_MFS; 168 mfsp->mfs_baseoff = mfs_rootbase; 169 mfsp->mfs_size = mfs_rootsize; 170 mfsp->mfs_vnode = rootvp; 171 mfsp->mfs_proc = NULL; /* indicate kernel space */ 172 mfsp->mfs_shutdown = 0; 173 bufq_init(&mfsp->mfs_buflist, BUFQ_FCFS); 174 if ((error = ffs_mountfs(rootvp, mp, p)) != 0) { 175 mp->mnt_op->vfs_refcount--; 176 vfs_unbusy(mp); 177 free(mp, M_MOUNT); 178 free(mfsp, M_MFSNODE); 179 vrele(rootvp); 180 return (error); 181 } 182 simple_lock(&mountlist_slock); 183 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 184 simple_unlock(&mountlist_slock); 185 mp->mnt_vnodecovered = NULLVP; 186 ump = VFSTOUFS(mp); 187 fs = ump->um_fs; 188 (void) copystr(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN - 1, 0); 189 (void)ffs_statfs(mp, &mp->mnt_stat, p); 190 vfs_unbusy(mp); 191 inittodr((time_t)0); 192 return (0); 193} 194 195/* 196 * This is called early in boot to set the base address and size 197 * of the mini-root. 198 */ 199int 200mfs_initminiroot(base) 201 caddr_t base; 202{ 203 struct fs *fs = (struct fs *)(base + SBOFF); 204 205 /* check for valid super block */ 206 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 207 fs->fs_bsize < sizeof(struct fs)) 208 return (0); 209 mountroot = mfs_mountroot; 210 mfs_rootbase = base; 211 mfs_rootsize = fs->fs_fsize * fs->fs_size; 212 rootdev = makedev(255, mfs_minor); 213 mfs_minor++; 214 return (mfs_rootsize); 215} 216 217/* 218 * VFS Operations. 219 * 220 * mount system call 221 */ 222/* ARGSUSED */ 223int 224mfs_mount(mp, path, data, ndp, p) 225 struct mount *mp; 226 const char *path; 227 void *data; 228 struct nameidata *ndp; 229 struct proc *p; 230{ 231 struct vnode *devvp; 232 struct mfs_args args; 233 struct ufsmount *ump; 234 struct fs *fs; 235 struct mfsnode *mfsp; 236 size_t size; 237 int flags, error; 238 239 /* 240 * XXX turn off async to avoid hangs when writing lots of data. 241 * the problem is that MFS needs to allocate pages to clean pages, 242 * so if we wait until the last minute to clean pages then there 243 * may not be any pages available to do the cleaning. 244 */ 245 mp->mnt_flag &= ~MNT_ASYNC; 246 247 error = copyin(data, (caddr_t)&args, sizeof (struct mfs_args)); 248 if (error) 249 return (error); 250 251 /* 252 * If updating, check whether changing from read-only to 253 * read/write; if there is no device name, that's all we do. 254 */ 255 if (mp->mnt_flag & MNT_UPDATE) { 256 ump = VFSTOUFS(mp); 257 fs = ump->um_fs; 258 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 259 flags = WRITECLOSE; 260 if (mp->mnt_flag & MNT_FORCE) 261 flags |= FORCECLOSE; 262 error = ffs_flushfiles(mp, flags, p); 263 if (error) 264 return (error); 265 } 266 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) 267 fs->fs_ronly = 0; 268 if (args.fspec == 0) 269 return (vfs_export(mp, &ump->um_export, &args.export)); 270 return (0); 271 } 272 error = getnewvnode(VT_MFS, (struct mount *)0, mfs_vnodeop_p, &devvp); 273 if (error) 274 return (error); 275 devvp->v_type = VBLK; 276 if (checkalias(devvp, makedev(255, mfs_minor), (struct mount *)0)) 277 panic("mfs_mount: dup dev"); 278 mfs_minor++; 279 mfsp = (struct mfsnode *)malloc(sizeof *mfsp, M_MFSNODE, M_WAITOK); 280 devvp->v_data = mfsp; 281 mfsp->mfs_baseoff = args.base; 282 mfsp->mfs_size = args.size; 283 mfsp->mfs_vnode = devvp; 284 mfsp->mfs_proc = p; 285 mfsp->mfs_shutdown = 0; 286 bufq_init(&mfsp->mfs_buflist, BUFQ_FCFS); 287 if ((error = ffs_mountfs(devvp, mp, p)) != 0) { 288 mfsp->mfs_shutdown = 1; 289 vrele(devvp); 290 return (error); 291 } 292 ump = VFSTOUFS(mp); 293 fs = ump->um_fs; 294 (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 295 memset(fs->fs_fsmnt + size, 0, sizeof(fs->fs_fsmnt) - size); 296 memcpy(mp->mnt_stat.f_mntonname, fs->fs_fsmnt, MNAMELEN); 297 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 298 &size); 299 memset(mp->mnt_stat.f_mntfromname + size, 0, MNAMELEN - size); 300 return (0); 301} 302 303int mfs_pri = PWAIT | PCATCH; /* XXX prob. temp */ 304 305/* 306 * Used to grab the process and keep it in the kernel to service 307 * memory filesystem I/O requests. 308 * 309 * Loop servicing I/O requests. 310 * Copy the requested data into or out of the memory filesystem 311 * address space. 312 */ 313/* ARGSUSED */ 314int 315mfs_start(mp, flags, p) 316 struct mount *mp; 317 int flags; 318 struct proc *p; 319{ 320 struct vnode *vp = VFSTOUFS(mp)->um_devvp; 321 struct mfsnode *mfsp = VTOMFS(vp); 322 struct buf *bp; 323 caddr_t base; 324 int sleepreturn = 0; 325 326 base = mfsp->mfs_baseoff; 327 while (mfsp->mfs_shutdown != 1) { 328 while ((bp = BUFQ_GET(&mfsp->mfs_buflist)) != NULL) { 329 mfs_doio(bp, base); 330 wakeup((caddr_t)bp); 331 } 332 /* 333 * If a non-ignored signal is received, try to unmount. 334 * If that fails, or the filesystem is already in the 335 * process of being unmounted, clear the signal (it has been 336 * "processed"), otherwise we will loop here, as tsleep 337 * will always return EINTR/ERESTART. 338 */ 339 if (sleepreturn != 0) { 340 /* 341 * XXX Freeze syncer. Must do this before locking 342 * the mount point. See dounmount() for details. 343 */ 344 lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL); 345 if (vfs_busy(mp, LK_NOWAIT, 0) != 0) 346 lockmgr(&syncer_lock, LK_RELEASE, NULL); 347 else if (dounmount(mp, 0, p) != 0) 348 CLRSIG(p, CURSIG(p)); 349 sleepreturn = 0; 350 continue; 351 } 352 353 sleepreturn = tsleep(vp, mfs_pri, "mfsidl", 0); 354 } 355 KASSERT(BUFQ_PEEK(&mfsp->mfs_buflist) == NULL); 356 return (sleepreturn); 357} 358 359/* 360 * Get file system statistics. 361 */ 362int 363mfs_statfs(mp, sbp, p) 364 struct mount *mp; 365 struct statfs *sbp; 366 struct proc *p; 367{ 368 int error; 369 370 error = ffs_statfs(mp, sbp, p); 371#ifdef COMPAT_09 372 sbp->f_type = 3; 373#else 374 sbp->f_type = 0; 375#endif 376 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 377 return (error); 378} 379