2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39
40 #pragma ident "@(#)ufs_vfsops.c 2.275 07/10/25 SMI"
41
42 #include <sys/types.h>
43 #include <sys/t_lock.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/bitmap.h>
47 #include <sys/sysmacros.h>
48 #include <sys/kmem.h>
49 #include <sys/signal.h>
50 #include <sys/user.h>
51 #include <sys/proc.h>
52 #include <sys/disp.h>
53 #include <sys/buf.h>
54 #include <sys/pathname.h>
55 #include <sys/vfs.h>
56 #include <sys/vfs_opreg.h>
57 #include <sys/vnode.h>
58 #include <sys/file.h>
59 #include <sys/atomic.h>
60 #include <sys/uio.h>
249 return (mod_info(&modlinkage, modinfop));
250 }
251
252 extern struct vnode *makespecvp(dev_t dev, vtype_t type);
253
254 extern kmutex_t ufs_scan_lock;
255
256 static int mountfs(struct vfs *, enum whymountroot, struct vnode *, char *,
257 struct cred *, int, void *, int);
258
259
260 static int
261 ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
262 struct cred *cr)
263
264 {
265 char *data = uap->dataptr;
266 int datalen = uap->datalen;
267 dev_t dev;
268 struct vnode *bvp;
269 struct pathname dpn;
270 int error;
271 enum whymountroot why = ROOT_INIT;
272 struct ufs_args args;
273 int oflag, aflag;
274 int fromspace = (uap->flags & MS_SYSSPACE) ?
275 UIO_SYSSPACE : UIO_USERSPACE;
276
277 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
278 return (error);
279
280 if (mvp->v_type != VDIR)
281 return (ENOTDIR);
282
283 mutex_enter(&mvp->v_lock);
284 if ((uap->flags & MS_REMOUNT) == 0 &&
285 (uap->flags & MS_OVERLAY) == 0 &&
286 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
287 mutex_exit(&mvp->v_lock);
288 return (EBUSY);
291
292 /*
293 * Get arguments
294 */
295 bzero(&args, sizeof (args));
296 if ((uap->flags & MS_DATA) && data != NULL && datalen != 0) {
297 int copy_result = 0;
298
299 if (datalen > sizeof (args))
300 return (EINVAL);
301 if (uap->flags & MS_SYSSPACE)
302 bcopy(data, &args, datalen);
303 else
304 copy_result = copyin(data, &args, datalen);
305 if (copy_result)
306 return (EFAULT);
307 datalen = sizeof (struct ufs_args);
308 } else {
309 datalen = 0;
310 }
311 /*
312 * Read in the mount point pathname
313 * (so we can record the directory the file system was last mounted on).
314 */
315 if (error = pn_get(uap->dir, fromspace, &dpn))
316 return (error);
317
318 /*
319 * Resolve path name of special file being mounted.
320 */
321 if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp)) {
322 pn_free(&dpn);
323 return (error);
324 }
325 if (bvp->v_type != VBLK) {
326 VN_RELE(bvp);
327 pn_free(&dpn);
328 return (ENOTBLK);
329 }
330 dev = bvp->v_rdev;
331 if (getmajor(dev) >= devcnt) {
332 pn_free(&dpn);
333 VN_RELE(bvp);
334 return (ENXIO);
335 }
336 if (uap->flags & MS_REMOUNT)
337 why = ROOT_REMOUNT;
338
339 /*
340 * In SunCluster, requests to a global device are satisfied by
341 * a local device. We substitute the global pxfs node with a
342 * local spec node here.
343 */
344 if (IS_PXFSVP(bvp)) {
345 VN_RELE(bvp);
346 bvp = makespecvp(dev, VBLK);
347 }
348
349 /*
350 * Open block device mounted on. We need this to
351 * check whether the caller has sufficient rights to
352 * access the device in question.
353 * When bio is fixed for vnodes this can all be vnode
354 * operations.
355 */
356 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
357 (uap->flags & MS_RDONLY) != 0) {
358 oflag = FREAD;
359 aflag = VREAD;
360 } else {
361 oflag = FREAD | FWRITE;
362 aflag = VREAD | VWRITE;
363 }
364 if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
365 (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
366 pn_free(&dpn);
367 VN_RELE(bvp);
368 return (error);
369 }
370
371 /*
372 * Ensure that this device isn't already mounted or in progress on a
373 * mount unless this is a REMOUNT request or we are told to suppress
374 * mount checks. Global mounts require special handling.
375 */
376 if ((uap->flags & MS_NOCHECK) == 0) {
377 if ((uap->flags & MS_GLOBAL) == 0 &&
378 vfs_devmounting(dev, vfsp)) {
379 pn_free(&dpn);
380 VN_RELE(bvp);
381 return (EBUSY);
382 }
383 if (vfs_devismounted(dev)) {
384 if ((uap->flags & MS_REMOUNT) == 0) {
385 pn_free(&dpn);
386 VN_RELE(bvp);
387 return (EBUSY);
388 }
389 }
390 }
391
392 /*
393 * If the device is a tape, mount it read only
394 */
395 if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
396 vfsp->vfs_flag |= VFS_RDONLY;
397 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
398 }
399 if (uap->flags & MS_RDONLY)
400 vfsp->vfs_flag |= VFS_RDONLY;
401
402 /*
403 * Mount the filesystem, free the device vnode on error.
404 */
405 error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
406 pn_free(&dpn);
407 if (error) {
408 VN_RELE(bvp);
409 }
410 if (error == 0)
411 vfs_set_feature(vfsp, VFSFT_XVATTR);
412 return (error);
413 }
414 /*
415 * Mount root file system.
416 * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
417 * remount the root file system, and ROOT_UNMOUNT if called to
418 * unmount the root (e.g., as part of a system shutdown).
419 *
420 * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
421 * operation, goes along with auto-configuration. A mechanism should be
422 * provided by which machine-INdependent code in the kernel can say "get me the
423 * right root file system" and "get me the right initial swap area", and have
424 * that done in what may well be a machine-dependent fashion.
425 * Unfortunately, it is also file-system-type dependent (NFS gets it via
426 * bootparams calls, UFS gets it from various and sundry machine-dependent
427 * mechanisms, as SPECFS does for swap).
428 */
429 static int
|
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39
40 #pragma ident "@(#)ufs_vfsops.c 2.276 08/05/07 SMI"
41
42 #include <sys/types.h>
43 #include <sys/t_lock.h>
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/bitmap.h>
47 #include <sys/sysmacros.h>
48 #include <sys/kmem.h>
49 #include <sys/signal.h>
50 #include <sys/user.h>
51 #include <sys/proc.h>
52 #include <sys/disp.h>
53 #include <sys/buf.h>
54 #include <sys/pathname.h>
55 #include <sys/vfs.h>
56 #include <sys/vfs_opreg.h>
57 #include <sys/vnode.h>
58 #include <sys/file.h>
59 #include <sys/atomic.h>
60 #include <sys/uio.h>
249 return (mod_info(&modlinkage, modinfop));
250 }
251
252 extern struct vnode *makespecvp(dev_t dev, vtype_t type);
253
254 extern kmutex_t ufs_scan_lock;
255
256 static int mountfs(struct vfs *, enum whymountroot, struct vnode *, char *,
257 struct cred *, int, void *, int);
258
259
260 static int
261 ufs_mount(struct vfs *vfsp, struct vnode *mvp, struct mounta *uap,
262 struct cred *cr)
263
264 {
265 char *data = uap->dataptr;
266 int datalen = uap->datalen;
267 dev_t dev;
268 struct vnode *bvp;
269 struct vnode *lvp = NULL;
270 struct vnode *svp = NULL;
271 struct pathname dpn;
272 int error;
273 enum whymountroot why = ROOT_INIT;
274 struct ufs_args args;
275 int oflag, aflag;
276 int fromspace = (uap->flags & MS_SYSSPACE) ?
277 UIO_SYSSPACE : UIO_USERSPACE;
278
279 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
280 return (error);
281
282 if (mvp->v_type != VDIR)
283 return (ENOTDIR);
284
285 mutex_enter(&mvp->v_lock);
286 if ((uap->flags & MS_REMOUNT) == 0 &&
287 (uap->flags & MS_OVERLAY) == 0 &&
288 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
289 mutex_exit(&mvp->v_lock);
290 return (EBUSY);
293
294 /*
295 * Get arguments
296 */
297 bzero(&args, sizeof (args));
298 if ((uap->flags & MS_DATA) && data != NULL && datalen != 0) {
299 int copy_result = 0;
300
301 if (datalen > sizeof (args))
302 return (EINVAL);
303 if (uap->flags & MS_SYSSPACE)
304 bcopy(data, &args, datalen);
305 else
306 copy_result = copyin(data, &args, datalen);
307 if (copy_result)
308 return (EFAULT);
309 datalen = sizeof (struct ufs_args);
310 } else {
311 datalen = 0;
312 }
313
314 if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
315 (uap->flags & MS_RDONLY) != 0) {
316 oflag = FREAD;
317 aflag = VREAD;
318 } else {
319 oflag = FREAD | FWRITE;
320 aflag = VREAD | VWRITE;
321 }
322
323 /*
324 * Read in the mount point pathname
325 * (so we can record the directory the file system was last mounted on).
326 */
327 if (error = pn_get(uap->dir, fromspace, &dpn))
328 return (error);
329
330 /*
331 * Resolve path name of special file being mounted.
332 */
333 if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) {
334 pn_free(&dpn);
335 return (error);
336 }
337
338 error = vfs_get_lofi(vfsp, &lvp);
339
340 if (error > 0) {
341 VN_RELE(svp);
342 pn_free(&dpn);
343 return (error);
344 } else if (error == 0) {
345 bvp = lvp;
346 } else {
347 bvp = svp;
348
349 if (svp->v_type != VBLK) {
350 VN_RELE(svp);
351 pn_free(&dpn);
352 return (ENOTBLK);
353 }
354
355 if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) {
356 VN_RELE(svp);
357 pn_free(&dpn);
358 return (error);
359 }
360 }
361
362 dev = bvp->v_rdev;
363 if (getmajor(dev) >= devcnt) {
364 pn_free(&dpn);
365 if (lvp != NULL)
366 VN_RELE(lvp);
367 if (svp != NULL)
368 VN_RELE(svp);
369 return (ENXIO);
370 }
371 if (uap->flags & MS_REMOUNT)
372 why = ROOT_REMOUNT;
373
374 /*
375 * In SunCluster, requests to a global device are satisfied by a
376 * local device. We substitute the global pxfs node with a local
377 * spec node here.
378 *
379 * Open device/file mounted on. We need this to check whether
380 * the caller has sufficient rights to access the resource in
381 * question. When bio is fixed for vnodes this can all be vnode
382 * operations.
383 */
384 if (IS_PXFSVP(bvp)) {
385 ASSERT(lvp == NULL);
386 VN_RELE(svp);
387 svp = NULL;
388 bvp = makespecvp(dev, VBLK);
389 error = VOP_ACCESS(bvp, aflag, 0, cr, NULL);
390 } else {
391 error = VOP_ACCESS(svp, aflag, 0, cr, NULL);
392 }
393
394 if (error != 0) {
395 pn_free(&dpn);
396 if (lvp != NULL)
397 VN_RELE(lvp);
398 if (svp != NULL)
399 VN_RELE(svp);
400 return (error);
401 }
402
403 /*
404 * Ensure that this device isn't already mounted or in progress on a
405 * mount unless this is a REMOUNT request or we are told to suppress
406 * mount checks. Global mounts require special handling.
407 */
408 if ((uap->flags & MS_NOCHECK) == 0) {
409 if ((uap->flags & MS_GLOBAL) == 0 &&
410 vfs_devmounting(dev, vfsp)) {
411 pn_free(&dpn);
412 if (lvp != NULL)
413 VN_RELE(lvp);
414 if (svp != NULL)
415 VN_RELE(svp);
416 return (EBUSY);
417 }
418 if (vfs_devismounted(dev)) {
419 if ((uap->flags & MS_REMOUNT) == 0) {
420 pn_free(&dpn);
421 if (lvp != NULL)
422 VN_RELE(lvp);
423 if (svp != NULL)
424 VN_RELE(svp);
425 return (EBUSY);
426 }
427 }
428 }
429
430 /*
431 * If the device is a tape, mount it read only
432 */
433 if (devopsp[getmajor(dev)]->devo_cb_ops->cb_flag & D_TAPE) {
434 vfsp->vfs_flag |= VFS_RDONLY;
435 vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
436 }
437 if (uap->flags & MS_RDONLY)
438 vfsp->vfs_flag |= VFS_RDONLY;
439
440 /*
441 * Mount the filesystem, free the device vnode on error.
442 */
443 error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
444 pn_free(&dpn);
445
446 if (error) {
447 if (lvp != NULL)
448 VN_RELE(lvp);
449 if (svp != NULL)
450 VN_RELE(svp);
451 } else {
452 /*
453 * If lofi, drop our reference to the original file.
454 */
455 if (lvp != NULL)
456 VN_RELE(svp);
457 }
458
459 if (error == 0)
460 vfs_set_feature(vfsp, VFSFT_XVATTR);
461 return (error);
462 }
463 /*
464 * Mount root file system.
465 * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
466 * remount the root file system, and ROOT_UNMOUNT if called to
467 * unmount the root (e.g., as part of a system shutdown).
468 *
469 * XXX - this may be partially machine-dependent; it, along with the VFS_SWAPVP
470 * operation, goes along with auto-configuration. A mechanism should be
471 * provided by which machine-INdependent code in the kernel can say "get me the
472 * right root file system" and "get me the right initial swap area", and have
473 * that done in what may well be a machine-dependent fashion.
474 * Unfortunately, it is also file-system-type dependent (NFS gets it via
475 * bootparams calls, UFS gets it from various and sundry machine-dependent
476 * mechanisms, as SPECFS does for swap).
477 */
478 static int
|