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) {
|
if (!zfs_prop_inheritable(prop) && !received) {
|
||||||
(void) fprintf(stderr, gettext("'%s' property cannot "
|
(void) fprintf(stderr, gettext("'%s' property cannot "
|
||||||
"be inherited\n"), propname);
|
"be inherited\n"), propname);
|
||||||
if (prop == ZFS_PROP_QUOTA ||
|
switch (prop) {
|
||||||
prop == ZFS_PROP_RESERVATION ||
|
case ZFS_PROP_QUOTA:
|
||||||
prop == ZFS_PROP_REFQUOTA ||
|
case ZFS_PROP_RESERVATION:
|
||||||
prop == ZFS_PROP_REFRESERVATION) {
|
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 "
|
(void) fprintf(stderr, gettext("use 'zfs set "
|
||||||
"%s=none' to clear\n"), propname);
|
"%s=none' to clear\n"), propname);
|
||||||
(void) fprintf(stderr, gettext("use 'zfs "
|
(void) fprintf(stderr, gettext("use 'zfs "
|
||||||
"inherit -S %s' to revert to received "
|
"inherit -S %s' to revert to received "
|
||||||
"value\n"), propname);
|
"value\n"), propname);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,9 +168,12 @@ zfs_exit(zfsvfs_t *zfsvfs, const char *tag)
|
||||||
(tp)->tv_sec = (time_t)(stmp)[0]; \
|
(tp)->tv_sec = (time_t)(stmp)[0]; \
|
||||||
(tp)->tv_nsec = (long)(stmp)[1]; \
|
(tp)->tv_nsec = (long)(stmp)[1]; \
|
||||||
}
|
}
|
||||||
#define ZFS_ACCESSTIME_STAMP(zfsvfs, zp) \
|
#define ZFS_ACCESSTIME_STAMP(zfsvfs, zp) do { \
|
||||||
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY)) \
|
if ((zfsvfs)->z_atime && !((zfsvfs)->z_vfs->vfs_flag & VFS_RDONLY)) { \
|
||||||
zfs_tstamp_update_setup_ext(zp, ACCESSED, NULL, NULL, B_FALSE);
|
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 *,
|
extern void zfs_tstamp_update_setup_ext(struct znode *,
|
||||||
uint_t, uint64_t [2], uint64_t [2], boolean_t have_tx);
|
uint_t, uint64_t [2], uint64_t [2], boolean_t have_tx);
|
||||||
|
|
|
@ -42,6 +42,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct dsl_dataset;
|
struct dsl_dataset;
|
||||||
|
struct vfs_ratelimit;
|
||||||
struct zthr;
|
struct zthr;
|
||||||
/*
|
/*
|
||||||
* DD_FIELD_* are strings that are used in the "extensified" dsl_dir zap object.
|
* 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;
|
boolean_t dd_activity_cancelled;
|
||||||
uint64_t dd_activity_waiters;
|
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 */
|
/* protected by dd_lock; keep at end of struct for better locality */
|
||||||
char dd_myname[ZFS_MAX_DATASET_NAME_LEN];
|
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);
|
uint64_t quota);
|
||||||
int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
|
int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
|
||||||
uint64_t reservation);
|
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_dir_activate_fs_ss_limit(const char *);
|
||||||
int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
|
int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
|
||||||
cred_t *, proc_t *);
|
cred_t *, proc_t *);
|
||||||
|
|
|
@ -193,6 +193,12 @@ typedef enum {
|
||||||
ZFS_PROP_SNAPSHOTS_CHANGED,
|
ZFS_PROP_SNAPSHOTS_CHANGED,
|
||||||
ZFS_PROP_PREFETCH,
|
ZFS_PROP_PREFETCH,
|
||||||
ZFS_PROP_VOLTHREADING,
|
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_NUM_PROPS
|
||||||
} zfs_prop_t;
|
} zfs_prop_t;
|
||||||
|
|
||||||
|
|
|
@ -457,6 +457,8 @@ struct spa {
|
||||||
uint64_t spa_leaf_list_gen; /* track leaf_list changes */
|
uint64_t spa_leaf_list_gen; /* track leaf_list changes */
|
||||||
uint32_t spa_hostid; /* cached system hostid */
|
uint32_t spa_hostid; /* cached system hostid */
|
||||||
|
|
||||||
|
rrmlock_t spa_ratelimit_lock;
|
||||||
|
|
||||||
/* synchronization for threads in spa_wait */
|
/* synchronization for threads in spa_wait */
|
||||||
kmutex_t spa_activities_lock;
|
kmutex_t spa_activities_lock;
|
||||||
kcondvar_t spa_activities_cv;
|
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_SNAPSHOTS_CHANGED' value='95'/>
|
||||||
<enumerator name='ZFS_PROP_PREFETCH' value='96'/>
|
<enumerator name='ZFS_PROP_PREFETCH' value='96'/>
|
||||||
<enumerator name='ZFS_PROP_VOLTHREADING' value='97'/>
|
<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>
|
</enum-decl>
|
||||||
<typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
|
<typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
|
||||||
<enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>
|
<enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include <sys/spa.h>
|
#include <sys/spa.h>
|
||||||
#include <sys/zap.h>
|
#include <sys/zap.h>
|
||||||
#include <sys/dsl_crypt.h>
|
#include <sys/dsl_crypt.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
#include <libzutil.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_SNAPSHOT_LIMIT:
|
||||||
case ZFS_PROP_FILESYSTEM_COUNT:
|
case ZFS_PROP_FILESYSTEM_COUNT:
|
||||||
case ZFS_PROP_SNAPSHOT_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);
|
*val = getprop_uint64(zhp, prop, source);
|
||||||
|
|
||||||
if (*source == NULL) {
|
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_REFQUOTA:
|
||||||
case ZFS_PROP_RESERVATION:
|
case ZFS_PROP_RESERVATION:
|
||||||
case ZFS_PROP_REFRESERVATION:
|
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)
|
if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
|
||||||
return (-1);
|
return (-1);
|
||||||
/*
|
/*
|
||||||
* If quota or reservation is 0, we translate this into 'none'
|
* If the value is 0, we translate this into 'none' (unless
|
||||||
* (unless literal is set), and indicate that it's the default
|
* literal is set), and indicate that it's the default
|
||||||
* value. Otherwise, we print the number nicely and indicate
|
* value. Otherwise, we print the number nicely and indicate
|
||||||
* that its set locally.
|
* 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);
|
zcp_check(zhp, prop, val, NULL);
|
||||||
break;
|
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_FILESYSTEM_LIMIT:
|
||||||
case ZFS_PROP_SNAPSHOT_LIMIT:
|
case ZFS_PROP_SNAPSHOT_LIMIT:
|
||||||
case ZFS_PROP_FILESYSTEM_COUNT:
|
case ZFS_PROP_FILESYSTEM_COUNT:
|
||||||
|
|
|
@ -162,6 +162,7 @@ nodist_libzpool_la_SOURCES = \
|
||||||
module/zfs/vdev_removal.c \
|
module/zfs/vdev_removal.c \
|
||||||
module/zfs/vdev_root.c \
|
module/zfs/vdev_root.c \
|
||||||
module/zfs/vdev_trim.c \
|
module/zfs/vdev_trim.c \
|
||||||
|
module/zfs/vfs_ratelimit.c \
|
||||||
module/zfs/zap.c \
|
module/zfs/zap.c \
|
||||||
module/zfs/zap_leaf.c \
|
module/zfs/zap_leaf.c \
|
||||||
module/zfs/zap_micro.c \
|
module/zfs/zap_micro.c \
|
||||||
|
|
|
@ -1184,6 +1184,117 @@ and the minimum is
|
||||||
.Sy 100000 .
|
.Sy 100000 .
|
||||||
This property may be changed with
|
This property may be changed with
|
||||||
.Nm zfs Cm change-key .
|
.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
|
.It Sy exec Ns = Ns Sy on Ns | Ns Sy off
|
||||||
Controls whether processes can be executed from within this file system.
|
Controls whether processes can be executed from within this file system.
|
||||||
The default value is
|
The default value is
|
||||||
|
|
|
@ -397,6 +397,7 @@ ZFS_OBJS := \
|
||||||
vdev_removal.o \
|
vdev_removal.o \
|
||||||
vdev_root.o \
|
vdev_root.o \
|
||||||
vdev_trim.o \
|
vdev_trim.o \
|
||||||
|
vfs_ratelimit.o \
|
||||||
zap.o \
|
zap.o \
|
||||||
zap_leaf.o \
|
zap_leaf.o \
|
||||||
zap_micro.o \
|
zap_micro.o \
|
||||||
|
|
|
@ -331,6 +331,7 @@ SRCS+= abd.c \
|
||||||
vdev_removal.c \
|
vdev_removal.c \
|
||||||
vdev_root.c \
|
vdev_root.c \
|
||||||
vdev_trim.c \
|
vdev_trim.c \
|
||||||
|
vfs_ratelimit.c \
|
||||||
zap.c \
|
zap.c \
|
||||||
zap_leaf.c \
|
zap_leaf.c \
|
||||||
zap_micro.c \
|
zap_micro.c \
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
#include <sys/acl.h>
|
#include <sys/acl.h>
|
||||||
#include <sys/vmmeter.h>
|
#include <sys/vmmeter.h>
|
||||||
#include <vm/vm_param.h>
|
#include <vm/vm_param.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zil.h>
|
#include <sys/zil.h>
|
||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/module.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;
|
obj = vp->v_object;
|
||||||
ASSERT3P(obj, !=, NULL);
|
ASSERT3P(obj, !=, NULL);
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(zp->z_zfsvfs->z_os, PAGESIZE, len);
|
||||||
|
|
||||||
off = start & PAGEOFFSET;
|
off = start & PAGEOFFSET;
|
||||||
zfs_vmobject_wlock_12(obj);
|
zfs_vmobject_wlock_12(obj);
|
||||||
#if __FreeBSD_version >= 1300041
|
#if __FreeBSD_version >= 1300041
|
||||||
|
@ -542,6 +545,8 @@ mappedread_sf(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
||||||
ASSERT3P(obj, !=, NULL);
|
ASSERT3P(obj, !=, NULL);
|
||||||
ASSERT0(zfs_uio_offset(uio) & PAGEOFFSET);
|
ASSERT0(zfs_uio_offset(uio) & PAGEOFFSET);
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(os, PAGESIZE, len);
|
||||||
|
|
||||||
zfs_vmobject_wlock_12(obj);
|
zfs_vmobject_wlock_12(obj);
|
||||||
for (start = zfs_uio_offset(uio); len > 0; start += PAGESIZE) {
|
for (start = zfs_uio_offset(uio); len > 0; start += PAGESIZE) {
|
||||||
int bytes = MIN(PAGESIZE, len);
|
int bytes = MIN(PAGESIZE, len);
|
||||||
|
@ -621,6 +626,8 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
||||||
obj = vp->v_object;
|
obj = vp->v_object;
|
||||||
ASSERT3P(obj, !=, NULL);
|
ASSERT3P(obj, !=, NULL);
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(zp->z_zfsvfs->z_os, PAGESIZE, nbytes);
|
||||||
|
|
||||||
start = zfs_uio_offset(uio);
|
start = zfs_uio_offset(uio);
|
||||||
off = start & PAGEOFFSET;
|
off = start & PAGEOFFSET;
|
||||||
zfs_vmobject_wlock_12(obj);
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(os);
|
||||||
|
|
||||||
getnewvnode_reserve_();
|
getnewvnode_reserve_();
|
||||||
|
|
||||||
tx = dmu_tx_create(os);
|
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);
|
ASSERT0(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may delete the znode now, or we may put it in the unlinked set;
|
* 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
|
* 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));
|
return (SET_ERROR(EDQUOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a new entry to the directory.
|
* 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);
|
vnevent_rmdir(vp, dvp, name, ct);
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
|
dmu_tx_hold_zap(tx, dzp->z_id, FALSE, name);
|
||||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
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;
|
iovp = GET_UIO_STRUCT(uio)->uio_iov;
|
||||||
bytes_wanted = iovp->iov_len;
|
bytes_wanted = iovp->iov_len;
|
||||||
|
bufsize = bytes_wanted;
|
||||||
if (zfs_uio_segflg(uio) != UIO_SYSSPACE || zfs_uio_iovcnt(uio) != 1) {
|
if (zfs_uio_segflg(uio) != UIO_SYSSPACE || zfs_uio_iovcnt(uio) != 1) {
|
||||||
bufsize = bytes_wanted;
|
|
||||||
outbuf = kmem_alloc(bufsize, KM_SLEEP);
|
outbuf = kmem_alloc(bufsize, KM_SLEEP);
|
||||||
odp = (struct dirent64 *)outbuf;
|
odp = (struct dirent64 *)outbuf;
|
||||||
} else {
|
} else {
|
||||||
bufsize = bytes_wanted;
|
|
||||||
outbuf = NULL;
|
outbuf = NULL;
|
||||||
odp = (struct dirent64 *)iovp->iov_base;
|
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)
|
if (ncookies != NULL)
|
||||||
*ncookies -= ncooks;
|
*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) {
|
if (zfs_uio_segflg(uio) == UIO_SYSSPACE && zfs_uio_iovcnt(uio) == 1) {
|
||||||
iovp->iov_base += outcount;
|
iovp->iov_base += outcount;
|
||||||
iovp->iov_len -= 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
|
* Return all attributes. It's cheaper to provide the answer
|
||||||
* than to determine whether we were asked the question.
|
* 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;
|
goto out2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(os);
|
||||||
|
|
||||||
tx = dmu_tx_create(os);
|
tx = dmu_tx_create(os);
|
||||||
|
|
||||||
if (mask & AT_MODE) {
|
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);
|
vnevent_rename_dest_dir(tdvp, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(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, szp->z_sa_hdl, B_FALSE);
|
||||||
dmu_tx_hold_sa(tx, sdzp->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));
|
return (SET_ERROR(EDQUOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
getnewvnode_reserve_();
|
getnewvnode_reserve_();
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
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)
|
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||||
|
|
||||||
if (zp->z_is_sa)
|
if (zp->z_is_sa)
|
||||||
error = sa_lookup_uio(zp->z_sa_hdl,
|
error = sa_lookup_uio(zp->z_sa_hdl,
|
||||||
SA_ZPL_SYMLINK(zfsvfs), uio);
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(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, szp->z_sa_hdl, B_FALSE);
|
||||||
dmu_tx_hold_zap(tx, tdzp->z_id, TRUE, name);
|
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);
|
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
|
* 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
|
* 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;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_data_write(zfsvfs->z_os, zp->z_blksz, len);
|
||||||
|
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
dmu_tx_hold_write(tx, zp->z_id, off, len);
|
dmu_tx_hold_write(tx, zp->z_id, off, len);
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@
|
||||||
#include <sys/dataset_kstats.h>
|
#include <sys/dataset_kstats.h>
|
||||||
#include <sys/dbuf.h>
|
#include <sys/dbuf.h>
|
||||||
#include <sys/dmu_tx.h>
|
#include <sys/dmu_tx.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
#include <sys/zio_checksum.h>
|
#include <sys/zio_checksum.h>
|
||||||
#include <sys/zil_impl.h>
|
#include <sys/zil_impl.h>
|
||||||
|
@ -729,6 +730,8 @@ zvol_geom_bio_strategy(struct bio *bp)
|
||||||
doread ? RL_READER : RL_WRITER);
|
doread ? RL_READER : RL_WRITER);
|
||||||
|
|
||||||
if (bp->bio_cmd == BIO_DELETE) {
|
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);
|
dmu_tx_t *tx = dmu_tx_create(zv->zv_objset);
|
||||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
@ -745,9 +748,13 @@ zvol_geom_bio_strategy(struct bio *bp)
|
||||||
while (resid != 0 && off < volsize) {
|
while (resid != 0 && off < volsize) {
|
||||||
size_t size = MIN(resid, zvol_maxphys);
|
size_t size = MIN(resid, zvol_maxphys);
|
||||||
if (doread) {
|
if (doread) {
|
||||||
|
vfs_ratelimit_data_read(zv->zv_objset,
|
||||||
|
zv->zv_volblocksize, size);
|
||||||
error = dmu_read(os, ZVOL_OBJ, off, size, addr,
|
error = dmu_read(os, ZVOL_OBJ, off, size, addr,
|
||||||
DMU_READ_PREFETCH);
|
DMU_READ_PREFETCH);
|
||||||
} else {
|
} else {
|
||||||
|
vfs_ratelimit_data_write(zv->zv_objset,
|
||||||
|
zv->zv_volblocksize, size);
|
||||||
dmu_tx_t *tx = dmu_tx_create(os);
|
dmu_tx_t *tx = dmu_tx_create(os);
|
||||||
dmu_tx_hold_write_by_dnode(tx, zv->zv_dn, off, size);
|
dmu_tx_hold_write_by_dnode(tx, zv->zv_dn, off, size);
|
||||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
#include <sys/zpl.h>
|
#include <sys/zpl.h>
|
||||||
#include <sys/zil.h>
|
#include <sys/zil.h>
|
||||||
#include <sys/sa_impl.h>
|
#include <sys/sa_impl.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Programming rules.
|
* Programming rules.
|
||||||
|
@ -237,9 +238,12 @@ static int zfs_fillpage(struct inode *ip, struct page *pp);
|
||||||
void
|
void
|
||||||
update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
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;
|
struct address_space *mp = ZTOI(zp)->i_mapping;
|
||||||
int64_t off = start & (PAGE_SIZE - 1);
|
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) {
|
for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
|
||||||
uint64_t nbytes = MIN(PAGE_SIZE - off, len);
|
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.
|
* from memory mapped pages, otherwise fallback to reading through the dmu.
|
||||||
*/
|
*/
|
||||||
int
|
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 inode *ip = ZTOI(zp);
|
||||||
struct address_space *mp = ip->i_mapping;
|
struct address_space *mp = ip->i_mapping;
|
||||||
int64_t start = uio->uio_loffset;
|
int64_t start = uio->uio_loffset;
|
||||||
int64_t off = start & (PAGE_SIZE - 1);
|
int64_t off = start & (PAGE_SIZE - 1);
|
||||||
int len = nbytes;
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(zfsvfs->z_os, PAGESIZE, len);
|
||||||
|
|
||||||
for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
|
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);
|
struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT);
|
||||||
if (pp) {
|
if (pp) {
|
||||||
|
@ -314,7 +320,7 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
||||||
unlock_page(pp);
|
unlock_page(pp);
|
||||||
|
|
||||||
void *pb = kmap(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);
|
kunmap(pp);
|
||||||
|
|
||||||
if (mapping_writably_mapped(mp))
|
if (mapping_writably_mapped(mp))
|
||||||
|
@ -324,10 +330,10 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
|
||||||
put_page(pp);
|
put_page(pp);
|
||||||
} else {
|
} else {
|
||||||
error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
|
error = dmu_read_uio_dbuf(sa_get_db(zp->z_sa_hdl),
|
||||||
uio, bytes);
|
uio, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
len -= bytes;
|
len -= nbytes;
|
||||||
off = 0;
|
off = 0;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -677,6 +683,8 @@ top:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(os);
|
||||||
|
|
||||||
tx = dmu_tx_create(os);
|
tx = dmu_tx_create(os);
|
||||||
|
|
||||||
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
||||||
|
@ -871,6 +879,8 @@ top:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(os);
|
||||||
|
|
||||||
tx = dmu_tx_create(os);
|
tx = dmu_tx_create(os);
|
||||||
|
|
||||||
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
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);
|
!zn_has_cached_data(zp, 0, LLONG_MAX);
|
||||||
mutex_exit(&zp->z_lock);
|
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;
|
* 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
|
* it depends on whether we're the last link, and on whether there are
|
||||||
|
@ -1278,6 +1290,8 @@ top:
|
||||||
return (SET_ERROR(EDQUOT));
|
return (SET_ERROR(EDQUOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a new entry to the directory.
|
* Add a new entry to the directory.
|
||||||
*/
|
*/
|
||||||
|
@ -1420,6 +1434,8 @@ top:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grab a lock on the directory to make sure that no one is
|
* Grab a lock on the directory to make sure that no one is
|
||||||
* trying to add (or lookup) entries while we are removing it.
|
* 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 */
|
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:
|
update:
|
||||||
zap_cursor_fini(&zc);
|
zap_cursor_fini(&zc);
|
||||||
if (error == ENOENT)
|
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)
|
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||||
|
|
||||||
mutex_enter(&zp->z_lock);
|
mutex_enter(&zp->z_lock);
|
||||||
|
|
||||||
#ifdef HAVE_GENERIC_FILLATTR_IDMAP_REQMASK
|
#ifdef HAVE_GENERIC_FILLATTR_IDMAP_REQMASK
|
||||||
|
@ -2269,6 +2297,9 @@ top:
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(os);
|
||||||
|
|
||||||
tx = dmu_tx_create(os);
|
tx = dmu_tx_create(os);
|
||||||
|
|
||||||
if (mask & ATTR_MODE) {
|
if (mask & ATTR_MODE) {
|
||||||
|
@ -2981,6 +3012,8 @@ top:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(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, szp->z_sa_hdl, B_FALSE);
|
||||||
dmu_tx_hold_sa(tx, sdzp->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);
|
zfs_exit(zfsvfs, FTAG);
|
||||||
return (SET_ERROR(EDQUOT));
|
return (SET_ERROR(EDQUOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
fuid_dirtied = zfsvfs->z_fuid_dirty;
|
||||||
dmu_tx_hold_write(tx, DMU_NEW_OBJECT, 0, MAX(1, len));
|
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)
|
if ((error = zfs_enter_verify_zp(zfsvfs, zp, FTAG)) != 0)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_read(zfsvfs->z_os);
|
||||||
|
|
||||||
mutex_enter(&zp->z_lock);
|
mutex_enter(&zp->z_lock);
|
||||||
if (zp->z_is_sa)
|
if (zp->z_is_sa)
|
||||||
error = sa_lookup_uio(zp->z_sa_hdl,
|
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);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
top:
|
top:
|
||||||
/*
|
/*
|
||||||
* Attempt to lock directory; fail if entry already exists.
|
* 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);
|
set_page_writeback(pp);
|
||||||
unlock_page(pp);
|
unlock_page(pp);
|
||||||
|
|
||||||
|
vfs_ratelimit_data_write(zfsvfs->z_os, zp->z_blksz, pglen);
|
||||||
|
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
|
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
|
||||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||||
|
@ -3905,6 +3947,8 @@ zfs_dirty_inode(struct inode *ip, int flags)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
vfs_ratelimit_metadata_write(zfsvfs->z_os);
|
||||||
|
|
||||||
tx = dmu_tx_create(zfsvfs->z_os);
|
tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
|
|
||||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
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) {
|
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_t *tx = dmu_tx_create(zfsvfs->z_os);
|
||||||
|
|
||||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
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)
|
if (io_off + io_len > i_size)
|
||||||
io_len = i_size - io_off;
|
io_len = i_size - io_off;
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(zfsvfs->z_os, PAGESIZE, io_len);
|
||||||
|
|
||||||
void *va = kmap(pp);
|
void *va = kmap(pp);
|
||||||
int error = dmu_read(zfsvfs->z_os, ITOZ(ip)->z_id, io_off,
|
int error = dmu_read(zfsvfs->z_os, ITOZ(ip)->z_id, io_off,
|
||||||
io_len, va, DMU_READ_PREFETCH);
|
io_len, va, DMU_READ_PREFETCH);
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <sys/zio.h>
|
#include <sys/zio.h>
|
||||||
#include <sys/zfs_rlock.h>
|
#include <sys/zfs_rlock.h>
|
||||||
#include <sys/spa_impl.h>
|
#include <sys/spa_impl.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zvol.h>
|
#include <sys/zvol.h>
|
||||||
#include <sys/zvol_impl.h>
|
#include <sys/zvol_impl.h>
|
||||||
#include <cityhash.h>
|
#include <cityhash.h>
|
||||||
|
@ -293,11 +294,15 @@ zvol_write(zv_request_t *zvr)
|
||||||
while (uio.uio_resid > 0 && uio.uio_loffset < volsize) {
|
while (uio.uio_resid > 0 && uio.uio_loffset < volsize) {
|
||||||
uint64_t bytes = MIN(uio.uio_resid, DMU_MAX_ACCESS >> 1);
|
uint64_t bytes = MIN(uio.uio_resid, DMU_MAX_ACCESS >> 1);
|
||||||
uint64_t off = uio.uio_loffset;
|
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 */
|
if (bytes > volsize - off) /* don't write past the end */
|
||||||
bytes = volsize - off;
|
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);
|
dmu_tx_hold_write_by_dnode(tx, zv->zv_dn, off, bytes);
|
||||||
|
|
||||||
/* This will only fail for ENOSPC */
|
/* 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,
|
zfs_locked_range_t *lr = zfs_rangelock_enter(&zv->zv_rangelock,
|
||||||
start, size, RL_WRITER);
|
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);
|
tx = dmu_tx_create(zv->zv_objset);
|
||||||
dmu_tx_mark_netfree(tx);
|
dmu_tx_mark_netfree(tx);
|
||||||
error = dmu_tx_assign(tx, TXG_WAIT);
|
error = dmu_tx_assign(tx, TXG_WAIT);
|
||||||
|
@ -476,6 +484,9 @@ zvol_read(zv_request_t *zvr)
|
||||||
if (bytes > volsize - uio.uio_loffset)
|
if (bytes > volsize - uio.uio_loffset)
|
||||||
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);
|
error = dmu_read_uio_dnode(zv->zv_dn, &uio, bytes);
|
||||||
if (error) {
|
if (error) {
|
||||||
/* convert checksum errors into IO errors */
|
/* convert checksum errors into IO errors */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <sys/zio.h>
|
#include <sys/zio.h>
|
||||||
#include <sys/spa.h>
|
#include <sys/spa.h>
|
||||||
#include <sys/u8_textprep.h>
|
#include <sys/u8_textprep.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zfs_acl.h>
|
#include <sys/zfs_acl.h>
|
||||||
#include <sys/zfs_ioctl.h>
|
#include <sys/zfs_ioctl.h>
|
||||||
#include <sys/zfs_znode.h>
|
#include <sys/zfs_znode.h>
|
||||||
|
@ -694,6 +695,24 @@ zfs_prop_init(void)
|
||||||
zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
|
zprop_register_number(ZFS_PROP_SNAPSHOT_LIMIT, "snapshot_limit",
|
||||||
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
UINT64_MAX, PROP_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
|
||||||
"<count> | none", "SSLIMIT", B_FALSE, sfeatures);
|
"<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 */
|
/* inherit number properties */
|
||||||
zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
|
zprop_register_number(ZFS_PROP_RECORDSIZE, "recordsize",
|
||||||
|
@ -997,7 +1016,6 @@ zfs_prop_valid_keylocation(const char *str, boolean_t encrypted)
|
||||||
return (B_FALSE);
|
return (B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef _KERNEL
|
#ifndef _KERNEL
|
||||||
#include <libzfs.h>
|
#include <libzfs.h>
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
#include <sys/bqueue.h>
|
#include <sys/bqueue.h>
|
||||||
#include <sys/objlist.h>
|
#include <sys/objlist.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -2204,6 +2205,9 @@ flush_write_batch_impl(struct receive_writer_arg *rwa)
|
||||||
|
|
||||||
ASSERT3U(drrw->drr_object, ==, rwa->last_object);
|
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) {
|
if (drrw->drr_logical_size != dn->dn_datablksz) {
|
||||||
/*
|
/*
|
||||||
* The WRITE record is larger than the object's block
|
* The WRITE record is larger than the object's block
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include <sys/zvol.h>
|
#include <sys/zvol.h>
|
||||||
#include <sys/policy.h>
|
#include <sys/policy.h>
|
||||||
#include <sys/objlist.h>
|
#include <sys/objlist.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -1684,6 +1685,8 @@ issue_data_read(struct send_reader_thread_arg *srta, struct send_range *range)
|
||||||
.zb_blkid = range->start_blkid,
|
.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;
|
arc_flags_t aflags = ARC_FLAG_CACHED_ONLY;
|
||||||
|
|
||||||
int arc_err = arc_read(NULL, os->os_spa, bp,
|
int arc_err = arc_read(NULL, os->os_spa, bp,
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include <sys/sunddi.h>
|
#include <sys/sunddi.h>
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
#include <sys/policy.h>
|
#include <sys/policy.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zfs_vfsops.h>
|
#include <sys/zfs_vfsops.h>
|
||||||
#include <sys/zfs_znode.h>
|
#include <sys/zfs_znode.h>
|
||||||
#include <sys/zvol.h>
|
#include <sys/zvol.h>
|
||||||
|
@ -143,7 +144,7 @@ dsl_dir_evict_async(void *dbu)
|
||||||
{
|
{
|
||||||
dsl_dir_t *dd = dbu;
|
dsl_dir_t *dd = dbu;
|
||||||
int t;
|
int t;
|
||||||
dsl_pool_t *dp __maybe_unused = dd->dd_pool;
|
dsl_pool_t *dp = dd->dd_pool;
|
||||||
|
|
||||||
dd->dd_dbuf = NULL;
|
dd->dd_dbuf = NULL;
|
||||||
|
|
||||||
|
@ -161,6 +162,19 @@ dsl_dir_evict_async(void *dbu)
|
||||||
if (dsl_deadlist_is_open(&dd->dd_livelist))
|
if (dsl_deadlist_is_open(&dd->dd_livelist))
|
||||||
dsl_dir_livelist_close(dd);
|
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);
|
dsl_prop_fini(dd);
|
||||||
cv_destroy(&dd->dd_activity_cv);
|
cv_destroy(&dd->dd_activity_cv);
|
||||||
mutex_destroy(&dd->dd_activity_lock);
|
mutex_destroy(&dd->dd_activity_lock);
|
||||||
|
@ -168,6 +182,75 @@ dsl_dir_evict_async(void *dbu)
|
||||||
kmem_free(dd, sizeof (dsl_dir_t));
|
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
|
int
|
||||||
dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
dsl_dir_hold_obj(dsl_pool_t *dp, uint64_t ddobj,
|
||||||
const char *tail, const void *tag, dsl_dir_t **ddp)
|
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;
|
dd = winner;
|
||||||
} else {
|
} else {
|
||||||
spa_open_ref(dp->dp_spa, dd);
|
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));
|
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 {
|
typedef struct dsl_dir_rename_arg {
|
||||||
const char *ddra_oldname;
|
const char *ddra_oldname;
|
||||||
const char *ddra_newname;
|
const char *ddra_newname;
|
||||||
|
@ -2105,6 +2312,22 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
|
||||||
return (0);
|
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
|
static void
|
||||||
dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
|
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,
|
dsl_fs_ss_count_adjust(newparent, ss_cnt,
|
||||||
DD_FIELD_SNAPSHOT_COUNT, tx);
|
DD_FIELD_SNAPSHOT_COUNT, tx);
|
||||||
|
|
||||||
|
dsl_dir_ratelimit_rename(dd, newparent);
|
||||||
|
|
||||||
dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
|
dsl_dir_diduse_space(dd->dd_parent, DD_USED_CHILD,
|
||||||
-dsl_dir_phys(dd)->dd_used_bytes,
|
-dsl_dir_phys(dd)->dd_used_bytes,
|
||||||
-dsl_dir_phys(dd)->dd_compressed_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_flushed_ms_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||||
mutex_init(&spa->spa_activities_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_async_cv, NULL, CV_DEFAULT, NULL);
|
||||||
cv_init(&spa->spa_evicting_os_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);
|
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_activities_cv);
|
||||||
cv_destroy(&spa->spa_waiters_cv);
|
cv_destroy(&spa->spa_waiters_cv);
|
||||||
|
|
||||||
|
rrm_destroy(&spa->spa_ratelimit_lock);
|
||||||
|
|
||||||
mutex_destroy(&spa->spa_flushed_ms_lock);
|
mutex_destroy(&spa->spa_flushed_ms_lock);
|
||||||
mutex_destroy(&spa->spa_async_lock);
|
mutex_destroy(&spa->spa_async_lock);
|
||||||
mutex_destroy(&spa->spa_errlist_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_QUOTA:
|
||||||
case ZFS_PROP_FILESYSTEM_LIMIT:
|
case ZFS_PROP_FILESYSTEM_LIMIT:
|
||||||
case ZFS_PROP_SNAPSHOT_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)) {
|
if (!INGLOBALZONE(curproc)) {
|
||||||
uint64_t zoned;
|
uint64_t zoned;
|
||||||
char setpoint[ZFS_MAX_DATASET_NAME_LEN];
|
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)
|
if (err == 0)
|
||||||
err = -1;
|
err = -1;
|
||||||
break;
|
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:
|
case ZFS_PROP_KEYLOCATION:
|
||||||
err = dsl_crypto_can_set_keylocation(dsname, strval);
|
err = dsl_crypto_can_set_keylocation(dsname, strval);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
#include <sys/dbuf.h>
|
#include <sys/dbuf.h>
|
||||||
#include <sys/policy.h>
|
#include <sys/policy.h>
|
||||||
#include <sys/zfeature.h>
|
#include <sys/zfeature.h>
|
||||||
|
#include <sys/vfs_ratelimit.h>
|
||||||
#include <sys/zfs_vnops.h>
|
#include <sys/zfs_vnops.h>
|
||||||
#include <sys/zfs_quota.h>
|
#include <sys/zfs_quota.h>
|
||||||
#include <sys/zfs_vfsops.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) {
|
while (n > 0) {
|
||||||
ssize_t nbytes = MIN(n, zfs_vnops_read_chunk_size -
|
ssize_t nbytes = MIN(n, zfs_vnops_read_chunk_size -
|
||||||
P2PHASE(zfs_uio_offset(uio), 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
|
#ifdef UIO_NOCOPY
|
||||||
if (zfs_uio_segflg(uio) == UIO_NOCOPY)
|
if (zfs_uio_segflg(uio) == UIO_NOCOPY)
|
||||||
error = mappedread_sf(zp, nbytes, uio);
|
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.
|
* Start a transaction.
|
||||||
*/
|
*/
|
||||||
|
@ -1309,6 +1315,9 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs_ratelimit_data_read(inos, inblksz, size);
|
||||||
|
vfs_ratelimit_data_write(outos, inblksz, size);
|
||||||
|
|
||||||
nbps = maxblocks;
|
nbps = maxblocks;
|
||||||
last_synced_txg = spa_last_synced_txg(dmu_objset_spa(inos));
|
last_synced_txg = spa_last_synced_txg(dmu_objset_spa(inos));
|
||||||
error = dmu_read_l0_bps(inos, inzp->z_id, inoff, size, bps,
|
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/linux.run \
|
||||||
%D%/runfiles/longevity.run \
|
%D%/runfiles/longevity.run \
|
||||||
%D%/runfiles/perf-regression.run \
|
%D%/runfiles/perf-regression.run \
|
||||||
|
%D%/runfiles/ratelimit.run \
|
||||||
%D%/runfiles/sanity.run \
|
%D%/runfiles/sanity.run \
|
||||||
%D%/runfiles/sunos.run
|
%D%/runfiles/sunos.run
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
# source. A copy of the CDDL is also available via the Internet at
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
# http://www.illumos.org/license/CDDL.
|
# http://www.illumos.org/license/CDDL.
|
||||||
#
|
#
|
||||||
# This run file contains all of the common functional tests. When
|
# This run file contains all tests related to the block cloning functionality.
|
||||||
# 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.
|
|
||||||
#
|
#
|
||||||
# Approximate run time: 5 hours
|
# 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']
|
'quota_004_pos', 'quota_005_pos', 'quota_006_neg']
|
||||||
tags = ['functional', 'quota']
|
tags = ['functional', 'quota']
|
||||||
|
|
||||||
|
[tests/functional/ratelimit]
|
||||||
|
tests = ['ratelimit_random']
|
||||||
|
tags = ['functional', 'ratelimit']
|
||||||
|
|
||||||
[tests/functional/redacted_send]
|
[tests/functional/redacted_send]
|
||||||
tests = ['redacted_compressed', 'redacted_contents', 'redacted_deleted',
|
tests = ['redacted_compressed', 'redacted_contents', 'redacted_deleted',
|
||||||
'redacted_disabled_feature', 'redacted_embedded', 'redacted_holes',
|
'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_check
|
||||||
/file_trunc
|
/file_trunc
|
||||||
/file_write
|
/file_write
|
||||||
|
/fsop
|
||||||
/get_diff
|
/get_diff
|
||||||
/getversion
|
/getversion
|
||||||
/largest_file
|
/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%/ctime
|
||||||
scripts_zfs_tests_bin_PROGRAMS += %D%/dir_rd_update
|
scripts_zfs_tests_bin_PROGRAMS += %D%/dir_rd_update
|
||||||
scripts_zfs_tests_bin_PROGRAMS += %D%/dosmode_readonly_write
|
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%/get_diff
|
||||||
scripts_zfs_tests_bin_PROGRAMS += %D%/rename_dir
|
scripts_zfs_tests_bin_PROGRAMS += %D%/rename_dir
|
||||||
scripts_zfs_tests_bin_PROGRAMS += %D%/suid_write_to_file
|
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_check
|
||||||
file_trunc
|
file_trunc
|
||||||
file_write
|
file_write
|
||||||
|
fsop
|
||||||
get_diff
|
get_diff
|
||||||
getversion
|
getversion
|
||||||
largest_file
|
largest_file
|
||||||
|
|
|
@ -1654,6 +1654,38 @@ function create_dataset #dataset dataset_options
|
||||||
return 0
|
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
|
# Return 0 if destroy successfully or the dataset exists; $? otherwise
|
||||||
# Note: In local zones, this function should return 0 silently.
|
# 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/projectquota/projectquota_common.kshlib \
|
||||||
functional/quota/quota.cfg \
|
functional/quota/quota.cfg \
|
||||||
functional/quota/quota.kshlib \
|
functional/quota/quota.kshlib \
|
||||||
|
functional/ratelimit/ratelimit_common.kshlib \
|
||||||
functional/redacted_send/redacted.cfg \
|
functional/redacted_send/redacted.cfg \
|
||||||
functional/redacted_send/redacted.kshlib \
|
functional/redacted_send/redacted.kshlib \
|
||||||
functional/redundancy/redundancy.cfg \
|
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_006_neg.ksh \
|
||||||
functional/raidz/raidz_expand_007_neg.ksh \
|
functional/raidz/raidz_expand_007_neg.ksh \
|
||||||
functional/raidz/setup.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/cleanup.ksh \
|
||||||
functional/redacted_send/redacted_compressed.ksh \
|
functional/redacted_send/redacted_compressed.ksh \
|
||||||
functional/redacted_send/redacted_contents.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