Merge b4c7ee6271
into c8184d714b
This commit is contained in:
commit
786c6e42ad
|
@ -2341,15 +2341,25 @@ zfs_do_inherit(int argc, char **argv)
|
|||
if (!zfs_prop_inheritable(prop) && !received) {
|
||||
(void) fprintf(stderr, gettext("'%s' property cannot "
|
||||
"be inherited\n"), propname);
|
||||
if (prop == ZFS_PROP_QUOTA ||
|
||||
prop == ZFS_PROP_RESERVATION ||
|
||||
prop == ZFS_PROP_REFQUOTA ||
|
||||
prop == ZFS_PROP_REFRESERVATION) {
|
||||
switch (prop) {
|
||||
case ZFS_PROP_QUOTA:
|
||||
case ZFS_PROP_RESERVATION:
|
||||
case ZFS_PROP_REFQUOTA:
|
||||
case ZFS_PROP_REFRESERVATION:
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
(void) fprintf(stderr, gettext("use 'zfs set "
|
||||
"%s=none' to clear\n"), propname);
|
||||
(void) fprintf(stderr, gettext("use 'zfs "
|
||||
"inherit -S %s' to revert to received "
|
||||
"value\n"), propname);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
|
|
@ -168,9 +168,12 @@ zfs_exit(zfsvfs_t *zfsvfs, const char *tag)
|
|||
(tp)->tv_sec = (time_t)(stmp)[0]; \
|
||||
(tp)->tv_nsec = (long)(stmp)[1]; \
|
||||
}
|
||||
#define ZFS_ACCESSTIME_STAMP(zfsvfs, zp) \
|
||||
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY)) \
|
||||
zfs_tstamp_update_setup_ext(zp, ACCESSED, NULL, NULL, B_FALSE);
|
||||
#define ZFS_ACCESSTIME_STAMP(zfsvfs, zp) do { \
|
||||
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY)) { \
|
||||
vfs_ratelimit_metadata_write((zfsvfs)->z_os); \
|
||||
zfs_tstamp_update_setup_ext(zp, ACCESSED, NULL, NULL, B_FALSE);\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern void zfs_tstamp_update_setup_ext(struct znode *,
|
||||
uint_t, uint64_t [2], uint64_t [2], boolean_t have_tx);
|
||||
|
|
|
@ -42,6 +42,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
struct dsl_dataset;
|
||||
struct vfs_ratelimit;
|
||||
struct zthr;
|
||||
/*
|
||||
* DD_FIELD_* are strings that are used in the "extensified" dsl_dir zap object.
|
||||
|
@ -127,6 +128,10 @@ struct dsl_dir {
|
|||
boolean_t dd_activity_cancelled;
|
||||
uint64_t dd_activity_waiters;
|
||||
|
||||
/* protected by spa_ratelimit_lock */
|
||||
struct vfs_ratelimit *dd_ratelimit;
|
||||
dsl_dir_t *dd_ratelimit_root;
|
||||
|
||||
/* protected by dd_lock; keep at end of struct for better locality */
|
||||
char dd_myname[ZFS_MAX_DATASET_NAME_LEN];
|
||||
};
|
||||
|
@ -182,6 +187,7 @@ int dsl_dir_set_quota(const char *ddname, zprop_source_t source,
|
|||
uint64_t quota);
|
||||
int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
|
||||
uint64_t reservation);
|
||||
int dsl_dir_set_ratelimit(const char *dsname, zfs_prop_t prop, uint64_t value);
|
||||
int dsl_dir_activate_fs_ss_limit(const char *);
|
||||
int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
|
||||
cred_t *, proc_t *);
|
||||
|
|
|
@ -193,6 +193,12 @@ typedef enum {
|
|||
ZFS_PROP_SNAPSHOTS_CHANGED,
|
||||
ZFS_PROP_PREFETCH,
|
||||
ZFS_PROP_VOLTHREADING,
|
||||
ZFS_PROP_RATELIMIT_BW_READ,
|
||||
ZFS_PROP_RATELIMIT_BW_WRITE,
|
||||
ZFS_PROP_RATELIMIT_BW_TOTAL,
|
||||
ZFS_PROP_RATELIMIT_OP_READ,
|
||||
ZFS_PROP_RATELIMIT_OP_WRITE,
|
||||
ZFS_PROP_RATELIMIT_OP_TOTAL,
|
||||
ZFS_NUM_PROPS
|
||||
} zfs_prop_t;
|
||||
|
||||
|
|
|
@ -457,6 +457,8 @@ struct spa {
|
|||
uint64_t spa_leaf_list_gen; /* track leaf_list changes */
|
||||
uint32_t spa_hostid; /* cached system hostid */
|
||||
|
||||
rrmlock_t spa_ratelimit_lock;
|
||||
|
||||
/* synchronization for threads in spa_wait */
|
||||
kmutex_t spa_activities_lock;
|
||||
kcondvar_t spa_activities_cv;
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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) 2024 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_VFS_RATELIMIT_H
|
||||
#define _SYS_VFS_RATELIMIT_H
|
||||
|
||||
#include <sys/dmu_objset.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct vfs_ratelimit;
|
||||
|
||||
#define ZFS_RATELIMIT_BW_READ 0
|
||||
#define ZFS_RATELIMIT_BW_WRITE 1
|
||||
#define ZFS_RATELIMIT_BW_TOTAL 2
|
||||
#define ZFS_RATELIMIT_OP_READ 3
|
||||
#define ZFS_RATELIMIT_OP_WRITE 4
|
||||
#define ZFS_RATELIMIT_OP_TOTAL 5
|
||||
#define ZFS_RATELIMIT_FIRST ZFS_RATELIMIT_BW_READ
|
||||
#define ZFS_RATELIMIT_LAST ZFS_RATELIMIT_OP_TOTAL
|
||||
#define ZFS_RATELIMIT_NTYPES (ZFS_RATELIMIT_LAST + 1)
|
||||
|
||||
int vfs_ratelimit_prop_to_type(zfs_prop_t prop);
|
||||
zfs_prop_t vfs_ratelimit_type_to_prop(int type);
|
||||
|
||||
struct vfs_ratelimit *vfs_ratelimit_alloc(const uint64_t *limits);
|
||||
void vfs_ratelimit_free(struct vfs_ratelimit *rl);
|
||||
struct vfs_ratelimit *vfs_ratelimit_set(struct vfs_ratelimit *rl,
|
||||
zfs_prop_t prop, uint64_t limit);
|
||||
|
||||
void vfs_ratelimit_data_read(objset_t *os, size_t blocksize, size_t bytes);
|
||||
void vfs_ratelimit_data_write(objset_t *os, size_t blocksize, size_t bytes);
|
||||
void vfs_ratelimit_metadata_read(objset_t *os);
|
||||
void vfs_ratelimit_metadata_write(objset_t *os);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_VFS_RATELIMIT_H */
|
|
@ -1852,7 +1852,13 @@
|
|||
<enumerator name='ZFS_PROP_SNAPSHOTS_CHANGED' value='95'/>
|
||||
<enumerator name='ZFS_PROP_PREFETCH' value='96'/>
|
||||
<enumerator name='ZFS_PROP_VOLTHREADING' value='97'/>
|
||||
<enumerator name='ZFS_NUM_PROPS' value='98'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_BW_READ' value='98'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_BW_WRITE' value='99'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_BW_TOTAL' value='100'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_OP_READ' value='101'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_OP_WRITE' value='102'/>
|
||||
<enumerator name='ZFS_PROP_RATELIMIT_OP_TOTAL' value='103'/>
|
||||
<enumerator name='ZFS_NUM_PROPS' value='104'/>
|
||||
</enum-decl>
|
||||
<typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
|
||||
<enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include <sys/spa.h>
|
||||
#include <sys/zap.h>
|
||||
#include <sys/dsl_crypt.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <libzfs.h>
|
||||
#include <libzutil.h>
|
||||
|
||||
|
@ -2287,6 +2288,12 @@ get_numeric_property(zfs_handle_t *zhp, zfs_prop_t prop, zprop_source_t *src,
|
|||
case ZFS_PROP_SNAPSHOT_LIMIT:
|
||||
case ZFS_PROP_FILESYSTEM_COUNT:
|
||||
case ZFS_PROP_SNAPSHOT_COUNT:
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
*val = getprop_uint64(zhp, prop, source);
|
||||
|
||||
if (*source == NULL) {
|
||||
|
@ -2811,12 +2818,15 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
|||
case ZFS_PROP_REFQUOTA:
|
||||
case ZFS_PROP_RESERVATION:
|
||||
case ZFS_PROP_REFRESERVATION:
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
|
||||
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||
return (-1);
|
||||
/*
|
||||
* If quota or reservation is 0, we translate this into 'none'
|
||||
* (unless literal is set), and indicate that it's the default
|
||||
* If the value is 0, we translate this into 'none' (unless
|
||||
* literal is set), and indicate that it's the default
|
||||
* value. Otherwise, we print the number nicely and indicate
|
||||
* that its set locally.
|
||||
*/
|
||||
|
@ -2835,6 +2845,25 @@ zfs_prop_get(zfs_handle_t *zhp, zfs_prop_t prop, char *propbuf, size_t proplen,
|
|||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
|
||||
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||
return (-1);
|
||||
/*
|
||||
* If the value is 0, we translate this into 'none', unless
|
||||
* literal is set.
|
||||
*/
|
||||
if (val == 0 && !literal) {
|
||||
(void) strlcpy(propbuf, "none", proplen);
|
||||
} else {
|
||||
(void) snprintf(propbuf, proplen, "%llu",
|
||||
(u_longlong_t)val);
|
||||
}
|
||||
zcp_check(zhp, prop, val, NULL);
|
||||
break;
|
||||
|
||||
case ZFS_PROP_FILESYSTEM_LIMIT:
|
||||
case ZFS_PROP_SNAPSHOT_LIMIT:
|
||||
case ZFS_PROP_FILESYSTEM_COUNT:
|
||||
|
|
|
@ -162,6 +162,7 @@ nodist_libzpool_la_SOURCES = \
|
|||
module/zfs/vdev_removal.c \
|
||||
module/zfs/vdev_root.c \
|
||||
module/zfs/vdev_trim.c \
|
||||
module/zfs/vfs_ratelimit.c \
|
||||
module/zfs/zap.c \
|
||||
module/zfs/zap_leaf.c \
|
||||
module/zfs/zap_micro.c \
|
||||
|
|
|
@ -1184,6 +1184,117 @@ and the minimum is
|
|||
.Sy 100000 .
|
||||
This property may be changed with
|
||||
.Nm zfs Cm change-key .
|
||||
.It Sy limit_bw_read Ns = Ns Ar size Ns | Ns Sy none
|
||||
.It Sy limit_bw_write Ns = Ns Ar size Ns | Ns Sy none
|
||||
.It Sy limit_bw_total Ns = Ns Ar size Ns | Ns Sy none
|
||||
Limits the read, write, or combined bandwidth, respectively, that a dataset and
|
||||
its descendants can consume.
|
||||
Limits are applied to both file systems and ZFS volumes.
|
||||
Bandwidth limits are in bytes per second.
|
||||
.Pp
|
||||
The configured limits are hierarchical, just like quotas; i.e., even if a
|
||||
higher limit is configured on the child dataset, the parent's lower limit will
|
||||
be enforced.
|
||||
.Pp
|
||||
The limits are applied at the VFS level, not at the disk level.
|
||||
The dataset is charged for each operation even if no disk access is required
|
||||
(e.g., due to caching, compression, deduplication, or NOP writes) or if the
|
||||
operation will cause more traffic (due to the copies property, mirroring,
|
||||
or RAIDZ).
|
||||
.Pp
|
||||
Read bandwidth consumption is based on:
|
||||
.Bl -bullet
|
||||
.It
|
||||
read-like syscalls, eg.,
|
||||
.Xr aio_read 2 ,
|
||||
.Xr copy_file_range 2 ,
|
||||
.Xr pread 2 ,
|
||||
.Xr preadv 2 ,
|
||||
.Xr read 2 ,
|
||||
.Xr readv 2 ,
|
||||
.Xr sendfile 2
|
||||
.It
|
||||
syscalls like
|
||||
.Xr getdents 2
|
||||
and
|
||||
.Xr getdirentries 2
|
||||
.It
|
||||
reading via mmaped files
|
||||
.It
|
||||
.Nm zfs Cm send
|
||||
.El
|
||||
.Pp
|
||||
Write bandwidth consumption is based on:
|
||||
.Bl -bullet
|
||||
.It
|
||||
write-like syscalls, eg.,
|
||||
.Xr aio_write 2 ,
|
||||
.Xr copy_file_range 2 ,
|
||||
.Xr pwrite 2 ,
|
||||
.Xr pwritev 2 ,
|
||||
.Xr write 2 ,
|
||||
.Xr writev 2
|
||||
.It
|
||||
writing via mmaped files
|
||||
.It
|
||||
.Nm zfs Cm receive
|
||||
.El
|
||||
.It Sy limit_op_read Ns = Ns Ar count Ns | Ns Sy none
|
||||
.It Sy limit_op_write Ns = Ns Ar count Ns | Ns Sy none
|
||||
.It Sy limit_op_total Ns = Ns Ar count Ns | Ns Sy none
|
||||
Limits the read, write, or both metadata operations, respectively, that a
|
||||
dataset and its descendants can generate.
|
||||
Limits are number of operations per second.
|
||||
.Pp
|
||||
Read operations consumption is based on:
|
||||
.Bl -bullet
|
||||
.It
|
||||
read-like syscalls where the number of operations is equal to the number of
|
||||
blocks being read (never less than 1)
|
||||
.It
|
||||
reading via mmaped files, where the number of operations is equal to the
|
||||
number of pages being read (never less than 1)
|
||||
.It
|
||||
syscalls accessing metadata:
|
||||
.Xr readlink 2 ,
|
||||
.Xr stat 2
|
||||
.El
|
||||
.Pp
|
||||
Write operations consumption is based on:
|
||||
.Bl -bullet
|
||||
.It
|
||||
write-like syscalls where the number of operations is equal to the number of
|
||||
blocks being written (never less than 1)
|
||||
.It
|
||||
writing via mmaped files, where the number of operations is equal to the
|
||||
number of pages being written (never less than 1)
|
||||
.It
|
||||
syscalls modifing a directory's content:
|
||||
.Xr bind 2 (UNIX-domain sockets) ,
|
||||
.Xr link 2 ,
|
||||
.Xr mkdir 2 ,
|
||||
.Xr mkfifo 2 ,
|
||||
.Xr mknod 2 ,
|
||||
.Xr open 2 (file creation) ,
|
||||
.Xr rename 2 ,
|
||||
.Xr rmdir 2 ,
|
||||
.Xr symlink 2 ,
|
||||
.Xr unlink 2
|
||||
.It
|
||||
syscalls modifing metadata:
|
||||
.Xr chflags 2 ,
|
||||
.Xr chmod 2 ,
|
||||
.Xr chown 2 ,
|
||||
.Xr utimes 2
|
||||
.It
|
||||
updating the access time of a file when reading it
|
||||
.El
|
||||
.Pp
|
||||
Just like
|
||||
.Sy limit_bw
|
||||
limits, the
|
||||
.Sy limit_op
|
||||
limits are also hierarchical and applied at the VFS level.
|
||||
.It Sy exec Ns = Ns Sy on Ns | Ns Sy off
|
||||
Controls whether processes can be executed from within this file system.
|
||||
The default value is
|
||||
|
|
|
@ -397,6 +397,7 @@ ZFS_OBJS := \
|
|||
vdev_removal.o \
|
||||
vdev_root.o \
|
||||
vdev_trim.o \
|
||||
vfs_ratelimit.o \
|
||||
zap.o \
|
||||
zap_leaf.o \
|
||||
zap_micro.o \
|
||||
|
|
|
@ -331,6 +331,7 @@ SRCS+= abd.c \
|
|||
vdev_removal.c \
|
||||
vdev_root.c \
|
||||
vdev_trim.c \
|
||||
vfs_ratelimit.c \
|
||||
zap.c \
|
||||
zap_leaf.c \
|
||||
zap_micro.c \
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include <sys/acl.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zil.h>
|
||||
#include <sys/zfs_vnops.h>
|
||||
#include <sys/module.h>
|
||||
|
@ -483,6 +484,8 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
|||
obj = vp->v_object;
|
||||
ASSERT3P(obj, !=, NULL);
|
||||
|
||||
vfs_ratelimit_data_read(zp->z_zfsvfs->z_os, PAGESIZE, len);
|
||||
|
||||
off = start & PAGEOFFSET;
|
||||
zfs_vmobject_wlock_12(obj);
|
||||
#if __FreeBSD_version >= 1300041
|
||||
|
@ -542,6 +545,8 @@ mappedread_sf(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
|||
ASSERT3P(obj, !=, NULL);
|
||||
ASSERT0(zfs_uio_offset(uio) & PAGEOFFSET);
|
||||
|
||||
vfs_ratelimit_data_read(os, PAGESIZE, len);
|
||||
|
||||
zfs_vmobject_wlock_12(obj);
|
||||
for (start = zfs_uio_offset(uio); len > 0; start += PAGESIZE) {
|
||||
int bytes = MIN(PAGESIZE, len);
|
||||
|
@ -621,6 +626,8 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
|||
obj = vp->v_object;
|
||||
ASSERT3P(obj, !=, NULL);
|
||||
|
||||
vfs_ratelimit_data_read(zp->z_zfsvfs->z_os, PAGESIZE, nbytes);
|
||||
|
||||
start = zfs_uio_offset(uio);
|
||||
off = start & PAGEOFFSET;
|
||||
zfs_vmobject_wlock_12(obj);
|
||||
|
@ -1149,6 +1156,8 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
|
|||
goto out;
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(os);
|
||||
|
||||
getnewvnode_reserve_();
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
@ -1282,6 +1291,8 @@ zfs_remove_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
|
|||
ASSERT0(error);
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* We may delete the znode now, or we may put it in the unlinked set;
|
||||
* it depends on whether we're the last link, and on whether there are
|
||||
|
@ -1509,6 +1520,8 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
|
|||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* Add a new entry to the directory.
|
||||
*/
|
||||
|
@ -1632,6 +1645,8 @@ zfs_rmdir_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
|
|||
|
||||
vnevent_rmdir(vp, dvp, name, ct);
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
|
||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||
|
@ -1788,12 +1803,11 @@ zfs_readdir(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, int *eofp,
|
|||
*/
|
||||
iovp = GET_UIO_STRUCT(uio)->uio_iov;
|
||||
bytes_wanted = iovp->iov_len;
|
||||
bufsize = bytes_wanted;
|
||||
if (zfs_uio_segflg(uio) != UIO_SYSSPACE || zfs_uio_iovcnt(uio) != 1) {
|
||||
bufsize = bytes_wanted;
|
||||
outbuf = kmem_alloc(bufsize, KM_SLEEP);
|
||||
odp = (struct dirent64 *)outbuf;
|
||||
} else {
|
||||
bufsize = bytes_wanted;
|
||||
outbuf = NULL;
|
||||
odp = (struct dirent64 *)iovp->iov_base;
|
||||
}
|
||||
|
@ -1925,6 +1939,14 @@ zfs_readdir(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, int *eofp,
|
|||
if (ncookies != NULL)
|
||||
*ncookies -= ncooks;
|
||||
|
||||
/*
|
||||
* This is post factum, but if we would do that inside the loop we
|
||||
* wouldn't know the record length before reading it anyway plus we
|
||||
* would be calling vfs_ratelimit_data_read() way too often and each
|
||||
* call accounts for a single operation.
|
||||
*/
|
||||
vfs_ratelimit_data_read(os, zp->z_blksz, outcount);
|
||||
|
||||
if (zfs_uio_segflg(uio) == UIO_SYSSPACE && zfs_uio_iovcnt(uio) == 1) {
|
||||
iovp->iov_base += outcount;
|
||||
iovp->iov_len -= outcount;
|
||||
|
@ -2017,6 +2039,8 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
|
|||
}
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* Return all attributes. It's cheaper to provide the answer
|
||||
* than to determine whether we were asked the question.
|
||||
|
@ -2612,6 +2636,9 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zidmap_t *mnt_ns)
|
|||
goto out2;
|
||||
}
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(os);
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
||||
if (mask & AT_MODE) {
|
||||
|
@ -3367,6 +3394,8 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp,
|
|||
vnevent_rename_dest_dir(tdvp, ct);
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
|
||||
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE);
|
||||
|
@ -3564,6 +3593,8 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
|
|||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
getnewvnode_reserve_();
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
||||
|
@ -3661,6 +3692,8 @@ zfs_readlink(vnode_t *vp, zfs_uio_t *uio, cred_t *cr, caller_context_t *ct)
|
|||
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||
return (error);
|
||||
|
||||
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||
|
||||
if (zp->z_is_sa)
|
||||
error = sa_lookup_uio(zp->z_sa_hdl,
|
||||
SA_ZPL_SYMLINK(zfsvfs), uio);
|
||||
|
@ -3789,6 +3822,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr,
|
|||
return (error);
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
|
||||
dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, name);
|
||||
|
@ -4118,6 +4153,9 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
|
|||
pgsin_a = MIN(*rahead, pgsin_a);
|
||||
}
|
||||
|
||||
vfs_ratelimit_data_read(zfsvfs->z_os, zp->z_blksz,
|
||||
MIN(end, obj_size) - start);
|
||||
|
||||
/*
|
||||
* NB: we need to pass the exact byte size of the data that we expect
|
||||
* to read after accounting for the file size. This is required because
|
||||
|
@ -4254,6 +4292,8 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
|
|||
goto out;
|
||||
}
|
||||
|
||||
vfs_ratelimit_data_write(zfsvfs->z_os, zp->z_blksz, len);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_write(tx, zp->z_id, off, len);
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
#include <sys/dataset_kstats.h>
|
||||
#include <sys/dbuf.h>
|
||||
#include <sys/dmu_tx.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/zio_checksum.h>
|
||||
#include <sys/zil_impl.h>
|
||||
|
@ -729,6 +730,8 @@ zvol_geom_bio_strategy(struct bio *bp)
|
|||
doread ? RL_READER : RL_WRITER);
|
||||
|
||||
if (bp->bio_cmd == BIO_DELETE) {
|
||||
/* Should we account only for a single metadata write? */
|
||||
vfs_ratelimit_metadata_write(zv->zv_objset);
|
||||
dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
|
||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||
if (error != 0) {
|
||||
|
@ -745,9 +748,13 @@ zvol_geom_bio_strategy(struct bio *bp)
|
|||
while (resid != 0 && off < volsize) {
|
||||
size_t size = MIN(resid, zvol_maxphys);
|
||||
if (doread) {
|
||||
vfs_ratelimit_data_read(zv->zv_objset,
|
||||
zv->zv_volblocksize, size);
|
||||
error = dmu_read(os, ZVOL_OBJ, off, size, addr,
|
||||
DMU_READ_PREFETCH);
|
||||
} else {
|
||||
vfs_ratelimit_data_write(zv->zv_objset,
|
||||
zv->zv_volblocksize, size);
|
||||
dmu_tx_t *tx = dmu_tx_create(os);
|
||||
dmu_tx_hold_write_by_dnode(tx, zv->zv_dn, off, size);
|
||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
#include <sys/zpl.h>
|
||||
#include <sys/zil.h>
|
||||
#include <sys/sa_impl.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
|
||||
/*
|
||||
* Programming rules.
|
||||
|
@ -237,9 +238,12 @@ static int zfs_fillpage(struct inode *ip, struct page *pp);
|
|||
void
|
||||
update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
||||
{
|
||||
zfsvfs_t *zfsvfs = ZTOZSB(zp);
|
||||
struct address_space *mp = ZTOI(zp)->i_mapping;
|
||||
int64_t off = start & (PAGE_SIZE - 1);
|
||||
|
||||
vfs_ratelimit_data_read(zfsvfs->z_os, PAGESIZE, len);
|
||||
|
||||
for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
|
||||
uint64_t nbytes = MIN(PAGE_SIZE - off, len);
|
||||
|
||||
|
@ -281,17 +285,19 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
|||
* from memory mapped pages, otherwise fallback to reading through the dmu.
|
||||
*/
|
||||
int
|
||||
mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
||||
mappedread(znode_t *zp, int len, zfs_uio_t *uio)
|
||||
{
|
||||
zfsvfs_t *zfsvfs = ZTOZSB(zp);
|
||||
struct inode *ip = ZTOI(zp);
|
||||
struct address_space *mp = ip->i_mapping;
|
||||
int64_t start = uio->uio_loffset;
|
||||
int64_t off = start & (PAGE_SIZE - 1);
|
||||
int len = nbytes;
|
||||
int error = 0;
|
||||
|
||||
vfs_ratelimit_data_read(zfsvfs->z_os, PAGESIZE, len);
|
||||
|
||||
for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
|
||||
uint64_t bytes = MIN(PAGE_SIZE - off, len);
|
||||
uint64_t nbytes = MIN(PAGE_SIZE - off, len);
|
||||
|
||||
struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT);
|
||||
if (pp) {
|
||||
|
@ -314,7 +320,7 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
|||
unlock_page(pp);
|
||||
|
||||
void *pb = kmap(pp);
|
||||
error = zfs_uiomove(pb + off, bytes, UIO_READ, uio);
|
||||
error = zfs_uiomove(pb + off, nbytes, UIO_READ, uio);
|
||||
kunmap(pp);
|
||||
|
||||
if (mapping_writably_mapped(mp))
|
||||
|
@ -324,10 +330,10 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
|||
put_page(pp);
|
||||
} else {
|
||||
error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
|
||||
uio, bytes);
|
||||
uio, nbytes);
|
||||
}
|
||||
|
||||
len -= bytes;
|
||||
len -= nbytes;
|
||||
off = 0;
|
||||
|
||||
if (error)
|
||||
|
@ -677,6 +683,8 @@ top:
|
|||
goto out;
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(os);
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
||||
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
||||
|
@ -871,6 +879,8 @@ top:
|
|||
goto out;
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(os);
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
||||
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
||||
|
@ -1007,6 +1017,8 @@ top:
|
|||
!zn_has_cached_data(zp, 0, LLONG_MAX);
|
||||
mutex_exit(&zp->z_lock);
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* We may delete the znode now, or we may put it in the unlinked set;
|
||||
* it depends on whether we're the last link, and on whether there are
|
||||
|
@ -1278,6 +1290,8 @@ top:
|
|||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* Add a new entry to the directory.
|
||||
*/
|
||||
|
@ -1420,6 +1434,8 @@ top:
|
|||
goto out;
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
/*
|
||||
* Grab a lock on the directory to make sure that no one is
|
||||
* trying to add (or lookup) entries while we are removing it.
|
||||
|
@ -1632,6 +1648,16 @@ zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr)
|
|||
}
|
||||
zp->z_zn_prefetch = B_FALSE; /* a lookup will re-enable pre-fetching */
|
||||
|
||||
#ifdef TODO
|
||||
/*
|
||||
* This is post factum, but if we would do that inside the loop we
|
||||
* wouldn't know the record length before reading it anyway plus we
|
||||
* would be calling vfs_ratelimit_data_read() way too often and each
|
||||
* call accounts for a single operation.
|
||||
*/
|
||||
vfs_ratelimit_data_read(os, zp->z_blksz, size /* ??? */);
|
||||
#endif
|
||||
|
||||
update:
|
||||
zap_cursor_fini(&zc);
|
||||
if (error == ENOENT)
|
||||
|
@ -1671,6 +1697,8 @@ zfs_getattr_fast(zidmap_t *user_ns, struct inode *ip, struct kstat *sp)
|
|||
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||
return (error);
|
||||
|
||||
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||
|
||||
mutex_enter(&zp->z_lock);
|
||||
|
||||
#ifdef HAVE_GENERIC_FILLATTR_IDMAP_REQMASK
|
||||
|
@ -2269,6 +2297,9 @@ top:
|
|||
goto out2;
|
||||
}
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(os);
|
||||
|
||||
tx = dmu_tx_create(os);
|
||||
|
||||
if (mask & ATTR_MODE) {
|
||||
|
@ -2981,6 +3012,8 @@ top:
|
|||
}
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_sa(tx, szp->z_sa_hdl, B_FALSE);
|
||||
dmu_tx_hold_sa(tx, sdzp->z_sa_hdl, B_FALSE);
|
||||
|
@ -3294,6 +3327,9 @@ top:
|
|||
zfs_exit(zfsvfs, FTAG);
|
||||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
||||
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, MAX(1, len));
|
||||
|
@ -3402,6 +3438,8 @@ zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr)
|
|||
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||
return (error);
|
||||
|
||||
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||
|
||||
mutex_enter(&zp->z_lock);
|
||||
if (zp->z_is_sa)
|
||||
error = sa_lookup_uio(zp->z_sa_hdl,
|
||||
|
@ -3539,6 +3577,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr,
|
|||
return (error);
|
||||
}
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
top:
|
||||
/*
|
||||
* Attempt to lock directory; fail if entry already exists.
|
||||
|
@ -3790,6 +3830,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
|
|||
set_page_writeback(pp);
|
||||
unlock_page(pp);
|
||||
|
||||
vfs_ratelimit_data_write(zfsvfs->z_os, zp->z_blksz, pglen);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
|
||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||
|
@ -3905,6 +3947,8 @@ zfs_dirty_inode(struct inode *ip, int flags)
|
|||
}
|
||||
#endif
|
||||
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
|
||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||
|
@ -3965,6 +4009,8 @@ zfs_inactive(struct inode *ip)
|
|||
}
|
||||
|
||||
if (zp->z_atime_dirty && zp->z_unlinked == B_FALSE) {
|
||||
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||
|
||||
dmu_tx_t *tx = dmu_tx_create(zfsvfs->z_os);
|
||||
|
||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||
|
@ -4006,6 +4052,8 @@ zfs_fillpage(struct inode *ip, struct page *pp)
|
|||
if (io_off + io_len > i_size)
|
||||
io_len = i_size - io_off;
|
||||
|
||||
vfs_ratelimit_data_read(zfsvfs->z_os, PAGESIZE, io_len);
|
||||
|
||||
void *va = kmap(pp);
|
||||
int error = dmu_read(zfsvfs->z_os, ITOZ(ip)->z_id, io_off,
|
||||
io_len, va, DMU_READ_PREFETCH);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <sys/zio.h>
|
||||
#include <sys/zfs_rlock.h>
|
||||
#include <sys/spa_impl.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zvol.h>
|
||||
#include <sys/zvol_impl.h>
|
||||
#include <cityhash.h>
|
||||
|
@ -293,11 +294,15 @@ zvol_write(zv_request_t *zvr)
|
|||
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;
|
||||
dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
|
||||
|
||||
if (bytes > volsize - off) /* don't write past the end */
|
||||
bytes = volsize - off;
|
||||
|
||||
vfs_ratelimit_data_write(zv->zv_objset, zv->zv_volblocksize,
|
||||
bytes);
|
||||
|
||||
dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
|
||||
|
||||
dmu_tx_hold_write_by_dnode(tx, zv->zv_dn, off, bytes);
|
||||
|
||||
/* This will only fail for ENOSPC */
|
||||
|
@ -395,6 +400,9 @@ zvol_discard(zv_request_t *zvr)
|
|||
zfs_locked_range_t *lr = zfs_rangelock_enter(&zv->zv_rangelock,
|
||||
start, size, RL_WRITER);
|
||||
|
||||
/* Should we account only for a single metadata write? */
|
||||
vfs_ratelimit_metadata_write(zv->zv_objset);
|
||||
|
||||
tx = dmu_tx_create(zv->zv_objset);
|
||||
dmu_tx_mark_netfree(tx);
|
||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||
|
@ -476,6 +484,9 @@ zvol_read(zv_request_t *zvr)
|
|||
if (bytes > volsize - uio.uio_loffset)
|
||||
bytes = volsize - uio.uio_loffset;
|
||||
|
||||
vfs_ratelimit_data_read(zv->zv_objset, zv->zv_volblocksize,
|
||||
bytes);
|
||||
|
||||
error = dmu_read_uio_dnode(zv->zv_dn, &uio, bytes);
|
||||
if (error) {
|
||||
/* convert checksum errors into IO errors */
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <sys/zio.h>
|
||||
#include <sys/spa.h>
|
||||
#include <sys/u8_textprep.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zfs_acl.h>
|
||||
#include <sys/zfs_ioctl.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
|
@ -694,6 +695,24 @@ zfs_prop_init(void)
|
|||
zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
|
||||
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<count> | none", "SSLIMIT", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_BW_READ, "limit_bw_read",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<bytes/sec> | none", "RTBWRD", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_BW_WRITE, "limit_bw_write",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<bytes/sec> | none", "RTBWWR", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_BW_TOTAL, "limit_bw_total",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<bytes/sec> | none", "RTBWTL", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_OP_READ, "limit_op_read",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<ops/sec> | none", "RTOPRD", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_OP_WRITE, "limit_op_write",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<ops/sec> | none", "RTOPWR", B_FALSE, sfeatures);
|
||||
zprop_register_number(ZFS_PROP_RATELIMIT_OP_TOTAL, "limit_op_total",
|
||||
0, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||
"<ops/sec> | none", "RTOPTL", B_FALSE, sfeatures);
|
||||
|
||||
/* inherit number properties */
|
||||
zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
|
||||
|
@ -997,7 +1016,6 @@ zfs_prop_valid_keylocation(const char *str, boolean_t encrypted)
|
|||
return (B_FALSE);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _KERNEL
|
||||
#include <libzfs.h>
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include <sys/zfeature.h>
|
||||
#include <sys/bqueue.h>
|
||||
#include <sys/objlist.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#ifdef _KERNEL
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#endif
|
||||
|
@ -2204,6 +2205,9 @@ flush_write_batch_impl(struct receive_writer_arg *rwa)
|
|||
|
||||
ASSERT3U(drrw->drr_object, ==, rwa->last_object);
|
||||
|
||||
vfs_ratelimit_data_write(rwa->os, drrw->drr_logical_size,
|
||||
drrw->drr_logical_size);
|
||||
|
||||
if (drrw->drr_logical_size != dn->dn_datablksz) {
|
||||
/*
|
||||
* The WRITE record is larger than the object's block
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include <sys/zvol.h>
|
||||
#include <sys/policy.h>
|
||||
#include <sys/objlist.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#ifdef _KERNEL
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#endif
|
||||
|
@ -1684,6 +1685,8 @@ issue_data_read(struct send_reader_thread_arg *srta, struct send_range *range)
|
|||
.zb_blkid = range->start_blkid,
|
||||
};
|
||||
|
||||
vfs_ratelimit_data_read(os, BP_GET_LSIZE(bp), BP_GET_LSIZE(bp));
|
||||
|
||||
arc_flags_t aflags = ARC_FLAG_CACHED_ONLY;
|
||||
|
||||
int arc_err = arc_read(NULL, os->os_spa, bp,
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <sys/sunddi.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/policy.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
#include <sys/zfs_znode.h>
|
||||
#include <sys/zvol.h>
|
||||
|
@ -143,7 +144,7 @@ dsl_dir_evict_async(void *dbu)
|
|||
{
|
||||
dsl_dir_t *dd = dbu;
|
||||
int t;
|
||||
dsl_pool_t *dp __maybe_unused = dd->dd_pool;
|
||||
dsl_pool_t *dp = dd->dd_pool;
|
||||
|
||||
dd->dd_dbuf = NULL;
|
||||
|
||||
|
@ -161,6 +162,19 @@ dsl_dir_evict_async(void *dbu)
|
|||
if (dsl_deadlist_is_open(&dd->dd_livelist))
|
||||
dsl_dir_livelist_close(dd);
|
||||
|
||||
rrm_enter_write(&dp->dp_spa->spa_ratelimit_lock);
|
||||
if (dd->dd_ratelimit_root == dd) {
|
||||
vfs_ratelimit_free(dd->dd_ratelimit);
|
||||
dd->dd_ratelimit = NULL;
|
||||
dd->dd_ratelimit_root = NULL;
|
||||
/*
|
||||
* We don't have to recurse down, because there are no children.
|
||||
* If there were any, they will have a hold on us and we
|
||||
* couldn't be evicted.
|
||||
*/
|
||||
}
|
||||
rrm_exit(&dp->dp_spa->spa_ratelimit_lock, NULL);
|
||||
|
||||
dsl_prop_fini(dd);
|
||||
cv_destroy(&dd->dd_activity_cv);
|
||||
mutex_destroy(&dd->dd_activity_lock);
|
||||
|
@ -168,6 +182,75 @@ dsl_dir_evict_async(void *dbu)
|
|||
kmem_free(dd, sizeof (dsl_dir_t));
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
dsl_dir_ratelimit_read_properties(dsl_dir_t *dd, uint64_t *limits)
|
||||
{
|
||||
char *myname, *setpoint;
|
||||
boolean_t isset;
|
||||
int type;
|
||||
|
||||
myname = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
|
||||
dsl_dir_name(dd, myname);
|
||||
setpoint = kmem_alloc(MAXNAMELEN, KM_SLEEP);
|
||||
|
||||
isset = B_FALSE;
|
||||
for (type = ZFS_RATELIMIT_FIRST; type <= ZFS_RATELIMIT_LAST; type++) {
|
||||
const char *propname;
|
||||
uint64_t limit;
|
||||
|
||||
propname = zfs_prop_to_name(vfs_ratelimit_type_to_prop(type));
|
||||
if (dsl_prop_get_dd(dd, propname, 8, 1, &limit, setpoint,
|
||||
B_FALSE) != 0) {
|
||||
/* Property doesn't exist or unable to read. */
|
||||
continue;
|
||||
}
|
||||
if (strcmp(myname, setpoint) != 0) {
|
||||
/* Property is not set here. */
|
||||
continue;
|
||||
}
|
||||
if (limit == 0) {
|
||||
/* Property is set to none, but we treat it as unset. */
|
||||
continue;
|
||||
}
|
||||
limits[type] = limit;
|
||||
isset = B_TRUE;
|
||||
}
|
||||
|
||||
kmem_free(setpoint, MAXNAMELEN);
|
||||
kmem_free(myname, ZFS_MAX_DATASET_NAME_LEN);
|
||||
|
||||
return (isset);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_ratelimit_read(dsl_dir_t *dd)
|
||||
{
|
||||
uint64_t limits[ZFS_RATELIMIT_NTYPES] = {0};
|
||||
boolean_t isset, needlock;
|
||||
|
||||
isset = dsl_dir_ratelimit_read_properties(dd, limits);
|
||||
needlock = !RRM_WRITE_HELD(&dd->dd_pool->dp_spa->spa_ratelimit_lock);
|
||||
|
||||
if (needlock) {
|
||||
rrm_enter_write(&dd->dd_pool->dp_spa->spa_ratelimit_lock);
|
||||
}
|
||||
if (isset) {
|
||||
dd->dd_ratelimit = vfs_ratelimit_alloc(limits);
|
||||
dd->dd_ratelimit_root = dd;
|
||||
} else {
|
||||
dd->dd_ratelimit = NULL;
|
||||
if (dd->dd_parent == NULL) {
|
||||
dd->dd_ratelimit_root = NULL;
|
||||
} else {
|
||||
dd->dd_ratelimit_root =
|
||||
dd->dd_parent->dd_ratelimit_root;
|
||||
}
|
||||
}
|
||||
if (needlock) {
|
||||
rrm_exit(&dd->dd_pool->dp_spa->spa_ratelimit_lock, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
||||
const char *tail, const void *tag, dsl_dir_t **ddp)
|
||||
|
@ -304,6 +387,10 @@ dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
|||
dd = winner;
|
||||
} else {
|
||||
spa_open_ref(dp->dp_spa, dd);
|
||||
|
||||
if (dd->dd_myname[0] != '$') {
|
||||
dsl_dir_ratelimit_read(dd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1908,6 +1995,126 @@ would_change(dsl_dir_t *dd, int64_t delta, dsl_dir_t *ancestor)
|
|||
return (would_change(dd->dd_parent, delta, ancestor));
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_ratelimit_recurse(dsl_dir_t *dd)
|
||||
{
|
||||
dsl_pool_t *dp = dd->dd_pool;
|
||||
objset_t *os = dp->dp_meta_objset;
|
||||
zap_cursor_t *zc;
|
||||
zap_attribute_t *za;
|
||||
|
||||
ASSERT(dsl_pool_config_held(dp));
|
||||
ASSERT(RRM_WRITE_HELD(&dp->dp_spa->spa_ratelimit_lock));
|
||||
|
||||
zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
|
||||
za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
|
||||
|
||||
/* Iterate my child dirs */
|
||||
for (zap_cursor_init(zc, os, dsl_dir_phys(dd)->dd_child_dir_zapobj);
|
||||
zap_cursor_retrieve(zc, za) == 0; zap_cursor_advance(zc)) {
|
||||
dsl_dir_t *child_dd;
|
||||
|
||||
VERIFY0(dsl_dir_hold_obj(dp, za->za_first_integer, NULL, FTAG,
|
||||
&child_dd));
|
||||
|
||||
/*
|
||||
* Ignore hidden ($FREE, $MOS & $ORIGIN) objsets.
|
||||
*/
|
||||
if (child_dd->dd_myname[0] == '$') {
|
||||
dsl_dir_rele(child_dd, FTAG);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ratelimit properties are also set here, don't overwrite.
|
||||
*/
|
||||
if (child_dd->dd_ratelimit_root == child_dd) {
|
||||
dsl_dir_rele(child_dd, FTAG);
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(child_dd->dd_ratelimit == NULL);
|
||||
child_dd->dd_ratelimit_root = dd->dd_ratelimit_root;
|
||||
|
||||
|
||||
dsl_dir_ratelimit_recurse(child_dd);
|
||||
|
||||
dsl_dir_rele(child_dd, FTAG);
|
||||
}
|
||||
zap_cursor_fini(zc);
|
||||
|
||||
kmem_free(zc, sizeof (zap_cursor_t));
|
||||
kmem_free(za, sizeof (zap_attribute_t));
|
||||
}
|
||||
|
||||
int
|
||||
dsl_dir_set_ratelimit(const char *dsname, zfs_prop_t prop, uint64_t limit)
|
||||
{
|
||||
spa_t *spa;
|
||||
dsl_pool_t *dp;
|
||||
dsl_dir_t *dd;
|
||||
int err;
|
||||
|
||||
mutex_enter(&spa_namespace_lock);
|
||||
|
||||
spa = spa_lookup(dsname);
|
||||
if (spa == NULL) {
|
||||
mutex_exit(&spa_namespace_lock);
|
||||
return (ENOENT);
|
||||
}
|
||||
|
||||
dp = spa->spa_dsl_pool;
|
||||
dsl_pool_config_enter(dp, FTAG);
|
||||
|
||||
mutex_exit(&spa_namespace_lock);
|
||||
|
||||
err = dsl_dir_hold(spa->spa_dsl_pool, dsname, FTAG, &dd, NULL);
|
||||
if (err != 0) {
|
||||
dsl_pool_config_exit(dp, FTAG);
|
||||
return (err);
|
||||
}
|
||||
|
||||
rrm_enter_write(&spa->spa_ratelimit_lock);
|
||||
|
||||
if (dd->dd_ratelimit_root == dd) {
|
||||
/* We are the root. */
|
||||
ASSERT(dd->dd_ratelimit != NULL);
|
||||
|
||||
dd->dd_ratelimit = vfs_ratelimit_set(dd->dd_ratelimit, prop,
|
||||
limit);
|
||||
if (dd->dd_ratelimit == NULL) {
|
||||
if (dd->dd_parent == NULL) {
|
||||
dd->dd_ratelimit_root = NULL;
|
||||
} else {
|
||||
dd->dd_ratelimit_root =
|
||||
dd->dd_parent->dd_ratelimit_root;
|
||||
}
|
||||
dsl_dir_ratelimit_recurse(dd);
|
||||
}
|
||||
} else if (limit != 0) {
|
||||
/*
|
||||
* No limits are currently configured or we are not the root.
|
||||
* Allocate new structure and set the limit.
|
||||
*/
|
||||
dd->dd_ratelimit = vfs_ratelimit_set(NULL, prop, limit);
|
||||
dd->dd_ratelimit_root = dd;
|
||||
dsl_dir_ratelimit_recurse(dd);
|
||||
} else {
|
||||
/*
|
||||
* We are not the root and limits is set to none,
|
||||
* so nothing to do.
|
||||
*/
|
||||
}
|
||||
|
||||
rrm_exit(&spa->spa_ratelimit_lock, NULL);
|
||||
|
||||
dsl_dir_rele(dd, FTAG);
|
||||
|
||||
dsl_pool_config_exit(dp, FTAG);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct dsl_dir_rename_arg {
|
||||
const char *ddra_oldname;
|
||||
const char *ddra_newname;
|
||||
|
@ -2105,6 +2312,22 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
|
|||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_ratelimit_rename(dsl_dir_t *dd, dsl_dir_t *newparent)
|
||||
{
|
||||
|
||||
rrm_enter_write(&dd->dd_pool->dp_spa->spa_ratelimit_lock);
|
||||
|
||||
if (dd->dd_ratelimit_root != dd) {
|
||||
ASSERT(dd->dd_ratelimit == NULL);
|
||||
dd->dd_ratelimit_root = newparent;
|
||||
|
||||
dsl_dir_ratelimit_recurse(dd);
|
||||
}
|
||||
|
||||
rrm_exit(&dd->dd_pool->dp_spa->spa_ratelimit_lock, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
|
||||
{
|
||||
|
@ -2156,6 +2379,8 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
|
|||
dsl_fs_ss_count_adjust(newparent, ss_cnt,
|
||||
DD_FIELD_SNAPSHOT_COUNT, tx);
|
||||
|
||||
dsl_dir_ratelimit_rename(dd, newparent);
|
||||
|
||||
dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
|
||||
-dsl_dir_phys(dd)->dd_used_bytes,
|
||||
-dsl_dir_phys(dd)->dd_compressed_bytes,
|
||||
|
|
|
@ -715,6 +715,8 @@ spa_add(const char *name, nvlist_t *config, const char *altroot)
|
|||
mutex_init(&spa->spa_flushed_ms_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
mutex_init(&spa->spa_activities_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
rrm_init(&spa->spa_ratelimit_lock, B_FALSE);
|
||||
|
||||
cv_init(&spa->spa_async_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_evicting_os_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&spa->spa_proc_cv, NULL, CV_DEFAULT, NULL);
|
||||
|
@ -902,6 +904,8 @@ spa_remove(spa_t *spa)
|
|||
cv_destroy(&spa->spa_activities_cv);
|
||||
cv_destroy(&spa->spa_waiters_cv);
|
||||
|
||||
rrm_destroy(&spa->spa_ratelimit_lock);
|
||||
|
||||
mutex_destroy(&spa->spa_flushed_ms_lock);
|
||||
mutex_destroy(&spa->spa_async_lock);
|
||||
mutex_destroy(&spa->spa_errlist_lock);
|
||||
|
|
|
@ -0,0 +1,664 @@
|
|||
/*
|
||||
* 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) 2024 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/dmu_objset.h>
|
||||
#include <sys/dsl_dataset.h>
|
||||
#include <sys/dsl_dir.h>
|
||||
#include <sys/spa_impl.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
|
||||
/*
|
||||
* The following comment describes rate limiting bandwidth and operations for
|
||||
* datasets that have the ratelimit property configured.
|
||||
*
|
||||
* The goal was to provide practically useful rate limiting for ZFS
|
||||
* without introducing any performance degradation when the limits are
|
||||
* configured, but not exceeded.
|
||||
*
|
||||
* The rate limiting is applied at the VFS level for file systems, before going
|
||||
* to DMU. The limits are not applied at the disk level. This means that even if
|
||||
* no disk access is required to perform the given operation, the dataset is
|
||||
* still charged for it.
|
||||
* The reasons for this design choice are the following:
|
||||
* - It would be impossible or at least very complicated to enforce such limits
|
||||
* at the VDEV level, especially for writes. At that point the writes are
|
||||
* already assigned to the specific txg and wating here would mean the whole
|
||||
* pool has to wait.
|
||||
* - It would be hard to predict what limits should be configured as there are a
|
||||
* lot of factors that dictate how much disk bandwidth is really required
|
||||
* (due to RAIDZ inflation, compression, gang blocks, deduplication,
|
||||
* NOP writes, I/O aggregation, metadata traffic, etc.).
|
||||
* By enforcing the limits at the VFS level for file system operations it should
|
||||
* be easy to find out what limits applications require and verify that the
|
||||
* limits are correctly enforced by monitoring system calls issued by the
|
||||
* applications.
|
||||
*
|
||||
* Bandwidth and operation limits are divided into three types: read, write and
|
||||
* total, where total is a combined limit for reads and writes.
|
||||
*
|
||||
* Each dataset can have its own limits configured. The configured limits are
|
||||
* enforced on the dataset and all its children - limits are hierarchical,
|
||||
* like quota. Even if a child dataset has a higher limit configured than its
|
||||
* parent, it cannot go beyond its parent limit.
|
||||
*
|
||||
* Dataset can have only selected limits configured (eg. read bandwidth and
|
||||
* write operations, but not the rest).
|
||||
*
|
||||
* The limits are stored in the vfs_ratelimit structure and attached to the
|
||||
* dsl_dir of the dataset we have configured the ratelimit properties on.
|
||||
* We walk down the dataset tree and set dd_ratelimit_root field to point to
|
||||
* this dsl_dir until we find dsl_dir that also has the vfs_ratelimit structure
|
||||
* already attached to it (which means it has its own limits configured).
|
||||
* During the accounting it allows us for quick access to the ratelimit
|
||||
* structure we need by just going to ds_dir->dd_ratelimit_root;
|
||||
* If ratelimits are not configured on this dataset or any of its parents,
|
||||
* the ds_dir->dd_ratelimit_root will be set to NULL, so we know we don't
|
||||
* have to do any accounting.
|
||||
*
|
||||
* The limits are configured per second, but we divde the second and the limits
|
||||
* into RATELIMIT_RESOLUTION slots (10 by default). This is to avoid a choking
|
||||
* effect, when process is doing progress in 1s steps. For example if we have
|
||||
* read bandwidth limits configured to 100MB/s and the process is trying to
|
||||
* read 130MB, it will take 1.3 seconds, not 2 seconds.
|
||||
* Not that very low limits may be rounded up - 7 ops/s limit will be rounded
|
||||
* up to 10 ops/s, so each slot is assigned 1 op/s limit. This rounding up
|
||||
* is done in the kernel and isn't shown in the properties value.
|
||||
*
|
||||
* How does the accounting work?
|
||||
*
|
||||
* When a request comes, we may need to consider multiple limits.
|
||||
* For example a data read request of eg. 192kB (with 128kB recordsize) is
|
||||
* accounted as 192kB bandwidth read, 192kB bandwidth total, two operations read
|
||||
* and two operations total. Not all of those limits have to be configured or
|
||||
* some might be configured on a dataset and others on a parent dataset(s).
|
||||
*
|
||||
* We remember those values in the rtslot structures at every level we have
|
||||
* limits configured on. The rtslot strucuture also remembers the time of
|
||||
* the request. For each ratelimit type (read bandwidth, total, operation read,
|
||||
* operation total) and for each dataset with the limits configured when we walk
|
||||
* the dataset tree up we find the point in time until which we have to wait to
|
||||
* satisfy configured limit. We select the furthest point in time and we do to
|
||||
* sleep. If the request doesn't exceed any limits, we just do the accounting
|
||||
* and allow for the request to be executed immediately.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Number of slots we divide one second into. More granularity is better for
|
||||
* interactivity, but it takes more memory and more calculations.
|
||||
*/
|
||||
#define RATELIMIT_RESOLUTION 16
|
||||
|
||||
struct vfs_ratelimit {
|
||||
kmutex_t rl_lock;
|
||||
uint64_t rl_limits[ZFS_RATELIMIT_NTYPES];
|
||||
/* List of current waiters and past activity. */
|
||||
list_t rl_list;
|
||||
};
|
||||
|
||||
struct rtslot {
|
||||
list_node_t rts_node;
|
||||
hrtime_t rts_timeslot;
|
||||
int rts_types;
|
||||
uint64_t rts_counts[ZFS_RATELIMIT_NTYPES];
|
||||
};
|
||||
|
||||
int
|
||||
vfs_ratelimit_prop_to_type(zfs_prop_t prop)
|
||||
{
|
||||
|
||||
switch (prop) {
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
return (ZFS_RATELIMIT_BW_READ);
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
return (ZFS_RATELIMIT_BW_WRITE);
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
return (ZFS_RATELIMIT_BW_TOTAL);
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
return (ZFS_RATELIMIT_OP_READ);
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
return (ZFS_RATELIMIT_OP_WRITE);
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
return (ZFS_RATELIMIT_OP_TOTAL);
|
||||
default:
|
||||
panic("Invalid property %d", prop);
|
||||
}
|
||||
}
|
||||
|
||||
zfs_prop_t
|
||||
vfs_ratelimit_type_to_prop(int type)
|
||||
{
|
||||
|
||||
switch (type) {
|
||||
case ZFS_RATELIMIT_BW_READ:
|
||||
return (ZFS_PROP_RATELIMIT_BW_READ);
|
||||
case ZFS_RATELIMIT_BW_WRITE:
|
||||
return (ZFS_PROP_RATELIMIT_BW_WRITE);
|
||||
case ZFS_RATELIMIT_BW_TOTAL:
|
||||
return (ZFS_PROP_RATELIMIT_BW_TOTAL);
|
||||
case ZFS_RATELIMIT_OP_READ:
|
||||
return (ZFS_PROP_RATELIMIT_OP_READ);
|
||||
case ZFS_RATELIMIT_OP_WRITE:
|
||||
return (ZFS_PROP_RATELIMIT_OP_WRITE);
|
||||
case ZFS_RATELIMIT_OP_TOTAL:
|
||||
return (ZFS_PROP_RATELIMIT_OP_TOTAL);
|
||||
default:
|
||||
panic("Invalid type %d", type);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean_t
|
||||
ratelimit_is_none(const uint64_t *limits)
|
||||
{
|
||||
|
||||
for (int i = ZFS_RATELIMIT_FIRST; i < ZFS_RATELIMIT_NTYPES; i++) {
|
||||
if (limits[i] != 0) {
|
||||
return (B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return (B_TRUE);
|
||||
}
|
||||
|
||||
struct vfs_ratelimit *
|
||||
vfs_ratelimit_alloc(const uint64_t *limits)
|
||||
{
|
||||
struct vfs_ratelimit *rl;
|
||||
int i;
|
||||
|
||||
ASSERT(limits == NULL || !ratelimit_is_none(limits));
|
||||
|
||||
rl = kmem_zalloc(sizeof (*rl), KM_SLEEP);
|
||||
|
||||
mutex_init(&rl->rl_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
list_create(&rl->rl_list, sizeof (struct rtslot),
|
||||
offsetof(struct rtslot, rts_node));
|
||||
/* Create two slots for a good start. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
list_insert_tail(&rl->rl_list,
|
||||
kmem_zalloc(sizeof (struct rtslot), KM_SLEEP));
|
||||
}
|
||||
|
||||
if (limits != NULL) {
|
||||
for (i = ZFS_RATELIMIT_FIRST; i < ZFS_RATELIMIT_NTYPES; i++) {
|
||||
uint64_t limit;
|
||||
|
||||
/*
|
||||
* We cannot have limits lower than RATELIMIT_RESOLUTION
|
||||
* as they will effectively be zero, so unlimited.
|
||||
*/
|
||||
limit = limits[i];
|
||||
if (limit > 0 && limit < RATELIMIT_RESOLUTION) {
|
||||
limit = RATELIMIT_RESOLUTION;
|
||||
}
|
||||
rl->rl_limits[i] = limit / RATELIMIT_RESOLUTION;
|
||||
}
|
||||
}
|
||||
|
||||
return (rl);
|
||||
}
|
||||
|
||||
void
|
||||
vfs_ratelimit_free(struct vfs_ratelimit *rl)
|
||||
{
|
||||
struct rtslot *slot;
|
||||
|
||||
if (rl == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((slot = list_remove_head(&rl->rl_list)) != NULL) {
|
||||
kmem_free(slot, sizeof (*slot));
|
||||
}
|
||||
list_destroy(&rl->rl_list);
|
||||
|
||||
mutex_destroy(&rl->rl_lock);
|
||||
|
||||
kmem_free(rl, sizeof (*rl));
|
||||
}
|
||||
|
||||
/*
|
||||
* If this change will make all the limits to be 0, we free the vfs_ratelimit
|
||||
* structure and return NULL.
|
||||
*/
|
||||
struct vfs_ratelimit *
|
||||
vfs_ratelimit_set(struct vfs_ratelimit *rl, zfs_prop_t prop, uint64_t limit)
|
||||
{
|
||||
int type;
|
||||
|
||||
if (rl == NULL) {
|
||||
if (limit == 0) {
|
||||
return (NULL);
|
||||
} else {
|
||||
rl = vfs_ratelimit_alloc(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
type = vfs_ratelimit_prop_to_type(prop);
|
||||
if (limit > 0 && limit < RATELIMIT_RESOLUTION) {
|
||||
limit = RATELIMIT_RESOLUTION;
|
||||
}
|
||||
rl->rl_limits[type] = limit / RATELIMIT_RESOLUTION;
|
||||
|
||||
if (ratelimit_is_none(rl->rl_limits)) {
|
||||
vfs_ratelimit_free(rl);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (rl);
|
||||
}
|
||||
|
||||
static __inline hrtime_t
|
||||
gettimeslot(void)
|
||||
{
|
||||
inode_timespec_t ts;
|
||||
hrtime_t nsec;
|
||||
|
||||
gethrestime(&ts);
|
||||
nsec = ((hrtime_t)ts.tv_sec * NANOSEC) + ts.tv_nsec;
|
||||
return (nsec / (NANOSEC / RATELIMIT_RESOLUTION));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns bit mask of the types configured for the given ratelimit structure.
|
||||
*/
|
||||
static int
|
||||
ratelimit_types(const struct vfs_ratelimit *rl)
|
||||
{
|
||||
int types, type;
|
||||
|
||||
if (rl == NULL) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
types = 0;
|
||||
for (type = ZFS_RATELIMIT_FIRST; type <= ZFS_RATELIMIT_LAST; type++) {
|
||||
if (rl->rl_limits[type] > 0) {
|
||||
types |= (1 << type);
|
||||
}
|
||||
}
|
||||
|
||||
return (types);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the ratelimit structure that includes one of the requested types
|
||||
* configured on the given dataset (os). If the given dataset doesn't have
|
||||
* ratelimit structure for one of the types, we walk up dataset tree trying
|
||||
* to find a dataset that has limits configured for one of the types we are
|
||||
* interested in.
|
||||
*/
|
||||
static dsl_dir_t *
|
||||
ratelimit_first(objset_t *os, int types)
|
||||
{
|
||||
dsl_dir_t *dd;
|
||||
int mytypes;
|
||||
|
||||
ASSERT(RRM_READ_HELD(&os->os_spa->spa_ratelimit_lock));
|
||||
|
||||
dd = os->os_dsl_dataset->ds_dir->dd_ratelimit_root;
|
||||
for (;;) {
|
||||
if (dd == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
mytypes = ratelimit_types(dd->dd_ratelimit);
|
||||
if ((mytypes & types) != 0) {
|
||||
/*
|
||||
* This dataset has at last one limit we are
|
||||
* interested in.
|
||||
*/
|
||||
return (dd);
|
||||
}
|
||||
if (dd->dd_parent == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
dd = dd->dd_parent->dd_ratelimit_root;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the ratelimit structure of the parent dataset. If the parent dataset
|
||||
* has no ratelimit structure configured or the ratelimit structure doesn't
|
||||
* include any of the types we are interested in, we walk up and continue our
|
||||
* search.
|
||||
*/
|
||||
static dsl_dir_t *
|
||||
ratelimit_parent(dsl_dir_t *dd, int types)
|
||||
{
|
||||
int mytypes;
|
||||
|
||||
ASSERT(RRM_READ_HELD(&dd->dd_pool->dp_spa->spa_ratelimit_lock));
|
||||
|
||||
for (;;) {
|
||||
if (dd->dd_parent == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
dd = dd->dd_parent->dd_ratelimit_root;
|
||||
if (dd == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
mytypes = ratelimit_types(dd->dd_ratelimit);
|
||||
if ((mytypes & types) != 0) {
|
||||
/*
|
||||
* This dataset has at last one limit we are
|
||||
* interested in.
|
||||
*/
|
||||
return (dd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have any entries with 'timeslot > now' we also must have an entry with
|
||||
* 'timeslot == now'. In other words if there is no entry with
|
||||
* 'timeslot == now', it means that all the entires expired.
|
||||
*
|
||||
* We return either the most recent entry related to the given type or we return
|
||||
* 'timeslot == now' entry not related to the given type and we will use it to
|
||||
* store accouting information about this type as well.
|
||||
*/
|
||||
static struct rtslot *
|
||||
ratelimit_find(struct vfs_ratelimit *rl, int typebit, hrtime_t now)
|
||||
{
|
||||
struct rtslot *slot;
|
||||
|
||||
ASSERT(MUTEX_HELD(&rl->rl_lock));
|
||||
|
||||
for (slot = list_head(&rl->rl_list); slot != NULL;
|
||||
slot = list_next(&rl->rl_list, slot)) {
|
||||
if (slot->rts_timeslot < now) {
|
||||
break;
|
||||
}
|
||||
if ((slot->rts_types & typebit) != 0 ||
|
||||
slot->rts_timeslot == now) {
|
||||
return (slot);
|
||||
}
|
||||
}
|
||||
/* All the entries expired. */
|
||||
#ifndef NDEBUG
|
||||
for (slot = list_head(&rl->rl_list); slot != NULL;
|
||||
slot = list_next(&rl->rl_list, slot)) {
|
||||
ASSERT(slot->rts_timeslot < now);
|
||||
}
|
||||
#endif
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Account for our request across all the types configured in this ratelimit
|
||||
* structure.
|
||||
* Return a timeslot we should wait for or now if we can execute the request
|
||||
* without waiting (we are within limits).
|
||||
*/
|
||||
static uint64_t
|
||||
ratelimit_account(struct vfs_ratelimit *rl, int types, hrtime_t now,
|
||||
const uint64_t *counts)
|
||||
{
|
||||
uint64_t timeslot;
|
||||
int type, typebit;
|
||||
|
||||
timeslot = 0;
|
||||
|
||||
mutex_enter(&rl->rl_lock);
|
||||
|
||||
for (type = ZFS_RATELIMIT_FIRST; type <= ZFS_RATELIMIT_LAST; type++) {
|
||||
struct rtslot *slot;
|
||||
uint64_t count, nexttimeslot;
|
||||
|
||||
typebit = (1 << type);
|
||||
|
||||
if ((types & typebit) == 0) {
|
||||
/* Not interested in this type. */
|
||||
continue;
|
||||
}
|
||||
if (rl->rl_limits[type] == 0) {
|
||||
/* This type has no limit configured on this dataset. */
|
||||
continue;
|
||||
}
|
||||
count = counts[type];
|
||||
ASSERT(count > 0);
|
||||
|
||||
slot = ratelimit_find(rl, typebit, now);
|
||||
if (slot == NULL) {
|
||||
slot = list_remove_tail(&rl->rl_list);
|
||||
ASSERT(slot->rts_timeslot < now);
|
||||
slot->rts_types = typebit;
|
||||
slot->rts_timeslot = now;
|
||||
memset(slot->rts_counts, 0, sizeof (slot->rts_counts));
|
||||
list_insert_head(&rl->rl_list, slot);
|
||||
} else if (slot->rts_timeslot == now) {
|
||||
/* The 'now' slot may not have our type yet. */
|
||||
slot->rts_types |= typebit;
|
||||
}
|
||||
ASSERT((slot->rts_types & typebit) != 0);
|
||||
nexttimeslot = slot->rts_timeslot + 1;
|
||||
|
||||
for (;;) {
|
||||
if (slot->rts_counts[type] + count <=
|
||||
rl->rl_limits[type]) {
|
||||
slot->rts_counts[type] += count;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* This request is too big to fit into a single slot,
|
||||
* ie. a single request exceeds the limit or this and
|
||||
* the previous requests exceed the limit.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fit as much as we can into the current slot.
|
||||
*/
|
||||
count -= rl->rl_limits[type] - slot->rts_counts[type];
|
||||
slot->rts_counts[type] = rl->rl_limits[type];
|
||||
|
||||
/*
|
||||
* Take the next slot (if already exists isn't aware of
|
||||
* our type yet), take an expired slot from the tail of
|
||||
* the list or allocate a new slot.
|
||||
*/
|
||||
slot = list_prev(&rl->rl_list, slot);
|
||||
if (slot != NULL) {
|
||||
ASSERT((slot->rts_types & typebit) == 0);
|
||||
ASSERT(slot->rts_timeslot == nexttimeslot);
|
||||
ASSERT0(slot->rts_counts[type]);
|
||||
|
||||
slot->rts_types |= typebit;
|
||||
} else {
|
||||
slot = list_tail(&rl->rl_list);
|
||||
if (slot->rts_timeslot < now) {
|
||||
list_remove(&rl->rl_list, slot);
|
||||
} else {
|
||||
slot = kmem_alloc(sizeof (*slot),
|
||||
KM_SLEEP);
|
||||
}
|
||||
slot->rts_types = typebit;
|
||||
slot->rts_timeslot = nexttimeslot;
|
||||
memset(slot->rts_counts, 0,
|
||||
sizeof (slot->rts_counts));
|
||||
list_insert_head(&rl->rl_list, slot);
|
||||
}
|
||||
|
||||
nexttimeslot++;
|
||||
}
|
||||
|
||||
if (timeslot < slot->rts_timeslot) {
|
||||
timeslot = slot->rts_timeslot;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_exit(&rl->rl_lock);
|
||||
|
||||
return (timeslot);
|
||||
}
|
||||
|
||||
static void
|
||||
vfs_ratelimit(objset_t *os, int types, const uint64_t *counts)
|
||||
{
|
||||
dsl_dir_t *dd;
|
||||
hrtime_t now, timeslot;
|
||||
|
||||
now = gettimeslot();
|
||||
timeslot = 0;
|
||||
|
||||
/*
|
||||
* Prevents configuration changes when we have requests in-flight.
|
||||
*/
|
||||
rrm_enter_read(&os->os_spa->spa_ratelimit_lock, FTAG);
|
||||
|
||||
for (dd = ratelimit_first(os, types); dd != NULL;
|
||||
dd = ratelimit_parent(dd, types)) {
|
||||
hrtime_t ts;
|
||||
|
||||
ts = ratelimit_account(dd->dd_ratelimit, types, now, counts);
|
||||
if (ts > timeslot) {
|
||||
timeslot = ts;
|
||||
}
|
||||
}
|
||||
|
||||
rrm_exit(&os->os_spa->spa_ratelimit_lock, FTAG);
|
||||
|
||||
if (timeslot > now) {
|
||||
/*
|
||||
* Too much traffic, slow it down.
|
||||
*/
|
||||
delay((hz / RATELIMIT_RESOLUTION) * (timeslot - now));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For every data read we charge:
|
||||
* - bytes of read bandwidth
|
||||
* - bytes of total bandwidth
|
||||
* - (bytes - 1) / blocksize + 1 of read operations
|
||||
* - (bytes - 1) / blocksize + 1 of total operations
|
||||
*/
|
||||
void
|
||||
vfs_ratelimit_data_read(objset_t *os, size_t blocksize, size_t bytes)
|
||||
{
|
||||
uint64_t counts[ZFS_RATELIMIT_NTYPES];
|
||||
unsigned int types;
|
||||
|
||||
if (bytes == 0) {
|
||||
return;
|
||||
}
|
||||
if (blocksize == 0) {
|
||||
blocksize = bytes;
|
||||
}
|
||||
|
||||
types = (1 << ZFS_RATELIMIT_BW_READ);
|
||||
types |= (1 << ZFS_RATELIMIT_BW_TOTAL);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_READ);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_TOTAL);
|
||||
|
||||
memset(counts, 0, sizeof (counts));
|
||||
counts[ZFS_RATELIMIT_BW_READ] = bytes;
|
||||
counts[ZFS_RATELIMIT_BW_TOTAL] = bytes;
|
||||
counts[ZFS_RATELIMIT_OP_READ] = (bytes - 1) / blocksize + 1;
|
||||
counts[ZFS_RATELIMIT_OP_TOTAL] = (bytes - 1) / blocksize + 1;
|
||||
|
||||
vfs_ratelimit(os, types, counts);
|
||||
}
|
||||
|
||||
/*
|
||||
* For every data write we charge:
|
||||
* - bytes of write bandwidth
|
||||
* - bytes of total bandwidth
|
||||
* - (bytes - 1) / blocksize + 1 of write operations
|
||||
* - (bytes - 1) / blocksize + 1 of total operations
|
||||
*/
|
||||
void
|
||||
vfs_ratelimit_data_write(objset_t *os, size_t blocksize, size_t bytes)
|
||||
{
|
||||
uint64_t counts[ZFS_RATELIMIT_NTYPES];
|
||||
unsigned int types;
|
||||
|
||||
if (bytes == 0) {
|
||||
return;
|
||||
}
|
||||
if (blocksize == 0) {
|
||||
blocksize = bytes;
|
||||
}
|
||||
|
||||
types = (1 << ZFS_RATELIMIT_BW_WRITE);
|
||||
types |= (1 << ZFS_RATELIMIT_BW_TOTAL);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_WRITE);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_TOTAL);
|
||||
|
||||
memset(counts, 0, sizeof (counts));
|
||||
counts[ZFS_RATELIMIT_BW_WRITE] = bytes;
|
||||
counts[ZFS_RATELIMIT_BW_TOTAL] = bytes;
|
||||
counts[ZFS_RATELIMIT_OP_WRITE] = (bytes - 1) / blocksize + 1;
|
||||
counts[ZFS_RATELIMIT_OP_TOTAL] = (bytes - 1) / blocksize + 1;
|
||||
|
||||
vfs_ratelimit(os, types, counts);
|
||||
}
|
||||
|
||||
/*
|
||||
* For every metadata read we charge:
|
||||
* - one read operation
|
||||
* - one total operation
|
||||
*/
|
||||
void
|
||||
vfs_ratelimit_metadata_read(objset_t *os)
|
||||
{
|
||||
uint64_t counts[ZFS_RATELIMIT_NTYPES];
|
||||
unsigned int types;
|
||||
|
||||
types = (1 << ZFS_RATELIMIT_OP_READ);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_TOTAL);
|
||||
|
||||
memset(counts, 0, sizeof (counts));
|
||||
counts[ZFS_RATELIMIT_OP_READ] = 1;
|
||||
counts[ZFS_RATELIMIT_OP_TOTAL] = 1;
|
||||
|
||||
vfs_ratelimit(os, types, counts);
|
||||
}
|
||||
|
||||
/*
|
||||
* For every metadata write we charge:
|
||||
* - one read operation
|
||||
* - one total operation
|
||||
*/
|
||||
void
|
||||
vfs_ratelimit_metadata_write(objset_t *os)
|
||||
{
|
||||
uint64_t counts[ZFS_RATELIMIT_NTYPES];
|
||||
unsigned int types;
|
||||
|
||||
types = (1 << ZFS_RATELIMIT_OP_WRITE);
|
||||
types |= (1 << ZFS_RATELIMIT_OP_TOTAL);
|
||||
|
||||
memset(counts, 0, sizeof (counts));
|
||||
counts[ZFS_RATELIMIT_OP_WRITE] = 1;
|
||||
counts[ZFS_RATELIMIT_OP_TOTAL] = 1;
|
||||
|
||||
vfs_ratelimit(os, types, counts);
|
||||
}
|
|
@ -623,6 +623,12 @@ zfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
|
|||
case ZFS_PROP_QUOTA:
|
||||
case ZFS_PROP_FILESYSTEM_LIMIT:
|
||||
case ZFS_PROP_SNAPSHOT_LIMIT:
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
if (!INGLOBALZONE(curproc)) {
|
||||
uint64_t zoned;
|
||||
char setpoint[ZFS_MAX_DATASET_NAME_LEN];
|
||||
|
@ -2495,6 +2501,16 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
|
|||
if (err == 0)
|
||||
err = -1;
|
||||
break;
|
||||
case ZFS_PROP_RATELIMIT_BW_READ:
|
||||
case ZFS_PROP_RATELIMIT_BW_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_BW_TOTAL:
|
||||
case ZFS_PROP_RATELIMIT_OP_READ:
|
||||
case ZFS_PROP_RATELIMIT_OP_WRITE:
|
||||
case ZFS_PROP_RATELIMIT_OP_TOTAL:
|
||||
err = dsl_dir_set_ratelimit(dsname, prop, intval);
|
||||
if (err == 0)
|
||||
err = -1;
|
||||
break;
|
||||
case ZFS_PROP_KEYLOCATION:
|
||||
err = dsl_crypto_can_set_keylocation(dsname, strval);
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include <sys/dbuf.h>
|
||||
#include <sys/policy.h>
|
||||
#include <sys/zfeature.h>
|
||||
#include <sys/vfs_ratelimit.h>
|
||||
#include <sys/zfs_vnops.h>
|
||||
#include <sys/zfs_quota.h>
|
||||
#include <sys/zfs_vfsops.h>
|
||||
|
@ -297,6 +298,9 @@ zfs_read(struct znode *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
|
|||
while (n > 0) {
|
||||
ssize_t nbytes = MIN(n, zfs_vnops_read_chunk_size -
|
||||
P2PHASE(zfs_uio_offset(uio), zfs_vnops_read_chunk_size));
|
||||
|
||||
vfs_ratelimit_data_read(zfsvfs->z_os, zp->z_blksz, nbytes);
|
||||
|
||||
#ifdef UIO_NOCOPY
|
||||
if (zfs_uio_segflg(uio) == UIO_NOCOPY)
|
||||
error = mappedread_sf(zp, nbytes, uio);
|
||||
|
@ -610,6 +614,8 @@ zfs_write(znode_t *zp, zfs_uio_t *uio, int ioflag, cred_t *cr)
|
|||
}
|
||||
}
|
||||
|
||||
vfs_ratelimit_data_write(zfsvfs->z_os, blksz, nbytes);
|
||||
|
||||
/*
|
||||
* Start a transaction.
|
||||
*/
|
||||
|
@ -1309,6 +1315,9 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
|
|||
break;
|
||||
}
|
||||
|
||||
vfs_ratelimit_data_read(inos, inblksz, size);
|
||||
vfs_ratelimit_data_write(outos, inblksz, size);
|
||||
|
||||
nbps = maxblocks;
|
||||
last_synced_txg = spa_last_synced_txg(dmu_objset_spa(inos));
|
||||
error = dmu_read_l0_bps(inos, inzp->z_id, inoff, size, bps,
|
||||
|
|
|
@ -22,6 +22,7 @@ dist_scripts_runfiles_DATA = \
|
|||
%D%/runfiles/linux.run \
|
||||
%D%/runfiles/longevity.run \
|
||||
%D%/runfiles/perf-regression.run \
|
||||
%D%/runfiles/ratelimit.run \
|
||||
%D%/runfiles/sanity.run \
|
||||
%D%/runfiles/sunos.run
|
||||
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# This run file contains all of the common functional tests. When
|
||||
# adding a new test consider also adding it to the sanity.run file
|
||||
# if the new test runs to completion in only a few seconds.
|
||||
# This run file contains all tests related to the block cloning functionality.
|
||||
#
|
||||
# Approximate run time: 5 hours
|
||||
#
|
||||
|
|
|
@ -817,6 +817,10 @@ tests = ['quota_001_pos', 'quota_002_pos', 'quota_003_pos',
|
|||
'quota_004_pos', 'quota_005_pos', 'quota_006_neg']
|
||||
tags = ['functional', 'quota']
|
||||
|
||||
[tests/functional/ratelimit]
|
||||
tests = ['ratelimit_random']
|
||||
tags = ['functional', 'ratelimit']
|
||||
|
||||
[tests/functional/redacted_send]
|
||||
tests = ['redacted_compressed', 'redacted_contents', 'redacted_deleted',
|
||||
'redacted_disabled_feature', 'redacted_embedded', 'redacted_holes',
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# This file and its contents are supplied under the terms of the
|
||||
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||
# You may only use this file in accordance with the terms of version
|
||||
# 1.0 of the CDDL.
|
||||
#
|
||||
# A full copy of the text of the CDDL should have accompanied this
|
||||
# source. A copy of the CDDL is also available via the Internet at
|
||||
# http://www.illumos.org/license/CDDL.
|
||||
#
|
||||
# This run file contains all tests related to the ratelimit functionality.
|
||||
#
|
||||
# Approximate run time: 1 hour 10 minutes
|
||||
#
|
||||
|
||||
[DEFAULT]
|
||||
pre = setup
|
||||
quiet = False
|
||||
pre_user = root
|
||||
user = root
|
||||
timeout = 7200
|
||||
post_user = root
|
||||
post = cleanup
|
||||
failsafe_user = root
|
||||
failsafe = callbacks/zfs_failsafe
|
||||
outputdir = /var/tmp/test_results
|
||||
tags = ['ratelimit']
|
||||
|
||||
[tests/functional/ratelimit]
|
||||
tests = ['filesystem_bw_combined',
|
||||
'filesystem_bw_hierarchical_horizontal',
|
||||
'filesystem_bw_hierarchical_vertical_read',
|
||||
'filesystem_bw_hierarchical_vertical_total',
|
||||
'filesystem_bw_hierarchical_vertical_write',
|
||||
'filesystem_bw_multiple',
|
||||
'filesystem_bw_recv',
|
||||
'filesystem_bw_send',
|
||||
'filesystem_bw_single',
|
||||
'filesystem_op_single',
|
||||
'filesystem_op_multiple',
|
||||
'inheritance',
|
||||
'volume_bw_combined',
|
||||
'volume_bw_hierarchical_horizontal',
|
||||
'volume_bw_hierarchical_vertical_read',
|
||||
'volume_bw_hierarchical_vertical_total',
|
||||
'volume_bw_hierarchical_vertical_write',
|
||||
'volume_bw_multiple',
|
||||
'volume_bw_recv',
|
||||
'volume_bw_send',
|
||||
'volume_bw_single']
|
||||
tags = ['ratelimit']
|
|
@ -12,6 +12,7 @@
|
|||
/file_check
|
||||
/file_trunc
|
||||
/file_write
|
||||
/fsop
|
||||
/get_diff
|
||||
/getversion
|
||||
/largest_file
|
||||
|
|
|
@ -9,6 +9,7 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/cp_files
|
|||
scripts_zfs_tests_bin_PROGRAMS += %D%/ctime
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/dir_rd_update
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/dosmode_readonly_write
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/fsop
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/get_diff
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/rename_dir
|
||||
scripts_zfs_tests_bin_PROGRAMS += %D%/suid_write_to_file
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
* 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) 2024 The FreeBSD Foundation
|
||||
*
|
||||
* This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef __unused
|
||||
#define __unused __attribute__((__unused__))
|
||||
#endif
|
||||
|
||||
static const char *progname;
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void) fprintf(stderr, "usage: %s <cnt> <syscall> <args>\n", progname);
|
||||
(void) fprintf(stderr, " chmod <path>\n");
|
||||
(void) fprintf(stderr, " chown <path>\n");
|
||||
(void) fprintf(stderr, " create <path>\n");
|
||||
(void) fprintf(stderr, " link <path>\n");
|
||||
(void) fprintf(stderr, " mkdir <path>\n");
|
||||
(void) fprintf(stderr, " readlink <symlink>\n");
|
||||
(void) fprintf(stderr, " rmdir <path>\n");
|
||||
(void) fprintf(stderr, " stat <path>\n");
|
||||
(void) fprintf(stderr, " symlink <path>\n");
|
||||
(void) fprintf(stderr, " unlink <path>\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_chmod(int i __unused, const char *path)
|
||||
{
|
||||
|
||||
return (chmod(path, 0600) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_chown(int i __unused, const char *path)
|
||||
{
|
||||
|
||||
return (chown(path, 0, 0) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_create(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
int fd;
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
fd = open(path, O_CREAT | O_EXCL, 0600);
|
||||
if (fd < 0) {
|
||||
return (false);
|
||||
}
|
||||
close(fd);
|
||||
return (true);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_link(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
return (link(base, path) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_stat(int i __unused, const char *path)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
return (stat(path, &sb) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_mkdir(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
return (mkdir(path, 0700) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_readlink(int i __unused, const char *symlink)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
return (readlink(symlink, path, sizeof (path)) >= 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_rename(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
const char *src, *dst;
|
||||
|
||||
snprintf(path, sizeof (path), "%s.renamed", base);
|
||||
|
||||
if ((i & 1) == 0) {
|
||||
src = base;
|
||||
dst = path;
|
||||
} else {
|
||||
src = path;
|
||||
dst = base;
|
||||
}
|
||||
|
||||
return (rename(src, dst) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_rmdir(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
return (rmdir(path) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_symlink(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
return (symlink(base, path) == 0);
|
||||
}
|
||||
|
||||
static bool
|
||||
fsop_unlink(int i, const char *base)
|
||||
{
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
snprintf(path, sizeof (path), "%s.%d", base, i);
|
||||
|
||||
return (unlink(path) == 0);
|
||||
}
|
||||
|
||||
static struct fsop {
|
||||
const char *fo_syscall;
|
||||
bool (*fo_handler)(int, const char *);
|
||||
} fsops[] = {
|
||||
{ "chmod", fsop_chmod },
|
||||
{ "chown", fsop_chown },
|
||||
{ "create", fsop_create },
|
||||
{ "link", fsop_link },
|
||||
{ "mkdir", fsop_mkdir },
|
||||
{ "readlink", fsop_readlink },
|
||||
{ "rename", fsop_rename },
|
||||
{ "rmdir", fsop_rmdir },
|
||||
{ "stat", fsop_stat },
|
||||
{ "symlink", fsop_symlink },
|
||||
{ "unlink", fsop_unlink }
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct fsop *fsop;
|
||||
const char *syscall;
|
||||
int count;
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (argc < 3) {
|
||||
usage();
|
||||
}
|
||||
|
||||
count = atoi(argv[1]);
|
||||
if (count <= 0) {
|
||||
(void) fprintf(stderr, "invalid count\n");
|
||||
exit(2);
|
||||
}
|
||||
syscall = argv[2];
|
||||
argc -= 3;
|
||||
argv += 3;
|
||||
if (argc != 1) {
|
||||
usage();
|
||||
}
|
||||
|
||||
fsop = NULL;
|
||||
for (unsigned int i = 0; i < sizeof (fsops) / sizeof (fsops[0]); i++) {
|
||||
if (strcmp(fsops[i].fo_syscall, syscall) == 0) {
|
||||
fsop = &fsops[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fsop == NULL) {
|
||||
fprintf(stderr, "Unknown syscall: %s\n", syscall);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (!fsop->fo_handler(i, argv[0])) {
|
||||
fprintf(stderr, "%s() failed: %s\n", syscall,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
|
@ -195,6 +195,7 @@ export ZFSTEST_FILES='badsend
|
|||
file_check
|
||||
file_trunc
|
||||
file_write
|
||||
fsop
|
||||
get_diff
|
||||
getversion
|
||||
largest_file
|
||||
|
|
|
@ -1654,6 +1654,38 @@ function create_dataset #dataset dataset_options
|
|||
return 0
|
||||
}
|
||||
|
||||
# Return 0 if created successfully; $? otherwise
|
||||
#
|
||||
# $1 - dataset name
|
||||
# $2 - dataset size
|
||||
# $3-n - dataset options
|
||||
|
||||
function create_volume #dataset size dataset_options
|
||||
{
|
||||
typeset dataset=$1
|
||||
typeset size=$2
|
||||
|
||||
shift 2
|
||||
|
||||
if [[ -z $dataset ]]; then
|
||||
log_note "Missing dataset name."
|
||||
return 1
|
||||
fi
|
||||
if [[ -z $size ]]; then
|
||||
log_note "Missing dataset size."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if datasetexists $dataset ; then
|
||||
destroy_dataset $dataset
|
||||
fi
|
||||
|
||||
log_must zfs create -V $size $@ $dataset
|
||||
is_linux && zvol_wait
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Return 0 if destroy successfully or the dataset exists; $? otherwise
|
||||
# Note: In local zones, this function should return 0 silently.
|
||||
#
|
||||
|
|
|
@ -346,6 +346,7 @@ nobase_dist_datadir_zfs_tests_tests_DATA += \
|
|||
functional/projectquota/projectquota_common.kshlib \
|
||||
functional/quota/quota.cfg \
|
||||
functional/quota/quota.kshlib \
|
||||
functional/ratelimit/ratelimit_common.kshlib \
|
||||
functional/redacted_send/redacted.cfg \
|
||||
functional/redacted_send/redacted.kshlib \
|
||||
functional/redundancy/redundancy.cfg \
|
||||
|
@ -1727,6 +1728,30 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
|||
functional/raidz/raidz_expand_006_neg.ksh \
|
||||
functional/raidz/raidz_expand_007_neg.ksh \
|
||||
functional/raidz/setup.ksh \
|
||||
functional/ratelimit/cleanup.ksh \
|
||||
functional/ratelimit/filesystem_bw_combined.ksh \
|
||||
functional/ratelimit/filesystem_bw_hierarchical_horizontal.ksh \
|
||||
functional/ratelimit/filesystem_bw_hierarchical_vertical_read.ksh \
|
||||
functional/ratelimit/filesystem_bw_hierarchical_vertical_total.ksh \
|
||||
functional/ratelimit/filesystem_bw_hierarchical_vertical_write.ksh \
|
||||
functional/ratelimit/filesystem_bw_multiple.ksh \
|
||||
functional/ratelimit/filesystem_bw_recv.ksh \
|
||||
functional/ratelimit/filesystem_bw_send.ksh \
|
||||
functional/ratelimit/filesystem_bw_single.ksh \
|
||||
functional/ratelimit/filesystem_op_multiple.ksh \
|
||||
functional/ratelimit/filesystem_op_single.ksh \
|
||||
functional/ratelimit/inheritance.ksh \
|
||||
functional/ratelimit/ratelimit_random.ksh \
|
||||
functional/ratelimit/setup.ksh \
|
||||
functional/ratelimit/volume_bw_combined.ksh \
|
||||
functional/ratelimit/volume_bw_hierarchical_horizontal.ksh \
|
||||
functional/ratelimit/volume_bw_hierarchical_vertical_read.ksh \
|
||||
functional/ratelimit/volume_bw_hierarchical_vertical_total.ksh \
|
||||
functional/ratelimit/volume_bw_hierarchical_vertical_write.ksh \
|
||||
functional/ratelimit/volume_bw_multiple.ksh \
|
||||
functional/ratelimit/volume_bw_recv.ksh \
|
||||
functional/ratelimit/volume_bw_send.ksh \
|
||||
functional/ratelimit/volume_bw_single.ksh \
|
||||
functional/redacted_send/cleanup.ksh \
|
||||
functional/redacted_send/redacted_compressed.ksh \
|
||||
functional/redacted_send/redacted_contents.ksh \
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#!/bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
default_cleanup_noexit
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,104 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify configurations where multiple limit types are set"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/file"
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "$TESTDIR/file"
|
||||
log_must ratelimit_bw_write 15 3 "$TESTDIR/file"
|
||||
stopwatch_start
|
||||
ddio "$TESTDIR/file" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "$TESTDIR/file" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
|
||||
rm -f "$TESTDIR/file"
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/lvl0/lvl1/lvl2/file0"
|
||||
log_must truncate -s 1G "$TESTDIR/lvl0/lvl1/lvl2/file1"
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "$TESTDIR/lvl0/lvl1/lvl2/file0"
|
||||
log_must ratelimit_bw_write 15 3 "$TESTDIR/lvl0/lvl1/lvl2/file1"
|
||||
stopwatch_start
|
||||
ddio "$TESTDIR/lvl0/lvl1/lvl2/file0" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "$TESTDIR/lvl0/lvl1/lvl2/file1" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "$TESTDIR/lvl0/lvl1/lvl2/file0"
|
||||
log_must ratelimit_bw_write 15 3 "$TESTDIR/lvl0/lvl1/lvl2/file1"
|
||||
stopwatch_start
|
||||
ddio "$TESTDIR/lvl0/lvl1/lvl2/file0" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "$TESTDIR/lvl0/lvl1/lvl2/file1" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
rm -f "$TESTDIR/lvl0/lvl1/lvl2/file0" "$TESTDIR/lvl0/lvl1/lvl2/file1"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,214 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical limits for multiple file systems at the same level"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/file"
|
||||
log_must truncate -s 1G "$TESTDIR/foo/file"
|
||||
log_must truncate -s 1G "$TESTDIR/bar/file"
|
||||
log_must truncate -s 1G "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_read 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "$TESTDIR/foo/file"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/foo/file" "$TESTDIR/bar/file"
|
||||
log_must ratelimit_bw_write 6 9 "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/bar"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
rm -f "$TESTDIR/file" "$TESTDIR/foo/file" "$TESTDIR/bar/file" "$TESTDIR/baz/file"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,65 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth read limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_read=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_read=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_read 5 5 "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,66 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth total limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_total=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_total=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_read 5 5 "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
log_must ratelimit_bw_write 5 5 "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,65 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth write limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_write=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_write 5 5 "$TESTDIR/lvl0/lvl1/lvl2/file"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,67 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for multiple active processes"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/file"
|
||||
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_read=none 500 1
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_read=1M 5 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_read=10M 50 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_read=100M 500 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_read=none 500 1
|
||||
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_total=none 500 1
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_total=1M 5 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_total=10M 50 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_total=100M 500 15
|
||||
log_must ratelimit_filesystem_bw_read_multiple limit_bw_total=none 500 1
|
||||
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_write=none 500 1
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_write=1M 5 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_write=10M 50 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_write=100M 500 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_write=none 500 1
|
||||
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_total=none 500 1
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_total=1M 5 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_total=10M 50 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_total=100M 500 15
|
||||
log_must ratelimit_filesystem_bw_write_multiple limit_bw_total=none 500 1
|
||||
|
||||
rm -f "$TESTDIR/file"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,171 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for zfs receive"
|
||||
|
||||
function ratelimit_recv
|
||||
{
|
||||
typeset -r exp=$1
|
||||
typeset res
|
||||
|
||||
shift
|
||||
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
zfs send "$TESTPOOL/$TESTFS/foo@snap" | zfs recv -F $@ "$TESTPOOL/$TESTFS/bar/baz" >/dev/null
|
||||
stopwatch_check $exp
|
||||
res=$?
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/bar/baz@snap"
|
||||
destroy_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
return $res
|
||||
}
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
log_must dd if=/dev/urandom of="$TESTDIR/foo/file" bs=1M count=16
|
||||
log_must create_snapshot "$TESTPOOL/$TESTFS/foo" "snap"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar"
|
||||
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=8M
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=8M
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=none -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M -o limit_bw_total=none
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=none -o limit_bw_total=8M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=8M -o limit_bw_total=none
|
||||
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/foo@snap"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,111 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for zfs send"
|
||||
|
||||
function ratelimit_send
|
||||
{
|
||||
typeset -r exp=$1
|
||||
|
||||
stopwatch_start
|
||||
zfs send "$TESTPOOL/$TESTFS/foo@snap" >/dev/null
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
log_must dd if=/dev/urandom of="$TESTDIR/foo/file" bs=1M count=16
|
||||
log_must create_snapshot "$TESTPOOL/$TESTFS/foo" "snap"
|
||||
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 8
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 8
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/foo@snap"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,85 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify various bandwidth limits for a single active process"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/file"
|
||||
|
||||
# Bandwidth read limits.
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_read=none 500 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_read=1M 5 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_read=10M 50 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_read=100M 500 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_read=none 500 1
|
||||
|
||||
# Bandwidth total limits limit reading.
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_total=none 500 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_total=1M 5 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_total=10M 50 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_total=100M 500 5
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_total=none 500 1
|
||||
|
||||
# Bandwidth write limits don't affect reading.
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_write=none 500 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_write=1M 5 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_write=10M 50 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_write=100M 500 1
|
||||
log_must ratelimit_filesystem_bw_read_single limit_bw_write=none 500 1
|
||||
|
||||
# Bandwidth write limits.
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_write=none 500 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_write=1M 5 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_write=10M 50 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_write=100M 500 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_write=none 500 1
|
||||
|
||||
# Bandwidth total limits limit writing.
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_total=none 500 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_total=1M 5 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_total=10M 50 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_total=100M 500 5
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_total=none 500 1
|
||||
|
||||
# Bandwidth read limits don't affect writing.
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_read=none 500 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_read=1M 5 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_read=10M 50 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_read=100M 500 1
|
||||
log_must ratelimit_filesystem_bw_write_single limit_bw_read=none 500 1
|
||||
|
||||
rm -f "$TESTDIR/file"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,78 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify operations limits for multiple active process"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must touch "$TESTDIR/file"
|
||||
log_must ln -s foo "$TESTDIR/symlink"
|
||||
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_read=none 1024 1
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_read=128 512 8
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_read=256 512 4
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_read=512 1024 4
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_read=none 1024 1
|
||||
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_total=none 1024 1
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_total=128 512 8
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_total=256 512 4
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_total=512 1024 4
|
||||
log_must ratelimit_filesystem_op_read_multiple limit_op_total=none 1024 1
|
||||
|
||||
rm -f "$TESTDIR/file" "$TESTDIR/symlink"
|
||||
|
||||
log_must touch "$TESTDIR/file0" "$TESTDIR/file1" "$TESTDIR/file2" "$TESTDIR/file3" "$TESTDIR/file4"
|
||||
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_write=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_write=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_write=128 128 5
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_write=128 128 5
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_write=256 512 10
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_write=256 512 10
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_write=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_write=none 1024 1
|
||||
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_total=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_total=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_total=128 128 5
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_total=128 128 5
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_total=256 512 10
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_total=256 512 10
|
||||
log_must ratelimit_filesystem_op_write_multiple_create limit_op_total=none 1024 1
|
||||
log_must ratelimit_filesystem_op_write_multiple_remove limit_op_total=none 1024 1
|
||||
|
||||
rm -f "$TESTDIR/file0" "$TESTDIR/file1" "$TESTDIR/file2" "$TESTDIR/file3" "$TESTDIR/file4"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,152 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify operations limits for a single active process"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must touch "$TESTDIR/file"
|
||||
log_must ln -s foo "$TESTDIR/symlink"
|
||||
|
||||
# Operations read limits.
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_read=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_read=64 512 8 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_read=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_read=128 512 4 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_read=none 1024 1 "$TESTDIR/symlink"
|
||||
|
||||
# Operations total limits limit reading.
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_total=64 512 8 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_total=128 512 4 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_total=none 1024 1 "$TESTDIR/symlink"
|
||||
|
||||
# Operations write limits don't affect reading.
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_write=64 512 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_write=64 512 1 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_write=128 512 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_write=128 512 1 "$TESTDIR/symlink"
|
||||
log_must ratelimit_filesystem_op_single stat limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single readlink limit_op_write=none 1024 1 "$TESTDIR/symlink"
|
||||
|
||||
# Operations write limits.
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_write=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single create limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_write=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_write=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_write=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single create limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_write=none 1024 1 "$TESTDIR/file"
|
||||
|
||||
# Operations total limits limit writing.
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
# Creating a file requires one metadata write and one metadata read operation.
|
||||
# On successful open(2), zfs_freebsd_open() calls vnode_create_vobject()
|
||||
# with size=0. If size=0, vnode_create_vobject() interprets this as not having
|
||||
# the proper size and calls VOP_GETATTR().
|
||||
if is_freebsd; then
|
||||
log_must ratelimit_filesystem_op_single create limit_op_total=128 512 8 "$TESTDIR/file"
|
||||
else
|
||||
log_must ratelimit_filesystem_op_single create limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
fi
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_total=64 512 8 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=128 512 4 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single create limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_total=none 1024 1 "$TESTDIR/file"
|
||||
|
||||
# Operations read limits don't affect writing.
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_read=32 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_read=64 1024 1 "$TESTDIR/file"
|
||||
if is_freebsd; then
|
||||
log_must ratelimit_filesystem_op_single create limit_op_read=128 1024 8 "$TESTDIR/file"
|
||||
else
|
||||
log_must ratelimit_filesystem_op_single create limit_op_read=128 1024 1 "$TESTDIR/file"
|
||||
fi
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=256 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_read=32 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_read=64 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_read=128 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_read=256 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=32 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_read=64 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=128 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chmod limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single chown limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single create limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single mkdir limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rmdir limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single rename limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single link limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single symlink limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
log_must ratelimit_filesystem_op_single unlink limit_op_read=none 1024 1 "$TESTDIR/file"
|
||||
|
||||
rm -f "$TESTDIR/file" "$TESTDIR/symlink"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,307 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify that limits are properly inherited"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/father"
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/mother/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must truncate -s 1G "$TESTDIR/father/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/father/file" "/dev/null"
|
||||
|
||||
if false; then
|
||||
# Parent configuration exists before child creation.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Parent configuration is done after child creation.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Child is moved between a parent with no configuration to a parent with limits and back.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/father"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/father/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/father"
|
||||
|
||||
# Child is moved between a parent with limits to a parent with no limits and back.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/father/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Child is moved between parent with different limits and back.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/father"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must ratelimit_bw 1 8 8 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 8 4 "$TESTDIR/father/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 8 8 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/father"
|
||||
|
||||
# Repeat the tests above, but test grandchild, so its direct ancestor doesn't have limits.
|
||||
|
||||
# Parent configuration exists before child and grandchild creation.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Parent configuration is done after child and grandchild creation.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Child is moved between a parent with no configuration to a parent with limits and back.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/father"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/father/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/father"
|
||||
|
||||
# Child is moved between a parent with limits to a parent with no limits and back.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 5 1 "$TESTDIR/father/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 5 5 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
|
||||
# Child is moved between parent with different limits and back.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/father"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 8 8 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/father/child"
|
||||
log_must ratelimit_bw 1 8 4 "$TESTDIR/father/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/father/child" "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must ratelimit_bw 1 8 8 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/father"
|
||||
fi
|
||||
|
||||
# Revert the order of datasets when all datasets have limits.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child/grandchild" "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother" "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the bottom doesn't affect ancestors.
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the top does affect descendants.
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 12 2 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 12 2 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 2 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/grandchild/child/mother" "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild"
|
||||
#
|
||||
# Revert the order of limits.
|
||||
#
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child/grandchild" "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother" "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the bottom doesn't affect ancestors.
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the top does affect descendants.
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/grandchild/child/mother" "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild"
|
||||
|
||||
# Revert the order datasets when grandchild doesn't have limits.
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child/grandchild" "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 10 1 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother" "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the bottom doesn't affect ancestors.
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 10 1 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the top does affect descendants.
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 10 10 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/grandchild/child/mother" "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild"
|
||||
#
|
||||
# Revert the order of limits.
|
||||
#
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/mother/child"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother/child/grandchild"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/file"
|
||||
log_must truncate -s 1G "$TESTDIR/mother/child/grandchild/file"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/mother/child/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child/grandchild" "$TESTPOOL/$TESTFS/grandchild"
|
||||
log_must ratelimit_bw 1 10 1 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother/child" "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/mother" "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 12 6 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
# Changing limits at the bottom doesn't affect ancestors.
|
||||
log_must zfs set limit_bw_read=6M "$TESTPOOL/$TESTFS/grandchild/child/mother"
|
||||
log_must ratelimit_bw 1 10 1 "$TESTDIR/grandchild/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/grandchild/child/file" "/dev/null"
|
||||
log_must ratelimit_bw 1 12 3 "$TESTDIR/grandchild/child/mother/file" "/dev/null"
|
||||
log_must zfs rename "$TESTPOOL/$TESTFS/grandchild/child/mother" "$TESTPOOL/$TESTFS/mother"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/mother"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild/child"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/grandchild"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/mother"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/father"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,282 @@
|
|||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
function ratelimit_reset
|
||||
{
|
||||
|
||||
for dataset in $(zfs list -H -r -t filesystem,volume -o name $TESTPOOL); do
|
||||
for type in bw op; do
|
||||
for io in read write total; do
|
||||
log_must zfs set limit_${type}_${io}=none $dataset
|
||||
done
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
function stopwatch_start
|
||||
{
|
||||
STARTTIME=$(date "+%s")
|
||||
}
|
||||
|
||||
function stopwatch_stop
|
||||
{
|
||||
typeset -r endtime=$(date "+%s")
|
||||
|
||||
echo $((endtime-STARTTIME))
|
||||
}
|
||||
|
||||
function stopwatch_check
|
||||
{
|
||||
typeset -r exp=$1 # Expected duration.
|
||||
typeset -r delta=$(stopwatch_stop)
|
||||
|
||||
min=$((exp-1))
|
||||
max=$((exp+1))
|
||||
|
||||
if [ $delta -lt $min ]; then
|
||||
log_note "took less time (${delta}s) than expected (${exp}s)"
|
||||
return 1
|
||||
fi
|
||||
if [ $delta -gt $max ]; then
|
||||
log_note "took more time (${delta}s) than expected (${exp}s)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function ddio
|
||||
{
|
||||
typeset -r src=$1
|
||||
typeset -r dst=$2
|
||||
typeset -r cnt=$3
|
||||
|
||||
dd if=$src of=$dst bs=1M count=$cnt conv=notrunc 2>/dev/null
|
||||
}
|
||||
|
||||
function ratelimit_bw_read
|
||||
{
|
||||
typeset -r cnt=$1
|
||||
typeset -r exp=$2
|
||||
|
||||
shift 2
|
||||
|
||||
stopwatch_start
|
||||
for src in $@; do
|
||||
ddio $src /dev/null $cnt &
|
||||
done
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_bw_write
|
||||
{
|
||||
typeset -r cnt=$1
|
||||
typeset -r exp=$2
|
||||
|
||||
shift 2
|
||||
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
for src in $@; do
|
||||
ddio /dev/zero $src $cnt &
|
||||
done
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_bw
|
||||
{
|
||||
typeset -r prs=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
typeset -r src=$4
|
||||
typeset -r dst=$5
|
||||
|
||||
stopwatch_start
|
||||
for i in {1..$prs}; do
|
||||
ddio $src $dst $cnt &
|
||||
done
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_bw_read_single
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
ratelimit_bw 1 $cnt $exp "$TESTDIR/file" "/dev/null"
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_bw_write_single
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
sync_pool $TESTPOOL
|
||||
ratelimit_bw 1 $cnt $exp "/dev/zero" "$TESTDIR/file"
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_bw_read_multiple
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
ratelimit_bw 3 $cnt $exp "$TESTDIR/file" "/dev/null"
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_bw_write_multiple
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
sync_pool $TESTPOOL
|
||||
ratelimit_bw 3 $cnt $exp "/dev/zero" "$TESTDIR/file"
|
||||
}
|
||||
|
||||
function ratelimit_volume_bw_read_single
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS/vol"
|
||||
ratelimit_bw 1 $cnt $exp "/dev/zvol/$TESTPOOL/$TESTFS/vol" "/dev/null"
|
||||
}
|
||||
|
||||
function ratelimit_volume_bw_write_single
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS/vol"
|
||||
sync_pool $TESTPOOL
|
||||
ratelimit_bw 1 $cnt $exp "/dev/zero" "/dev/zvol/$TESTPOOL/$TESTFS/vol"
|
||||
}
|
||||
|
||||
function ratelimit_volume_bw_read_multiple
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS/vol"
|
||||
ratelimit_bw 3 $cnt $exp "/dev/zvol/$TESTPOOL/$TESTFS/vol" "/dev/null"
|
||||
}
|
||||
|
||||
function ratelimit_volume_bw_write_multiple
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS/vol"
|
||||
sync_pool $TESTPOOL
|
||||
ratelimit_bw 3 $cnt $exp "/dev/zero" "/dev/zvol/$TESTPOOL/$TESTFS/vol"
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_op_single
|
||||
{
|
||||
typeset -r sys=$1
|
||||
typeset -r lmt=$2
|
||||
typeset -r cnt=$3
|
||||
typeset -r exp=$4
|
||||
typeset -r pth=$5
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
log_must fsop $cnt $sys $pth
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_op_read_multiple
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
stopwatch_start
|
||||
fsop $cnt stat "$TESTDIR/file" &
|
||||
fsop $cnt readlink "$TESTDIR/symlink" &
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_op_write_multiple_create
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
fsop $cnt chmod "$TESTDIR/file0" &
|
||||
# Creating a file also triggers VOP_GETATTR() on FreeBSD,
|
||||
# so switch to link(2) for the time being when setting
|
||||
# total limits.
|
||||
if is_freebsd && echo $lmt | grep -q limit_op_total=; then
|
||||
fsop $cnt link "$TESTDIR/file1" &
|
||||
else
|
||||
fsop $cnt create "$TESTDIR/file1" &
|
||||
fi
|
||||
fsop $cnt mkdir "$TESTDIR/file2" &
|
||||
fsop $cnt link "$TESTDIR/file3" &
|
||||
fsop $cnt symlink "$TESTDIR/file4" &
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
function ratelimit_filesystem_op_write_multiple_remove
|
||||
{
|
||||
typeset -r lmt=$1
|
||||
typeset -r cnt=$2
|
||||
typeset -r exp=$3
|
||||
|
||||
log_must zfs set $lmt "$TESTPOOL/$TESTFS"
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
fsop $cnt chown "$TESTDIR/file0" &
|
||||
fsop $cnt unlink "$TESTDIR/file1" &
|
||||
fsop $cnt rmdir "$TESTDIR/file2" &
|
||||
fsop $cnt unlink "$TESTDIR/file3" &
|
||||
fsop $cnt unlink "$TESTDIR/file4" &
|
||||
wait
|
||||
stopwatch_check $exp
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
# All ratelimit tests take too much time, so as a part of the common.run
|
||||
# runfile we will execute one random test.
|
||||
# All tests can be run from the ratelimit.run runfile.
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
RATELIMIT_DIR="${STF_SUITE}/tests/functional/ratelimit"
|
||||
|
||||
RATELIMIT_TEST=$(random_get $(ls -1 $RATELIMIT_DIR/*.ksh | grep -Ev '/(cleanup|setup)\.ksh$'))
|
||||
|
||||
log_note "Random test choosen: ${RATELIMIT_TEST}"
|
||||
|
||||
. $RATELIMIT_TEST
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
|
||||
if ! command -v fsop > /dev/null ; then
|
||||
log_unsupported "fsop program required to test ratelimiting"
|
||||
fi
|
||||
|
||||
DISK=${DISKS%% *}
|
||||
|
||||
default_setup_noexit $DISK "true"
|
||||
|
||||
# Make the pool as fast as possible, so we don't have tests failing, because
|
||||
# the test pool is a bit too slow.
|
||||
log_must zfs set atime=off $TESTPOOL
|
||||
log_must zfs set checksum=off $TESTPOOL
|
||||
log_must zfs set compress=zle $TESTPOOL
|
||||
log_must zfs set recordsize=1M $TESTPOOL
|
||||
log_must zfs set sync=disabled $TESTPOOL
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,105 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify configurations where multiple limit types are set"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/vol0" 100M
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/vol1" 100M
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "/dev/zvol/$TESTPOOL/$TESTFS/vol0"
|
||||
log_must ratelimit_bw_write 15 3 "/dev/zvol/$TESTPOOL/$TESTFS/vol1"
|
||||
stopwatch_start
|
||||
ddio "/dev/zvol/$TESTPOOL/$TESTFS/vol0" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "/dev/zvol/$TESTPOOL/$TESTFS/vol1" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/vol0"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/vol1"
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0" 100M
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1" 100M
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0"
|
||||
log_must ratelimit_bw_write 15 3 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1"
|
||||
stopwatch_start
|
||||
ddio "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must zfs set limit_bw_total=6M "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=5M "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must ratelimit_bw_read 12 3 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0"
|
||||
log_must ratelimit_bw_write 15 3 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1"
|
||||
stopwatch_start
|
||||
ddio "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0" "/dev/null" 36 &
|
||||
ddio "/dev/zero" "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1" 36 &
|
||||
wait
|
||||
stopwatch_check 12
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2/vol0"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
211
tests/zfs-tests/tests/functional/ratelimit/volume_bw_hierarchical_horizontal.ksh
Executable file
211
tests/zfs-tests/tests/functional/ratelimit/volume_bw_hierarchical_horizontal.ksh
Executable file
|
@ -0,0 +1,211 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical limits for multiple ZVOLs at the same level"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must truncate -s 1G "$TESTDIR/file"
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/foo" 16M
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar" 16M
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/baz" 16M
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_read 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_read 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_read 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=1M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 3 "/dev/zvol/$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_bw_write 6 6 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_bw_write 6 9 "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
log_must ratelimit_bw_write 6 12 "$TESTDIR/file" "/dev/zvol/$TESTPOOL/$TESTFS/foo" "/dev/zvol/$TESTPOOL/$TESTFS/bar" "/dev/zvol/$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/bar"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/baz"
|
||||
|
||||
rm -f "$TESTDIR/file"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,63 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth read limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2" 16M
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_read=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_read=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_read=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_read 5 5 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,64 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth total limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2" 16M
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_total=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_total=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_total=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_read 5 5 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_write 5 5 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,63 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify hierarchical bandwidth write limits configured on multiple levels"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2" 16M
|
||||
|
||||
for lvl0 in none 1M 3M 5M; do
|
||||
for lvl1 in none 1M 3M 5M; do
|
||||
for lvl2 in none 1M 3M 5M; do
|
||||
# We need at least one level with 1M limit.
|
||||
if [ $lvl0 != "1M" ] && [ $lvl1 != "1M" ] && [ $lvl2 != "1M" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
log_must zfs set limit_bw_write=$lvl0 "$TESTPOOL/$TESTFS/lvl0"
|
||||
log_must zfs set limit_bw_write=$lvl1 "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must zfs set limit_bw_write=$lvl2 "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must ratelimit_bw_write 5 5 "/dev/zvol/$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1/lvl2"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0/lvl1"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/lvl0"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,67 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for multiple active processes"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/vol" 500M
|
||||
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_read=none 500 1
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_read=1M 5 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_read=10M 50 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_read=100M 500 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_read=none 500 1
|
||||
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_total=none 500 1
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_total=1M 5 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_total=10M 50 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_total=100M 500 15
|
||||
log_must ratelimit_volume_bw_read_multiple limit_bw_total=none 500 1
|
||||
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_write=none 500 1
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_write=1M 5 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_write=10M 50 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_write=100M 500 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_write=none 500 1
|
||||
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_total=none 500 1
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_total=1M 5 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_total=10M 50 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_total=100M 500 15
|
||||
log_must ratelimit_volume_bw_write_multiple limit_bw_total=none 500 1
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/vol"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,171 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for zfs receive"
|
||||
|
||||
function ratelimit_recv
|
||||
{
|
||||
typeset -r exp=$1
|
||||
typeset res
|
||||
|
||||
shift
|
||||
|
||||
sync_pool $TESTPOOL
|
||||
stopwatch_start
|
||||
zfs send "$TESTPOOL/$TESTFS/foo@snap" | zfs recv -F $@ "$TESTPOOL/$TESTFS/bar/baz" >/dev/null
|
||||
stopwatch_check $exp
|
||||
res=$?
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/bar/baz@snap"
|
||||
destroy_dataset "$TESTPOOL/$TESTFS/bar/baz"
|
||||
return $res
|
||||
}
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/foo" 16M
|
||||
log_must dd if=/dev/urandom of="/dev/zvol/$TESTPOOL/$TESTFS/foo" bs=1M count=16
|
||||
log_must create_snapshot "$TESTPOOL/$TESTFS/foo" "snap"
|
||||
log_must create_dataset "$TESTPOOL/$TESTFS/bar"
|
||||
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=8M
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=8M
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 1
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=none -o limit_bw_total=4M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=4M -o limit_bw_total=none
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=none -o limit_bw_total=8M
|
||||
|
||||
log_must zfs set limit_bw_write=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/bar/baz" 16M
|
||||
log_must zfs set limit_bw_write=8M "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar/baz"
|
||||
log_must ratelimit_recv 4
|
||||
|
||||
log_must zfs set limit_bw_write=4M "$TESTPOOL/$TESTFS/bar"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/bar"
|
||||
log_must ratelimit_recv 4 -o limit_bw_write=8M -o limit_bw_total=none
|
||||
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/foo@snap"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,111 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify bandwidth limits for zfs send"
|
||||
|
||||
function ratelimit_send
|
||||
{
|
||||
typeset -r exp=$1
|
||||
|
||||
stopwatch_start
|
||||
zfs send "$TESTPOOL/$TESTFS/foo@snap" >/dev/null
|
||||
stopwatch_check $exp
|
||||
}
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/foo" 16M
|
||||
log_must dd if=/dev/urandom of="/dev/zvol/$TESTPOOL/$TESTFS/foo" bs=1M count=16
|
||||
log_must create_snapshot "$TESTPOOL/$TESTFS/foo" "snap"
|
||||
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_read=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 8
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_total=2M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 8
|
||||
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 1
|
||||
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
log_must zfs set limit_bw_read=none "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_total=8M "$TESTPOOL/$TESTFS"
|
||||
log_must zfs set limit_bw_read=4M "$TESTPOOL/$TESTFS/foo"
|
||||
log_must zfs set limit_bw_total=none "$TESTPOOL/$TESTFS/foo"
|
||||
log_must ratelimit_send 4
|
||||
|
||||
destroy_snapshot "$TESTPOOL/$TESTFS/foo@snap"
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/foo"
|
||||
|
||||
log_pass
|
|
@ -0,0 +1,85 @@
|
|||
#! /bin/ksh -p
|
||||
#
|
||||
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||
# 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) 2024 The FreeBSD Foundation
|
||||
#
|
||||
# This software was developed by Pawel Dawidek <pawel@dawidek.net>
|
||||
# under sponsorship from the FreeBSD Foundation.
|
||||
#
|
||||
|
||||
. $STF_SUITE/include/libtest.shlib
|
||||
. $STF_SUITE/tests/functional/ratelimit/ratelimit_common.kshlib
|
||||
|
||||
verify_runnable "both"
|
||||
|
||||
log_assert "Verify various bandwidth limits for a single active process"
|
||||
|
||||
ratelimit_reset
|
||||
|
||||
log_must create_volume "$TESTPOOL/$TESTFS/vol" 500M
|
||||
|
||||
# Bandwidth read limits.
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_read=none 500 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_read=1M 5 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_read=10M 50 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_read=100M 500 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_read=none 500 1
|
||||
|
||||
# Bandwidth total limits limit reading.
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_total=none 500 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_total=1M 5 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_total=10M 50 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_total=100M 500 5
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_total=none 500 1
|
||||
|
||||
# Bandwidth write limits don't affect reading.
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_write=none 500 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_write=1M 5 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_write=10M 50 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_write=100M 500 1
|
||||
log_must ratelimit_volume_bw_read_single limit_bw_write=none 500 1
|
||||
|
||||
# Bandwidth write limits.
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_write=none 500 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_write=1M 5 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_write=10M 50 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_write=100M 500 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_write=none 500 1
|
||||
|
||||
# Bandwidth total limits limit writing.
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_total=none 500 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_total=1M 5 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_total=10M 50 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_total=100M 500 5
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_total=none 500 1
|
||||
|
||||
# Bandwidth read limits don't affect writing.
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_read=none 500 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_read=1M 5 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_read=10M 50 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_read=100M 500 1
|
||||
log_must ratelimit_volume_bw_write_single limit_bw_read=none 500 1
|
||||
|
||||
log_must destroy_dataset "$TESTPOOL/$TESTFS/vol"
|
||||
|
||||
log_pass
|
Loading…
Reference in New Issue