Linux 3.9 compat: Undefine GCC_VERSION
[zfs.git] / module / zfs / vdev_file.c
index dc0e920..3c0ce53 100644 (file)
@@ -19,8 +19,8 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
  * Virtual device vector for files.
  */
 
+static void
+vdev_file_hold(vdev_t *vd)
+{
+       ASSERT(vd->vdev_path != NULL);
+}
+
+static void
+vdev_file_rele(vdev_t *vd)
+{
+       ASSERT(vd->vdev_path != NULL);
+}
+
 static int
-vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
+vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize,
+    uint64_t *ashift)
 {
        vdev_file_t *vf;
        vnode_t *vp;
@@ -51,7 +64,17 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
                return (EINVAL);
        }
 
-       vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_SLEEP);
+       /*
+        * Reopen the device if it's not currently open.  Otherwise,
+        * just update the physical size of the device.
+        */
+       if (vd->vdev_tsd != NULL) {
+               ASSERT(vd->vdev_reopening);
+               vf = vd->vdev_tsd;
+               goto skip_open;
+       }
+
+       vf = vd->vdev_tsd = kmem_zalloc(sizeof (vdev_file_t), KM_PUSHPAGE);
 
        /*
         * We always open the files from the root of the global zone, even if
@@ -61,7 +84,7 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
         */
        ASSERT(vd->vdev_path != NULL && vd->vdev_path[0] == '/');
        error = vn_openat(vd->vdev_path + 1, UIO_SYSSPACE,
-           spa_mode | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
+           spa_mode(vd->vdev_spa) | FOFFMAX, 0, &vp, 0, 0, rootdir, -1);
 
        if (error) {
                vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED;
@@ -79,6 +102,8 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
                return (ENODEV);
        }
 #endif
+
+skip_open:
        /*
         * Determine the physical size of the file.
         */
@@ -89,7 +114,7 @@ vdev_file_open(vdev_t *vd, uint64_t *psize, uint64_t *ashift)
                return (error);
        }
 
-       *psize = vattr.va_size;
+       *max_psize = *psize = vattr.va_size;
        *ashift = SPA_MINBLOCKSHIFT;
 
        return (0);
@@ -100,15 +125,16 @@ vdev_file_close(vdev_t *vd)
 {
        vdev_file_t *vf = vd->vdev_tsd;
 
-       if (vf == NULL)
+       if (vd->vdev_reopening || vf == NULL)
                return;
 
        if (vf->vf_vnode != NULL) {
                (void) VOP_PUTPAGE(vf->vf_vnode, 0, 0, B_INVAL, kcred, NULL);
-               (void) VOP_CLOSE(vf->vf_vnode, spa_mode, 1, 0, kcred, NULL);
-               VN_RELE(vf->vf_vnode);
+               (void) VOP_CLOSE(vf->vf_vnode, spa_mode(vd->vdev_spa), 1, 0,
+                   kcred, NULL);
        }
 
+       vd->vdev_delayed_close = B_FALSE;
        kmem_free(vf, sizeof (vdev_file_t));
        vd->vdev_tsd = NULL;
 }
@@ -117,16 +143,17 @@ static int
 vdev_file_io_start(zio_t *zio)
 {
        vdev_t *vd = zio->io_vd;
-       vdev_file_t *vf = vd->vdev_tsd;
-       ssize_t resid;
+       vdev_file_t *vf;
+       ssize_t resid = 0;
 
-       if (zio->io_type == ZIO_TYPE_IOCTL) {
-               /* XXPOLICY */
-               if (!vdev_readable(vd)) {
-                       zio->io_error = ENXIO;
-                       return (ZIO_PIPELINE_CONTINUE);
-               }
+       if (!vdev_readable(vd)) {
+               zio->io_error = ENXIO;
+               return (ZIO_PIPELINE_CONTINUE);
+       }
 
+       vf = vd->vdev_tsd;
+
+       if (zio->io_type == ZIO_TYPE_IOCTL) {
                switch (zio->io_cmd) {
                case DKIOCFLUSHWRITECACHE:
                        zio->io_error = VOP_FSYNC(vf->vf_vnode, FSYNC | FDSYNC,
@@ -165,6 +192,8 @@ vdev_ops_t vdev_file_ops = {
        vdev_file_io_start,
        vdev_file_io_done,
        NULL,
+       vdev_file_hold,
+       vdev_file_rele,
        VDEV_TYPE_FILE,         /* name of this vdev type */
        B_TRUE                  /* leaf vdev */
 };
@@ -181,6 +210,8 @@ vdev_ops_t vdev_disk_ops = {
        vdev_file_io_start,
        vdev_file_io_done,
        NULL,
+       vdev_file_hold,
+       vdev_file_rele,
        VDEV_TYPE_DISK,         /* name of this vdev type */
        B_TRUE                  /* leaf vdev */
 };