]> granicus.if.org Git - zfs/commitdiff
Introduce read/write kstats per dataset
authorSerapheim Dimitropoulos <serapheimd@gmail.com>
Mon, 20 Aug 2018 16:52:37 +0000 (09:52 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 20 Aug 2018 16:52:37 +0000 (09:52 -0700)
The following patch introduces a few statistics on reads and writes
grouped by dataset. These statistics are implemented as kstats
(backed by aggregate sums for performance) and can be retrieved by
using the dataset objset ID number. The motivation for this change is
to provide some preliminary analytics on dataset usage/performance.

Reviewed-by: Richard Elling <Richard.Elling@RichardElling.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Signed-off-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Closes #7705

16 files changed:
include/sys/Makefile.am
include/sys/dataset_kstats.h [new file with mode: 0644]
include/sys/fs/zfs.h
include/sys/zfs_vfsops.h
man/man8/zfs.8
man/man8/zpool.8
module/zcommon/zfs_prop.c
module/zcommon/zpool_prop.c
module/zfs/Makefile.in
module/zfs/dataset_kstats.c [new file with mode: 0644]
module/zfs/spa.c
module/zfs/zfs_vfsops.c
module/zfs/zfs_vnops.c
module/zfs/zpl_file.c
module/zfs/zvol.c
tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg

index d64133ceb98470aef540cb0055539b352dc5b23b..f246c111d7bf472d3cf2c4c50760e43d303ccb55 100644 (file)
@@ -14,6 +14,7 @@ COMMON_H = \
        $(top_srcdir)/include/sys/bqueue.h \
        $(top_srcdir)/include/sys/cityhash.h \
        $(top_srcdir)/include/sys/spa_checkpoint.h \
+       $(top_srcdir)/include/sys/dataset_kstats.h \
        $(top_srcdir)/include/sys/dbuf.h \
        $(top_srcdir)/include/sys/ddt.h \
        $(top_srcdir)/include/sys/dmu.h \
diff --git a/include/sys/dataset_kstats.h b/include/sys/dataset_kstats.h
new file mode 100644 (file)
index 0000000..5dd9a8e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2018 by Delphix. All rights reserved.
+ */
+
+#ifndef _SYS_DATASET_KSTATS_H
+#define        _SYS_DATASET_KSTATS_H
+
+#include <sys/aggsum.h>
+#include <sys/dmu.h>
+#include <sys/kstat.h>
+
+typedef struct dataset_aggsum_stats_t {
+       aggsum_t das_writes;
+       aggsum_t das_nwritten;
+       aggsum_t das_reads;
+       aggsum_t das_nread;
+} dataset_aggsum_stats_t;
+
+typedef struct dataset_kstat_values {
+       kstat_named_t dkv_ds_name;
+       kstat_named_t dkv_writes;
+       kstat_named_t dkv_nwritten;
+       kstat_named_t dkv_reads;
+       kstat_named_t dkv_nread;
+} dataset_kstat_values_t;
+
+typedef struct dataset_kstats {
+       dataset_aggsum_stats_t dk_aggsums;
+       kstat_t *dk_kstats;
+} dataset_kstats_t;
+
+void dataset_kstats_create(dataset_kstats_t *, objset_t *);
+void dataset_kstats_destroy(dataset_kstats_t *);
+
+void dataset_kstats_update_write_kstats(dataset_kstats_t *, int64_t);
+void dataset_kstats_update_read_kstats(dataset_kstats_t *, int64_t);
+
+#endif /* _SYS_DATASET_KSTATS_H */
index 76e61eb0762084c328eef5c4ffab92429b9054b7..7daf72895730f03f5332be708bd3f6714a350a7b 100644 (file)
@@ -145,7 +145,7 @@ typedef enum {
        ZFS_PROP_USERREFS,
        ZFS_PROP_LOGBIAS,
        ZFS_PROP_UNIQUE,                /* not exposed to the user */
-       ZFS_PROP_OBJSETID,              /* not exposed to the user */
+       ZFS_PROP_OBJSETID,
        ZFS_PROP_DEDUP,
        ZFS_PROP_MLSLABEL,
        ZFS_PROP_SYNC,
@@ -240,6 +240,7 @@ typedef enum {
        ZPOOL_PROP_MAXDNODESIZE,
        ZPOOL_PROP_MULTIHOST,
        ZPOOL_PROP_CHECKPOINT,
+       ZPOOL_PROP_LOAD_GUID,
        ZPOOL_NUM_PROPS
 } zpool_prop_t;
 
index 31c9c6d7f74b0613ccb207051ec6d8e4a4160387..0a4f52f2f5b62953c94dae11081c4525122eecd0 100644 (file)
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018 by Delphix. All rights reserved.
  */
 
 #ifndef        _SYS_FS_ZFS_VFSOPS_H
 #define        _SYS_FS_ZFS_VFSOPS_H
 
+#include <sys/dataset_kstats.h>
 #include <sys/isa_defs.h>
 #include <sys/types32.h>
 #include <sys/list.h>
@@ -117,6 +119,7 @@ struct zfsvfs {
        boolean_t       z_xattr_sa;     /* allow xattrs to be stores as SA */
        uint64_t        z_version;      /* ZPL version */
        uint64_t        z_shares_dir;   /* hidden shares dir */
+       dataset_kstats_t        z_kstat;        /* fs kstats */
        kmutex_t        z_lock;
        uint64_t        z_userquota_obj;
        uint64_t        z_groupquota_obj;
index 02141da71c5c0fde79b90d1ae0bc633c019036dd..d21966c3dde6ed945d8cceed1a09aa82ea69e28c 100644 (file)
@@ -718,6 +718,16 @@ This property can be either
 .Sy yes
 or
 .Sy no .
+.It Sy objsetid
+A unique identifier for this dataset within the pool. Unlike the dataset's
+.Sy guid
+, the
+.Sy objsetid
+of a dataset is not transferred to other pools when the snapshot is copied
+with a send/receive operation.
+The
+.Sy objsetid
+can be reused (for a new datatset) after the dataset is deleted.
 .It Sy origin
 For cloned file systems or volumes, the snapshot from which the clone was
 created.
index b3196399d47e75de226e100c3ca5ad5d7d15b8ed..44ee116f3093a45c72a333ad6b5fa43f4b7ab1b4 100644 (file)
@@ -20,7 +20,7 @@
 .\"
 .\"
 .\" Copyright (c) 2007, Sun Microsystems, Inc. All Rights Reserved.
-.\" Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+.\" Copyright (c) 2012, 2018 by Delphix. All rights reserved.
 .\" Copyright (c) 2012 Cyril Plisko. All Rights Reserved.
 .\" Copyright (c) 2017 Datto Inc.
 .\" Copyright (c) 2018 George Melikov. All Rights Reserved.
@@ -562,6 +562,15 @@ Health can be one of
 .Sy ONLINE , DEGRADED , FAULTED , OFFLINE, REMOVED , UNAVAIL .
 .It Sy guid
 A unique identifier for the pool.
+.It Sy load_guid
+A unique identifier for the pool.
+Unlike the
+.Sy guid
+property, this identifier is generated every time we load the pool (e.g. does
+not persist across imports/exports) and never changes while the pool is loaded
+(even if a
+.Sy reguid
+operation takes place).
 .It Sy size
 Total size of the storage pool.
 .It Sy unsupported@ Ns Em feature_guid
index 698fb8e214ff1dd538ff15571a843514036a37c6..28eb1255b41f1ae76a643c5744432666faa6b820 100644 (file)
@@ -511,6 +511,8 @@ zfs_prop_init(void)
        zprop_register_number(ZFS_PROP_PBKDF2_ITERS, "pbkdf2iters",
            0, PROP_ONETIME_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
            "<iters>", "PBKDF2ITERS");
+       zprop_register_number(ZFS_PROP_OBJSETID, "objsetid", 0,
+           PROP_READONLY, ZFS_TYPE_DATASET, "<uint64>", "OBJSETID");
 
        /* default number properties */
        zprop_register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
@@ -552,8 +554,6 @@ zfs_prop_init(void)
            "USERACCOUNTING");
        zprop_register_hidden(ZFS_PROP_UNIQUE, "unique", PROP_TYPE_NUMBER,
            PROP_READONLY, ZFS_TYPE_DATASET, "UNIQUE");
-       zprop_register_hidden(ZFS_PROP_OBJSETID, "objsetid", PROP_TYPE_NUMBER,
-           PROP_READONLY, ZFS_TYPE_DATASET, "OBJSETID");
        zprop_register_hidden(ZFS_PROP_INCONSISTENT, "inconsistent",
            PROP_TYPE_NUMBER, PROP_READONLY, ZFS_TYPE_DATASET, "INCONSISTENT");
        zprop_register_hidden(ZFS_PROP_PREV_SNAP, "prevsnap", PROP_TYPE_STRING,
index 263d043cc6157e1e63d282cb09b7202b786b2a3a..2d577793753e8a06685d0a6f7a1c093727d4b8d6 100644 (file)
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  */
 
 #include <sys/zio.h>
@@ -93,6 +93,8 @@ zpool_prop_init(void)
            ZFS_TYPE_POOL, "<size>", "CAP");
        zprop_register_number(ZPOOL_PROP_GUID, "guid", 0, PROP_READONLY,
            ZFS_TYPE_POOL, "<guid>", "GUID");
+       zprop_register_number(ZPOOL_PROP_LOAD_GUID, "load_guid", 0,
+           PROP_READONLY, ZFS_TYPE_POOL, "<load_guid>", "LOAD_GUID");
        zprop_register_number(ZPOOL_PROP_HEALTH, "health", 0, PROP_READONLY,
            ZFS_TYPE_POOL, "<state>", "HEALTH");
        zprop_register_number(ZPOOL_PROP_DEDUPRATIO, "dedupratio", 0,
index d8d1e3a23925a4b84ba3e0fd463c62c79e5194b6..2c27cf65c5b53630a93ce077e41ac1d90ab20fbb 100644 (file)
@@ -27,6 +27,7 @@ $(MODULE)-objs += dbuf.o
 $(MODULE)-objs += dbuf_stats.o
 $(MODULE)-objs += bptree.o
 $(MODULE)-objs += bqueue.o
+$(MODULE)-objs += dataset_kstats.o
 $(MODULE)-objs += ddt.o
 $(MODULE)-objs += ddt_zap.o
 $(MODULE)-objs += dmu.o
diff --git a/module/zfs/dataset_kstats.c b/module/zfs/dataset_kstats.c
new file mode 100644 (file)
index 0000000..ac0ad84
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2018 by Delphix. All rights reserved.
+ */
+
+#include <sys/dataset_kstats.h>
+#include <sys/dmu_objset.h>
+#include <sys/dsl_dataset.h>
+#include <sys/spa.h>
+
+static dataset_kstat_values_t empty_dataset_kstats = {
+       { "dataset_name",       KSTAT_DATA_STRING },
+       { "writes",     KSTAT_DATA_UINT64 },
+       { "nwritten",   KSTAT_DATA_UINT64 },
+       { "reads",      KSTAT_DATA_UINT64 },
+       { "nread",      KSTAT_DATA_UINT64 },
+};
+
+static int
+dataset_kstats_update(kstat_t *ksp, int rw)
+{
+       dataset_kstats_t *dk = ksp->ks_private;
+       ASSERT3P(dk->dk_kstats->ks_data, ==, ksp->ks_data);
+
+       if (rw == KSTAT_WRITE)
+               return (EACCES);
+
+       dataset_kstat_values_t *dkv = dk->dk_kstats->ks_data;
+       dkv->dkv_writes.value.ui64 =
+           aggsum_value(&dk->dk_aggsums.das_writes);
+       dkv->dkv_nwritten.value.ui64 =
+           aggsum_value(&dk->dk_aggsums.das_nwritten);
+       dkv->dkv_reads.value.ui64 =
+           aggsum_value(&dk->dk_aggsums.das_reads);
+       dkv->dkv_nread.value.ui64 =
+           aggsum_value(&dk->dk_aggsums.das_nread);
+
+       return (0);
+}
+
+void
+dataset_kstats_create(dataset_kstats_t *dk, objset_t *objset)
+{
+       /*
+        * There should not be anything wrong with having kstats for
+        * snapshots. Since we are not sure how useful they would be
+        * though nor how much their memory overhead would matter in
+        * a filesystem with many snapshots, we skip them for now.
+        */
+       if (dmu_objset_is_snapshot(objset))
+               return;
+
+       /*
+        * At the time of this writing, KSTAT_STRLEN is 255 in Linux,
+        * and the spa_name can theoretically be up to 256 characters.
+        * In reality though the spa_name can be 240 characters max
+        * [see origin directory name check in pool_namecheck()]. Thus,
+        * the naming scheme for the module name below should not cause
+        * any truncations. In the event that a truncation does happen
+        * though, due to some future change, we silently skip creating
+        * the kstat and log the event.
+        */
+       char kstat_module_name[KSTAT_STRLEN];
+       int n = snprintf(kstat_module_name, sizeof (kstat_module_name),
+           "zfs/%s", spa_name(dmu_objset_spa(objset)));
+       if (n < 0) {
+               zfs_dbgmsg("failed to create dataset kstat for objset %lld: "
+                   " snprintf() for kstat module name returned %d",
+                   (unsigned long long)dmu_objset_id(objset), n);
+               return;
+       } else if (n >= KSTAT_STRLEN) {
+               zfs_dbgmsg("failed to create dataset kstat for objset %lld: "
+                   "kstat module name length (%d) exceeds limit (%d)",
+                   (unsigned long long)dmu_objset_id(objset),
+                   n, KSTAT_STRLEN);
+               return;
+       }
+
+       char kstat_name[KSTAT_STRLEN];
+       n = snprintf(kstat_name, sizeof (kstat_name), "objset-0x%llx",
+           (unsigned long long)dmu_objset_id(objset));
+       if (n < 0) {
+               zfs_dbgmsg("failed to create dataset kstat for objset %lld: "
+                   " snprintf() for kstat name returned %d",
+                   (unsigned long long)dmu_objset_id(objset), n);
+               return;
+       }
+       ASSERT3U(n, <, KSTAT_STRLEN);
+
+       kstat_t *kstat = kstat_create(kstat_module_name, 0, kstat_name,
+           "dataset", KSTAT_TYPE_NAMED,
+           sizeof (empty_dataset_kstats) / sizeof (kstat_named_t),
+           KSTAT_FLAG_VIRTUAL);
+       if (kstat == NULL)
+               return;
+
+       dataset_kstat_values_t *dk_kstats =
+           kmem_alloc(sizeof (empty_dataset_kstats), KM_SLEEP);
+       bcopy(&empty_dataset_kstats, dk_kstats,
+           sizeof (empty_dataset_kstats));
+
+       char *ds_name = kmem_zalloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
+       dsl_dataset_name(objset->os_dsl_dataset, ds_name);
+       KSTAT_NAMED_STR_PTR(&dk_kstats->dkv_ds_name) = ds_name;
+       KSTAT_NAMED_STR_BUFLEN(&dk_kstats->dkv_ds_name) =
+           ZFS_MAX_DATASET_NAME_LEN;
+
+       kstat->ks_data = dk_kstats;
+       kstat->ks_update = dataset_kstats_update;
+       kstat->ks_private = dk;
+
+       kstat_install(kstat);
+       dk->dk_kstats = kstat;
+
+       aggsum_init(&dk->dk_aggsums.das_writes, 0);
+       aggsum_init(&dk->dk_aggsums.das_nwritten, 0);
+       aggsum_init(&dk->dk_aggsums.das_reads, 0);
+       aggsum_init(&dk->dk_aggsums.das_nread, 0);
+}
+
+void
+dataset_kstats_destroy(dataset_kstats_t *dk)
+{
+       if (dk->dk_kstats == NULL)
+               return;
+
+       dataset_kstat_values_t *dkv = dk->dk_kstats->ks_data;
+       kmem_free(KSTAT_NAMED_STR_PTR(&dkv->dkv_ds_name),
+           KSTAT_NAMED_STR_BUFLEN(&dkv->dkv_ds_name));
+       kmem_free(dkv, sizeof (empty_dataset_kstats));
+
+       kstat_delete(dk->dk_kstats);
+       dk->dk_kstats = NULL;
+
+       aggsum_fini(&dk->dk_aggsums.das_writes);
+       aggsum_fini(&dk->dk_aggsums.das_nwritten);
+       aggsum_fini(&dk->dk_aggsums.das_reads);
+       aggsum_fini(&dk->dk_aggsums.das_nread);
+}
+
+void
+dataset_kstats_update_write_kstats(dataset_kstats_t *dk,
+    int64_t nwritten)
+{
+       ASSERT3S(nwritten, >=, 0);
+
+       if (dk->dk_kstats == NULL)
+               return;
+
+       aggsum_add(&dk->dk_aggsums.das_writes, 1);
+       aggsum_add(&dk->dk_aggsums.das_nwritten, nwritten);
+}
+
+void
+dataset_kstats_update_read_kstats(dataset_kstats_t *dk,
+    int64_t nread)
+{
+       ASSERT3S(nread, >=, 0);
+
+       if (dk->dk_kstats == NULL)
+               return;
+
+       aggsum_add(&dk->dk_aggsums.das_reads, 1);
+       aggsum_add(&dk->dk_aggsums.das_nread, nread);
+}
index 0d0cb556cc788a6a9b15cc2d426c0607431c12b5..39f329bea27e7440012656f4e31fa333cfb8461e 100644 (file)
@@ -306,6 +306,8 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp)
                        spa_prop_add_list(*nvp, ZPOOL_PROP_VERSION, NULL,
                            version, ZPROP_SRC_LOCAL);
                }
+               spa_prop_add_list(*nvp, ZPOOL_PROP_LOAD_GUID,
+                   NULL, spa_load_guid(spa), src);
        }
 
        if (pool != NULL) {
index a477c8669b543e0ed0cd8363958fb1110d616b33..488eaa4f2f45ec560ff92a037f2ad3dfd314ce87 100644 (file)
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -1256,6 +1256,9 @@ zfsvfs_setup(zfsvfs_t *zfsvfs, boolean_t mounting)
                /* restore readonly bit */
                if (readonly != 0)
                        readonly_changed_cb(zfsvfs, B_TRUE);
+
+               ASSERT3P(zfsvfs->z_kstat.dk_kstats, ==, NULL);
+               dataset_kstats_create(&zfsvfs->z_kstat, zfsvfs->z_os);
        }
 
        /*
@@ -1288,6 +1291,7 @@ zfsvfs_free(zfsvfs_t *zfsvfs)
        vmem_free(zfsvfs->z_hold_trees, sizeof (avl_tree_t) * size);
        vmem_free(zfsvfs->z_hold_locks, sizeof (kmutex_t) * size);
        zfsvfs_vfs_free(zfsvfs->z_vfs);
+       dataset_kstats_destroy(&zfsvfs->z_kstat);
        kmem_free(zfsvfs, sizeof (zfsvfs_t));
 }
 
index 35bbd884b9762676a34c1375542af73fc2c71bfc..4e163e2e3fe8864197987cbcdd5ea6a50f1ad8e6 100644 (file)
@@ -21,7 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  * Copyright (c) 2015 by Chunwei Chen. All rights reserved.
  * Copyright 2017 Nexenta Systems, Inc.
  */
@@ -438,15 +438,10 @@ unsigned long zfs_delete_blocks = DMU_MAX_DELETEBLKCNT;
 int
 zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 {
-       znode_t         *zp = ITOZ(ip);
-       zfsvfs_t        *zfsvfs = ITOZSB(ip);
-       ssize_t         n, nbytes;
-       int             error = 0;
-       rl_t            *rl;
-#ifdef HAVE_UIO_ZEROCOPY
-       xuio_t          *xuio = NULL;
-#endif /* HAVE_UIO_ZEROCOPY */
+       int error = 0;
 
+       znode_t *zp = ITOZ(ip);
+       zfsvfs_t *zfsvfs = ITOZSB(ip);
        ZFS_ENTER(zfsvfs);
        ZFS_VERIFY_ZP(zp);
 
@@ -482,8 +477,8 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
        /*
         * Lock the range against changes.
         */
-       rl = zfs_range_lock(&zp->z_range_lock, uio->uio_loffset, uio->uio_resid,
-           RL_READER);
+       rl_t *rl = zfs_range_lock(&zp->z_range_lock,
+           uio->uio_loffset, uio->uio_resid, RL_READER);
 
        /*
         * If we are reading past end-of-file we can skip
@@ -495,9 +490,11 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
        }
 
        ASSERT(uio->uio_loffset < zp->z_size);
-       n = MIN(uio->uio_resid, zp->z_size - uio->uio_loffset);
+       ssize_t n = MIN(uio->uio_resid, zp->z_size - uio->uio_loffset);
+       ssize_t start_resid = n;
 
 #ifdef HAVE_UIO_ZEROCOPY
+       xuio_t *xuio = NULL;
        if ((uio->uio_extflg == UIO_XUIO) &&
            (((xuio_t *)uio)->xu_type == UIOTYPE_ZEROCOPY)) {
                int nblk;
@@ -529,7 +526,7 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 #endif /* HAVE_UIO_ZEROCOPY */
 
        while (n > 0) {
-               nbytes = MIN(n, zfs_read_chunk_size -
+               ssize_t nbytes = MIN(n, zfs_read_chunk_size -
                    P2PHASE(uio->uio_loffset, zfs_read_chunk_size));
 
                if (zp->z_is_mapped && !(ioflag & O_DIRECT)) {
@@ -548,6 +545,10 @@ zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 
                n -= nbytes;
        }
+
+       int64_t nread = start_resid - n;
+       dataset_kstats_update_read_kstats(&zfsvfs->z_kstat, nread);
+       task_io_account_read(nread);
 out:
        zfs_range_unlock(rl);
 
@@ -578,46 +579,28 @@ out:
 int
 zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 {
-       znode_t         *zp = ITOZ(ip);
-       rlim64_t        limit = uio->uio_limit;
-       ssize_t         start_resid = uio->uio_resid;
-       ssize_t         tx_bytes;
-       uint64_t        end_size;
-       dmu_tx_t        *tx;
-       zfsvfs_t        *zfsvfs = ZTOZSB(zp);
-       zilog_t         *zilog;
-       offset_t        woff;
-       ssize_t         n, nbytes;
-       rl_t            *rl;
-       int             max_blksz = zfsvfs->z_max_blksz;
-       int             error = 0;
-       arc_buf_t       *abuf;
-       const iovec_t   *aiov = NULL;
-       xuio_t          *xuio = NULL;
-       int             write_eof;
-       int             count = 0;
-       sa_bulk_attr_t  bulk[4];
-       uint64_t        mtime[2], ctime[2];
-       uint32_t        uid;
-#ifdef HAVE_UIO_ZEROCOPY
-       int             i_iov = 0;
-       const iovec_t   *iovp = uio->uio_iov;
-       ASSERTV(int     iovcnt = uio->uio_iovcnt);
-#endif
+       int error = 0;
+       ssize_t start_resid = uio->uio_resid;
 
        /*
         * Fasttrack empty write
         */
-       n = start_resid;
+       ssize_t n = start_resid;
        if (n == 0)
                return (0);
 
+       rlim64_t limit = uio->uio_limit;
        if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
                limit = MAXOFFSET_T;
 
+       znode_t *zp = ITOZ(ip);
+       zfsvfs_t *zfsvfs = ZTOZSB(zp);
        ZFS_ENTER(zfsvfs);
        ZFS_VERIFY_ZP(zp);
 
+       sa_bulk_attr_t bulk[4];
+       int count = 0;
+       uint64_t mtime[2], ctime[2];
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, &ctime, 16);
        SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs), NULL,
@@ -644,17 +627,18 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                return (SET_ERROR(EPERM));
        }
 
-       zilog = zfsvfs->z_log;
-
        /*
         * Validate file offset
         */
-       woff = ioflag & FAPPEND ? zp->z_size : uio->uio_loffset;
+       offset_t woff = ioflag & FAPPEND ? zp->z_size : uio->uio_loffset;
        if (woff < 0) {
                ZFS_EXIT(zfsvfs);
                return (SET_ERROR(EINVAL));
        }
 
+       int max_blksz = zfsvfs->z_max_blksz;
+       xuio_t *xuio = NULL;
+
        /*
         * Pre-fault the pages to ensure slow (eg NFS) pages
         * don't hold up txg.
@@ -668,6 +652,8 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 #endif
                uio_prefaultpages(MIN(n, max_blksz), uio);
 
+       rl_t     *rl;
+
        /*
         * If in append mode, set the io offset pointer to eof.
         */
@@ -706,9 +692,16 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                n = limit - woff;
 
        /* Will this write extend the file length? */
-       write_eof = (woff + n > zp->z_size);
+       int write_eof = (woff + n > zp->z_size);
+
+       uint64_t end_size = MAX(zp->z_size, woff + n);
+       zilog_t *zilog = zfsvfs->z_log;
+#ifdef HAVE_UIO_ZEROCOPY
+       int             i_iov = 0;
+       const iovec_t   *iovp = uio->uio_iov;
+       ASSERTV(int     iovcnt = uio->uio_iovcnt);
+#endif
 
-       end_size = MAX(zp->z_size, woff + n);
 
        /*
         * Write the file in reasonable size chunks.  Each chunk is written
@@ -716,8 +709,8 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
         * and allows us to do more fine-grained space accounting.
         */
        while (n > 0) {
-               abuf = NULL;
                woff = uio->uio_loffset;
+
                if (zfs_id_overblockquota(zfsvfs, DMU_USERUSED_OBJECT,
                    KUID_TO_SUID(ip->i_uid)) ||
                    zfs_id_overblockquota(zfsvfs, DMU_GROUPUSED_OBJECT,
@@ -725,13 +718,13 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                    (zp->z_projid != ZFS_DEFAULT_PROJID &&
                    zfs_id_overblockquota(zfsvfs, DMU_PROJECTUSED_OBJECT,
                    zp->z_projid))) {
-                       if (abuf != NULL)
-                               dmu_return_arcbuf(abuf);
                        error = SET_ERROR(EDQUOT);
                        break;
                }
 
-               if (xuio && abuf == NULL) {
+               arc_buf_t *abuf = NULL;
+               const iovec_t *aiov = NULL;
+               if (xuio) {
 #ifdef HAVE_UIO_ZEROCOPY
                        ASSERT(i_iov < iovcnt);
                        ASSERT3U(uio->uio_segflg, !=, UIO_BVEC);
@@ -743,8 +736,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                            aiov->iov_len == arc_buf_size(abuf)));
                        i_iov++;
 #endif
-               } else if (abuf == NULL && n >= max_blksz &&
-                   woff >= zp->z_size &&
+               } else if (n >= max_blksz && woff >= zp->z_size &&
                    P2PHASE(woff, max_blksz) == 0 &&
                    zp->z_blksz == max_blksz) {
                        /*
@@ -771,7 +763,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                /*
                 * Start a transaction.
                 */
-               tx = dmu_tx_create(zfsvfs->z_os);
+               dmu_tx_t *tx = dmu_tx_create(zfsvfs->z_os);
                dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
                dmu_tx_hold_write(tx, zp->z_id, woff, MIN(n, max_blksz));
                zfs_sa_upgrade_txholds(tx, zp);
@@ -812,8 +804,9 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                 * XXX - should we really limit each write to z_max_blksz?
                 * Perhaps we should use SPA_MAXBLOCKSIZE chunks?
                 */
-               nbytes = MIN(n, max_blksz - P2PHASE(woff, max_blksz));
+               ssize_t nbytes = MIN(n, max_blksz - P2PHASE(woff, max_blksz));
 
+               ssize_t tx_bytes;
                if (abuf == NULL) {
                        tx_bytes = uio->uio_resid;
                        error = dmu_write_uio_dbuf(sa_get_db(zp->z_sa_hdl),
@@ -873,7 +866,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
                 * user 0 is not an ephemeral uid.
                 */
                mutex_enter(&zp->z_acl_lock);
-               uid = KUID_TO_SUID(ip->i_uid);
+               uint32_t uid = KUID_TO_SUID(ip->i_uid);
                if ((zp->z_mode & (S_IXUSR | (S_IXUSR >> 3) |
                    (S_IXUSR >> 6))) != 0 &&
                    (zp->z_mode & (S_ISUID | S_ISGID)) != 0 &&
@@ -937,6 +930,10 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
            zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
                zil_commit(zilog, zp->z_id);
 
+       int64_t nwritten = start_resid - uio->uio_resid;
+       dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, nwritten);
+       task_io_account_write(nwritten);
+
        ZFS_EXIT(zfsvfs);
        return (0);
 }
index 5b6839dd478f7b67e26197462db2186d24a8cb39..91251f9e6e0fd986cf5a1d33e620d89972eded93 100644 (file)
@@ -242,7 +242,6 @@ zpl_read_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
 
        read = count - uio.uio_resid;
        *ppos += read;
-       task_io_account_read(read);
 
        return (read);
 }
@@ -339,7 +338,6 @@ zpl_write_common_iovec(struct inode *ip, const struct iovec *iovp, size_t count,
 
        wrote = count - uio.uio_resid;
        *ppos += wrote;
-       task_io_account_write(wrote);
 
        return (wrote);
 }
index ecba516fcc0d836a56f4b97947db19838b12ca22..19bc1b18ef23e75c323876fd7daf31e3cf3e5980 100644 (file)
@@ -36,7 +36,7 @@
  *
  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
- * Copyright (c) 2012, 2017 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2018 by Delphix. All rights reserved.
  */
 
 /*
@@ -74,6 +74,7 @@
  * and zvol_release()->zvol_last_close() directly as well.
  */
 
+#include <sys/dataset_kstats.h>
 #include <sys/dbuf.h>
 #include <sys/dmu_traverse.h>
 #include <sys/dsl_dataset.h>
@@ -88,7 +89,9 @@
 #include <sys/zfs_znode.h>
 #include <sys/spa_impl.h>
 #include <sys/zvol.h>
+
 #include <linux/blkdev_compat.h>
+#include <linux/task_io_accounting_ops.h>
 
 unsigned int zvol_inhibit_dev = 0;
 unsigned int zvol_major = ZVOL_MAJOR;
@@ -125,6 +128,7 @@ struct zvol_state {
        dev_t                   zv_dev;         /* device id */
        struct gendisk          *zv_disk;       /* generic disk */
        struct request_queue    *zv_queue;      /* request queue */
+       dataset_kstats_t        zv_kstat;       /* zvol kstats */
        list_node_t             zv_next;        /* next zvol_state_t linkage */
        uint64_t                zv_hash;        /* name hash */
        struct hlist_node       zv_hlink;       /* hash link */
@@ -730,25 +734,25 @@ uio_from_bio(uio_t *uio, struct bio *bio)
 static void
 zvol_write(void *arg)
 {
+       int error = 0;
+
        zv_request_t *zvr = arg;
        struct bio *bio = zvr->bio;
        uio_t uio;
-       zvol_state_t *zv = zvr->zv;
-       uint64_t volsize = zv->zv_volsize;
-       boolean_t sync;
-       int error = 0;
-       unsigned long start_jif;
-
        uio_from_bio(&uio, bio);
 
+       zvol_state_t *zv = zvr->zv;
        ASSERT(zv && zv->zv_open_count > 0);
 
-       start_jif = jiffies;
+       ssize_t start_resid = uio.uio_resid;
+       unsigned long start_jif = jiffies;
        blk_generic_start_io_acct(zv->zv_queue, WRITE, bio_sectors(bio),
            &zv->zv_disk->part0);
 
-       sync = bio_is_fua(bio) || zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS;
+       boolean_t sync =
+           bio_is_fua(bio) || zv->zv_objset->os_sync == ZFS_SYNC_ALWAYS;
 
+       uint64_t volsize = zv->zv_volsize;
        while (uio.uio_resid > 0 && uio.uio_loffset < volsize) {
                uint64_t bytes = MIN(uio.uio_resid, DMU_MAX_ACCESS >> 1);
                uint64_t off = uio.uio_loffset;
@@ -766,14 +770,20 @@ zvol_write(void *arg)
                        break;
                }
                error = dmu_write_uio_dnode(zv->zv_dn, &uio, bytes, tx);
-               if (error == 0)
+               if (error == 0) {
                        zvol_log_write(zv, tx, off, bytes, sync);
+               }
                dmu_tx_commit(tx);
 
                if (error)
                        break;
        }
        zfs_range_unlock(zvr->rl);
+
+       int64_t nwritten = start_resid - uio.uio_resid;
+       dataset_kstats_update_write_kstats(&zv->zv_kstat, nwritten);
+       task_io_account_write(nwritten);
+
        if (sync)
                zil_commit(zv->zv_zilog, ZVOL_OBJ);
 
@@ -876,22 +886,22 @@ unlock:
 static void
 zvol_read(void *arg)
 {
+       int error = 0;
+
        zv_request_t *zvr = arg;
        struct bio *bio = zvr->bio;
        uio_t uio;
-       zvol_state_t *zv = zvr->zv;
-       uint64_t volsize = zv->zv_volsize;
-       int error = 0;
-       unsigned long start_jif;
-
        uio_from_bio(&uio, bio);
 
+       zvol_state_t *zv = zvr->zv;
        ASSERT(zv && zv->zv_open_count > 0);
 
-       start_jif = jiffies;
+       ssize_t start_resid = uio.uio_resid;
+       unsigned long start_jif = jiffies;
        blk_generic_start_io_acct(zv->zv_queue, READ, bio_sectors(bio),
            &zv->zv_disk->part0);
 
+       uint64_t volsize = zv->zv_volsize;
        while (uio.uio_resid > 0 && uio.uio_loffset < volsize) {
                uint64_t bytes = MIN(uio.uio_resid, DMU_MAX_ACCESS >> 1);
 
@@ -909,6 +919,10 @@ zvol_read(void *arg)
        }
        zfs_range_unlock(zvr->rl);
 
+       int64_t nread = start_resid - uio.uio_resid;
+       dataset_kstats_update_read_kstats(&zv->zv_kstat, nread);
+       task_io_account_read(nread);
+
        rw_exit(&zv->zv_suspend_lock);
        blk_generic_end_io_acct(zv->zv_queue, READ, &zv->zv_disk->part0,
            start_jif);
@@ -1741,6 +1755,7 @@ zvol_free(void *arg)
        ida_simple_remove(&zvol_ida, MINOR(zv->zv_dev) >> ZVOL_MINOR_BITS);
 
        mutex_destroy(&zv->zv_state_lock);
+       dataset_kstats_destroy(&zv->zv_kstat);
 
        kmem_free(zv, sizeof (zvol_state_t));
 }
@@ -1831,6 +1846,8 @@ zvol_create_minor_impl(const char *name)
                else
                        zil_replay(os, zv, zvol_replay_vector);
        }
+       ASSERT3P(zv->zv_kstat.dk_kstats, ==, NULL);
+       dataset_kstats_create(&zv->zv_kstat, zv->zv_objset);
 
        /*
         * When udev detects the addition of the device it will immediately
index 8994332b5d10bc2438ab91c22d755d05dbfd3574..6219caed78e3b216b688a3a446bace3d5f454b16 100644 (file)
@@ -36,6 +36,7 @@ typeset -a properties=(
     "altroot"
     "health"
     "guid"
+    "load_guid"
     "version"
     "bootfs"
     "delegation"