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: src/sys/ufs/mfs/mfs_vfsops.c,v 1.81.2.3 2001/07/04 17:35:21 tegge Exp $ 35 * $DragonFly: src/sys/vfs/mfs/mfs_vfsops.c,v 1.9 2003/07/26 22:04:26 rob Exp $ 36 */ 37 38 39 #include "opt_mfs.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/conf.h> 44 #include <sys/kernel.h> 45 #include <sys/proc.h> 46 #include <sys/buf.h> 47 #include <sys/mount.h> 48 #include <sys/signalvar.h> 49 #include <sys/vnode.h> 50 #include <sys/malloc.h> 51 #include <sys/linker.h> 52 53 #include <sys/buf2.h> 54 55 #include <ufs/ufs/quota.h> 56 #include <ufs/ufs/inode.h> 57 #include <ufs/ufs/ufsmount.h> 58 #include <ufs/ufs/ufs_extern.h> 59 60 #include <ufs/ffs/fs.h> 61 #include <ufs/ffs/ffs_extern.h> 62 63 #include <ufs/mfs/mfsnode.h> 64 #include <ufs/mfs/mfs_extern.h> 65 66 MALLOC_DEFINE(M_MFSNODE, "MFS node", "MFS vnode private part"); 67 68 69 static int mfs_minor; /* used for building internal dev_t */ 70 71 extern vop_t **mfs_vnodeop_p; 72 73 static int mfs_mount __P((struct mount *mp, 74 char *path, caddr_t data, struct nameidata *ndp, 75 struct thread *td)); 76 static int mfs_start __P((struct mount *mp, int flags, struct thread *td)); 77 static int mfs_statfs __P((struct mount *mp, struct statfs *sbp, 78 struct thread *td)); 79 static int mfs_init __P((struct vfsconf *)); 80 81 #define MFS_CDEV_MAJOR 253 82 83 static struct cdevsw mfs_cdevsw = { 84 /* name */ "MFS", 85 /* maj */ MFS_CDEV_MAJOR, 86 /* flags */ D_DISK, 87 /* port */ NULL, 88 /* autoq */ 0, 89 90 /* open */ noopen, 91 /* close */ noclose, 92 /* read */ physread, 93 /* write */ physwrite, 94 /* ioctl */ noioctl, 95 /* poll */ nopoll, 96 /* mmap */ nommap, 97 /* strategy */ nostrategy, 98 /* dump */ nodump, 99 /* psize */ nopsize 100 }; 101 102 /* 103 * mfs vfs operations. 104 */ 105 static struct vfsops mfs_vfsops = { 106 mfs_mount, 107 mfs_start, 108 ffs_unmount, 109 ufs_root, 110 ufs_quotactl, 111 mfs_statfs, 112 ffs_sync, 113 ffs_vget, 114 ffs_fhtovp, 115 ufs_check_export, 116 ffs_vptofh, 117 mfs_init, 118 vfs_stduninit, 119 vfs_stdextattrctl, 120 }; 121 122 VFS_SET(mfs_vfsops, mfs, 0); 123 124 125 /* 126 * mfs_mount 127 * 128 * Called when mounting local physical media 129 * 130 * PARAMETERS: 131 * mountroot 132 * mp mount point structure 133 * path NULL (flag for root mount!!!) 134 * data <unused> 135 * ndp <unused> 136 * p process (user credentials check [statfs]) 137 * 138 * mount 139 * mp mount point structure 140 * path path to mount point 141 * data pointer to argument struct in user space 142 * ndp mount point namei() return (used for 143 * credentials on reload), reused to look 144 * up block device. 145 * p process (user credentials check) 146 * 147 * RETURNS: 0 Success 148 * !0 error number (errno.h) 149 * 150 * LOCK STATE: 151 * 152 * ENTRY 153 * mount point is locked 154 * EXIT 155 * mount point is locked 156 * 157 * NOTES: 158 * A NULL path can be used for a flag since the mount 159 * system call will fail with EFAULT in copyinstr in 160 * namei() if it is a genuine NULL from the user. 161 */ 162 /* ARGSUSED */ 163 static int 164 mfs_mount(mp, path, data, ndp, td) 165 struct mount *mp; 166 char *path; 167 caddr_t data; 168 struct nameidata *ndp; 169 struct thread *td; 170 { 171 struct vnode *devvp; 172 struct mfs_args args; 173 struct ufsmount *ump; 174 struct fs *fs; 175 struct mfsnode *mfsp; 176 size_t size; 177 int flags, err; 178 dev_t dev; 179 180 /* 181 * Use NULL path to flag a root mount 182 */ 183 if( path == NULL) { 184 /* 185 *** 186 * Mounting root file system 187 *** 188 */ 189 190 /* you lose */ 191 panic("mfs_mount: mount MFS as root: not configured!"); 192 } 193 194 /* 195 *** 196 * Mounting non-root file system or updating a file system 197 *** 198 */ 199 200 /* copy in user arguments*/ 201 if ((err = copyin(data, (caddr_t)&args, sizeof (struct mfs_args))) != 0) 202 goto error_1; 203 204 /* 205 * If updating, check whether changing from read-only to 206 * read/write; if there is no device name, that's all we do. 207 */ 208 if (mp->mnt_flag & MNT_UPDATE) { 209 /* 210 ******************** 211 * UPDATE 212 ******************** 213 */ 214 ump = VFSTOUFS(mp); 215 fs = ump->um_fs; 216 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 217 flags = WRITECLOSE; 218 if (mp->mnt_flag & MNT_FORCE) 219 flags |= FORCECLOSE; 220 err = ffs_flushfiles(mp, flags, td); 221 if (err) 222 goto error_1; 223 } 224 if (fs->fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) 225 fs->fs_ronly = 0; 226 /* if not updating name...*/ 227 if (args.fspec == 0) { 228 /* 229 * Process export requests. Jumping to "success" 230 * will return the vfs_export() error code. 231 */ 232 err = vfs_export(mp, &ump->um_export, &args.export); 233 goto success; 234 } 235 236 /* XXX MFS does not support name updating*/ 237 goto success; 238 } 239 /* 240 * Do the MALLOC before the getnewvnode since doing so afterward 241 * might cause a bogus v_data pointer to get dereferenced 242 * elsewhere if MALLOC should block. 243 */ 244 MALLOC(mfsp, struct mfsnode *, sizeof *mfsp, M_MFSNODE, M_WAITOK); 245 246 err = getnewvnode(VT_MFS, (struct mount *)0, mfs_vnodeop_p, &devvp); 247 if (err) { 248 FREE(mfsp, M_MFSNODE); 249 goto error_1; 250 } 251 devvp->v_type = VCHR; 252 dev = make_dev(&mfs_cdevsw, mfs_minor, 0, 0, 0, "MFS%d", mfs_minor); 253 /* It is not clear that these will get initialized otherwise */ 254 dev->si_bsize_phys = DEV_BSIZE; 255 dev->si_iosize_max = DFLTPHYS; 256 addaliasu(devvp, makeudev(253, mfs_minor++)); 257 devvp->v_data = mfsp; 258 mfsp->mfs_baseoff = args.base; 259 mfsp->mfs_size = args.size; 260 mfsp->mfs_vnode = devvp; 261 mfsp->mfs_td = td; 262 mfsp->mfs_active = 1; 263 bufq_init(&mfsp->buf_queue); 264 265 /* 266 * Since this is a new mount, we want the names for 267 * the device and the mount point copied in. If an 268 * error occurs, the mountpoint is discarded by the 269 * upper level code. 270 */ 271 /* Save "last mounted on" info for mount point (NULL pad)*/ 272 copyinstr( path, /* mount point*/ 273 mp->mnt_stat.f_mntonname, /* save area*/ 274 MNAMELEN - 1, /* max size*/ 275 &size); /* real size*/ 276 bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 277 278 /* Save "mounted from" info for mount point (NULL pad)*/ 279 copyinstr( args.fspec, /* device name*/ 280 mp->mnt_stat.f_mntfromname, /* save area*/ 281 MNAMELEN - 1, /* max size*/ 282 &size); /* real size*/ 283 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 284 285 if ((err = ffs_mountfs(devvp, mp, td, M_MFSNODE)) != 0) { 286 mfsp->mfs_active = 0; 287 goto error_2; 288 } 289 290 /* 291 * Initialize FS stat information in mount struct; uses both 292 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 293 * 294 * This code is common to root and non-root mounts 295 */ 296 (void) VFS_STATFS(mp, &mp->mnt_stat, td); 297 298 goto success; 299 300 error_2: /* error with devvp held*/ 301 302 /* release devvp before failing*/ 303 vrele(devvp); 304 305 error_1: /* no state to back out*/ 306 307 success: 308 return( err); 309 } 310 311 /* 312 * Used to grab the process and keep it in the kernel to service 313 * memory filesystem I/O requests. 314 * 315 * Loop servicing I/O requests. 316 * Copy the requested data into or out of the memory filesystem 317 * address space. 318 */ 319 /* ARGSUSED */ 320 static int 321 mfs_start(struct mount *mp, int flags, struct thread *td) 322 { 323 struct vnode *vp = VFSTOUFS(mp)->um_devvp; 324 struct mfsnode *mfsp = VTOMFS(vp); 325 struct buf *bp; 326 int gotsig = 0, sig; 327 328 /* 329 * We must prevent the system from trying to swap 330 * out or kill ( when swap space is low, see vm/pageout.c ) the 331 * process. A deadlock can occur if the process is swapped out, 332 * and the system can loop trying to kill the unkillable ( while 333 * references exist ) MFS process when swap space is low. 334 */ 335 KKASSERT(curproc); 336 PHOLD(curproc); 337 338 while (mfsp->mfs_active) { 339 int s; 340 341 s = splbio(); 342 343 while ((bp = bufq_first(&mfsp->buf_queue)) != NULL) { 344 bufq_remove(&mfsp->buf_queue, bp); 345 splx(s); 346 mfs_doio(bp, mfsp); 347 wakeup((caddr_t)bp); 348 s = splbio(); 349 } 350 351 splx(s); 352 353 /* 354 * If a non-ignored signal is received, try to unmount. 355 * If that fails, clear the signal (it has been "processed"), 356 * otherwise we will loop here, as tsleep will always return 357 * EINTR/ERESTART. 358 */ 359 /* 360 * Note that dounmount() may fail if work was queued after 361 * we slept. We have to jump hoops here to make sure that we 362 * process any buffers after the sleep, before we dounmount() 363 */ 364 if (gotsig) { 365 gotsig = 0; 366 if (dounmount(mp, 0, td) != 0) { 367 KKASSERT(td->td_proc); 368 sig = CURSIG(td->td_proc); 369 if (sig) 370 SIGDELSET(td->td_proc->p_siglist, sig); 371 } 372 } 373 else if (tsleep((caddr_t)vp, PCATCH, "mfsidl", 0)) 374 gotsig++; /* try to unmount in next pass */ 375 } 376 return (0); 377 } 378 379 /* 380 * Get file system statistics. 381 */ 382 static int 383 mfs_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) 384 { 385 int error; 386 387 error = ffs_statfs(mp, sbp, td); 388 sbp->f_type = mp->mnt_vfc->vfc_typenum; 389 return (error); 390 } 391 392 /* 393 * Memory based filesystem initialization. 394 */ 395 static int 396 mfs_init(vfsp) 397 struct vfsconf *vfsp; 398 { 399 400 cdevsw_add(&mfs_cdevsw); 401 return (0); 402 } 403 404