OpenGrok

Cross Reference: vdev_file.c
xref: /onnv/onnv-gate/usr/src/uts/common/fs/zfs/vdev_file.c
Home | History | Annotate | Line # | Download | only in zfs
      1 /*
      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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
     23  */
     24 
     25 #include <sys/zfs_context.h>
     26 #include <sys/spa.h>
     27 #include <sys/vdev_file.h>
     28 #include <sys/vdev_impl.h>
     29 #include <sys/zio.h>
     30 #include <sys/fs/zfs.h>
     31 #include <sys/fm/fs/zfs.h>
     32 
     33 /*
     34  * Virtual device vector for files.
     35  */
     36 
     37 static void
     38 vdev_file_hold(vdev_t *vd)
     39 {
     40 	ASSERT(vd->vdev_path != NULL);
     41 }
     42 
     43 static void
     44 vdev_file_rele(vdev_t *vd)
     45 {
     46 	ASSERT(vd->vdev_path != NULL);
     47 }
     48 
     49 static int
     50 vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
     51 {
     52 	vdev_file_t *vf;
     53 	vnode_t *vp;
     54 	vattr_t vattr;
     55 	int error;
     56 
     57 	/*
     58 	 * We must have a pathname, and it must be absolute.
     59 	 */
     60 	if (vd->vdev_path == NULL || vd->vdev_path[0] != '/') {
     61 		vd->vdev_stat.vs_aux = VDEV_AUX_BAD_LABEL;
     62 		return (EINVAL);
     63 	}
     64 
     65 	/*
     66 	 * Reopen the device if it's not currently open.  Otherwise,
     67 	 * just update the physical size of the device.
     68 	 */
     69 	if (vd->vdev_tsd != NULL) {
     70 		ASSERT(vd->vdev_reopening);
     71 		vf = vd->vdev_tsd;
     72 		goto skip_open;
     73 	}
     74 
     75 	vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP);
     76 
     77 	/*
     78 	 * We always open the files from the root of the global zone, even if
     79 	 * we're in a local zone.  If the user has gotten to this point, the
     80 	 * administrator has already decided that the pool should be available
     81 	 * to local zone users, so the underlying devices should be as well.
     82 	 */
     83 	ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
     84 	error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
     85 	    spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
     86 
     87 	if (error) {
     88 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
     89 		return (error);
     90 	}
     91 
     92 	vf->vf_vnode = vp;
     93 
     94 #ifdef _KERNEL
     95 	/*
     96 	 * Make sure it's a regular file.
     97 	 */
     98 	if (vp->v_type != VREG) {
     99 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
    100 		return (ENODEV);
    101 	}
    102 #endif
    103 
    104 skip_open:
    105 	/*
    106 	 * Determine the physical size of the file.
    107 	 */
    108 	vattr.va_mask = AT_SIZE;
    109 	error = VOP_GETATTR(vf->vf_vnode, &vattr, 0, kcred, NULL);
    110 	if (error) {
    111 		vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
    112 		return (error);
    113 	}
    114 
    115 	*psize = vattr.va_size;
    116 	*ashift = SPA_MINBLOCKSHIFT;
    117 
    118 	return (0);
    119 }
    120 
    121 static void
    122 vdev_file_close(vdev_t *vd)
    123 {
    124 	vdev_file_t *vf = vd->vdev_tsd;
    125 
    126 	if (vd->vdev_reopening || vf == NULL)
    127 		return;
    128 
    129 	if (vf->vf_vnode != NULL) {
    130 		(void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
    131 		(void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
    132 		    kcred, NULL);
    133 		VN_RELE(vf->vf_vnode);
    134 	}
    135 
    136 	vd->vdev_delayed_close = B_FALSE;
    137 	kmem_free(vf, sizeof (vdev_file_t));
    138 	vd->vdev_tsd = NULL;
    139 }
    140 
    141 static int
    142 vdev_file_io_start(zio_t *zio)
    143 {
    144 	vdev_t *vd = zio->io_vd;
    145 	vdev_file_t *vf = vd->vdev_tsd;
    146 	ssize_t resid;
    147 
    148 	if (zio->io_type == ZIO_TYPE_IOCTL) {
    149 		/* XXPOLICY */
    150 		if (!vdev_readable(vd)) {
    151 			zio->io_error = ENXIO;
    152 			return (ZIO_PIPELINE_CONTINUE);
    153 		}
    154 
    155 		switch (zio->io_cmd) {
    156 		case DKIOCFLUSHWRITECACHE:
    157 			zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
    158 			    kcred, NULL);
    159 			break;
    160 		default:
    161 			zio->io_error = ENOTSUP;
    162 		}
    163 
    164 		return (ZIO_PIPELINE_CONTINUE);
    165 	}
    166 
    167 	zio->io_error = vn_rdwr(zio->io_type == ZIO_TYPE_READ ?
    168 	    UIO_READ : UIO_WRITE, vf->vf_vnode, zio->io_data,
    169 	    zio->io_size, zio->io_offset, UIO_SYSSPACE,
    170 	    0, RLIM64_INFINITY, kcred, &resid);
    171 
    172 	if (resid != 0 && zio->io_error == 0)
    173 		zio->io_error = ENOSPC;
    174 
    175 	zio_interrupt(zio);
    176 
    177 	return (ZIO_PIPELINE_STOP);
    178 }
    179 
    180 /* ARGSUSED */
    181 static void
    182 vdev_file_io_done(zio_t *zio)
    183 {
    184 }
    185 
    186 vdev_ops_t vdev_file_ops = {
    187 	vdev_file_open,
    188 	vdev_file_close,
    189 	vdev_default_asize,
    190 	vdev_file_io_start,
    191 	vdev_file_io_done,
    192 	NULL,
    193 	vdev_file_hold,
    194 	vdev_file_rele,
    195 	VDEV_TYPE_FILE,		/* name of this vdev type */
    196 	B_TRUE			/* leaf vdev */
    197 };
    198 
    199 /*
    200  * From userland we access disks just like files.
    201  */
    202 #ifndef _KERNEL
    203 
    204 vdev_ops_t vdev_disk_ops = {
    205 	vdev_file_open,
    206 	vdev_file_close,
    207 	vdev_default_asize,
    208 	vdev_file_io_start,
    209 	vdev_file_io_done,
    210 	NULL,
    211 	vdev_file_hold,
    212 	vdev_file_rele,
    213 	VDEV_TYPE_DISK,		/* name of this vdev type */
    214 	B_TRUE			/* leaf vdev */
    215 };
    216 
    217 #endif
    218