$(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 \
--- /dev/null
+/*
+ * 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 */
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,
ZPOOL_PROP_MAXDNODESIZE,
ZPOOL_PROP_MULTIHOST,
ZPOOL_PROP_CHECKPOINT,
+ ZPOOL_PROP_LOAD_GUID,
ZPOOL_NUM_PROPS
} zpool_prop_t;
*/
/*
* 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>
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;
.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.
.\"
.\"
.\" 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.
.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
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,
"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,
/*
* 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>
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,
$(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
--- /dev/null
+/*
+ * 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);
+}
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) {
*/
/*
* 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 */
/* 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);
}
/*
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));
}
/*
* 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.
*/
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);
/*
* 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
}
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;
#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)) {
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);
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,
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.
#endif
uio_prefaultpages(MIN(n, max_blksz), uio);
+ rl_t *rl;
+
/*
* If in append mode, set the io offset pointer to eof.
*/
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
* 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,
(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);
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) {
/*
/*
* 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);
* 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),
* 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 &&
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);
}
read = count - uio.uio_resid;
*ppos += read;
- task_io_account_read(read);
return (read);
}
wrote = count - uio.uio_resid;
*ppos += wrote;
- task_io_account_write(wrote);
return (wrote);
}
*
* 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.
*/
/*
* 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>
#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;
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 */
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;
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);
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);
}
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);
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));
}
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
"altroot"
"health"
"guid"
+ "load_guid"
"version"
"bootfs"
"delegation"