* [PATCH] Add fill_quota option
@ 2020-08-11 19:44 Martin Bukatovic
2020-08-21 22:15 ` Sitsofe Wheeler
2020-08-28 23:53 ` Jens Axboe
0 siblings, 2 replies; 4+ messages in thread
From: Martin Bukatovic @ 2020-08-11 19:44 UTC (permalink / raw)
To: fio
Option fill_quota causes fio to write until EDQUOT occurs (assuming rw=write),
in the same way as fill_device option makes fio to write until ENOSPC.
Signed-off-by: Martin Bukatovic <martin.bukatovic@gmail.com>
---
HOWTO | 9 +++++++++
backend.c | 9 ++++++---
cconv.c | 2 ++
eta.c | 2 +-
filesetup.c | 17 +++++++++++------
fio.1 | 8 ++++++++
init.c | 2 +-
options.c | 10 ++++++++++
thread_options.h | 4 ++++
9 files changed, 52 insertions(+), 11 deletions(-)
diff --git a/HOWTO b/HOWTO
index e0403b08..4d0be15f 100644
--- a/HOWTO
+++ b/HOWTO
@@ -1810,6 +1810,15 @@ I/O size
device node, since the size of that is already known by the file system.
Additionally, writing beyond end-of-device will not return ENOSPC there.
+.. option:: fill_quota=bool
+
+ Sets size to something really large and waits for EDQUOT (disk quota
+ exceeded) as the terminating condition. It is done in the same way as
+ :option:`fill_device` handles ENOSPC, so that the same assumptions and
+ limitations apply. If both options :option:`fill_device` and
+ :option:`fill_quota` are specified at the same time, fio will terminate
+ when either entire free space or quota is used, whichever comes first.
+
I/O engine
~~~~~~~~~~
diff --git a/backend.c b/backend.c
index 0e454cdd..c61ed9b2 100644
--- a/backend.c
+++ b/backend.c
@@ -394,7 +394,8 @@ static bool break_on_this_error(struct thread_data *td, enum fio_ddir ddir,
td_clear_error(td);
*retptr = 0;
return false;
- } else if (td->o.fill_device && err == ENOSPC) {
+ } else if ((td->o.fill_device && err == ENOSPC) ||
+ (td->o.fill_quota && err == EDQUOT)) {
/*
* We expect to hit this error if
* fill_device option is set.
@@ -1101,7 +1102,8 @@ reap:
if (td->trim_entries)
log_err("fio: %lu trim entries leaked?\n", td->trim_entries);
- if (td->o.fill_device && td->error == ENOSPC) {
+ if ((td->o.fill_device && td->error == ENOSPC) ||
+ (td->o.fill_quota && td->error == EDQUOT)) {
td->error = 0;
fio_mark_td_terminate(td);
}
@@ -1116,7 +1118,8 @@ reap:
if (i) {
ret = io_u_queued_complete(td, i);
- if (td->o.fill_device && td->error == ENOSPC)
+ if ((td->o.fill_device && td->error == ENOSPC) ||
+ (td->o.fill_quota && td->error == EDQUOT))
td->error = 0;
}
diff --git a/cconv.c b/cconv.c
index 2469389b..8b148625 100644
--- a/cconv.c
+++ b/cconv.c
@@ -103,6 +103,7 @@ void convert_thread_options_to_cpu(struct thread_options *o,
o->io_size = le64_to_cpu(top->io_size);
o->size_percent = le32_to_cpu(top->size_percent);
o->fill_device = le32_to_cpu(top->fill_device);
+ o->fill_quota = le32_to_cpu(top->fill_quota);
o->file_append = le32_to_cpu(top->file_append);
o->file_size_low = le64_to_cpu(top->file_size_low);
o->file_size_high = le64_to_cpu(top->file_size_high);
@@ -369,6 +370,7 @@ void convert_thread_options_to_net(struct thread_options_pack *top,
top->serialize_overlap = cpu_to_le32(o->serialize_overlap);
top->size_percent = cpu_to_le32(o->size_percent);
top->fill_device = cpu_to_le32(o->fill_device);
+ top->fill_quota = cpu_to_le32(o->fill_quota);
top->file_append = cpu_to_le32(o->file_append);
top->ratecycle = cpu_to_le32(o->ratecycle);
top->io_submit_mode = cpu_to_le32(o->io_submit_mode);
diff --git a/eta.c b/eta.c
index 13f61ba4..6c250348 100644
--- a/eta.c
+++ b/eta.c
@@ -170,7 +170,7 @@ static unsigned long thread_eta(struct thread_data *td)
if (td->flags & TD_F_NO_PROGRESS)
return -1;
- if (td->o.fill_device && td->o.size == -1ULL) {
+ if ((td->o.fill_device || td->o.fill_quota) && td->o.size == -1ULL) {
if (!td->fill_device_size || td->fill_device_size == -1ULL)
return 0;
diff --git a/filesetup.c b/filesetup.c
index 49c54b81..90623188 100644
--- a/filesetup.c
+++ b/filesetup.c
@@ -57,7 +57,7 @@ static int native_fallocate(struct thread_data *td, struct fio_file *f)
static void fallocate_file(struct thread_data *td, struct fio_file *f)
{
- if (td->o.fill_device)
+ if (td->o.fill_device || td->o.fill_quota)
return;
switch (td->o.fallocate_mode) {
@@ -187,7 +187,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
* The size will be -1ULL when fill_device is used, so don't truncate
* or fallocate this file, just write it
*/
- if (!td->o.fill_device) {
+ if (!td->o.fill_device && !td->o.fill_quota) {
dprint(FD_FILE, "truncate file %s, size %llu\n", f->file_name,
(unsigned long long) f->real_file_size);
if (ftruncate(f->fd, f->real_file_size) == -1) {
@@ -233,6 +233,10 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
"file, stopping\n");
break;
}
+ if (__e == EDQUOT) {
+ if (td->o.fill_quota)
+ break;
+ }
td_verror(td, errno, "write");
} else
td_verror(td, EIO, "write");
@@ -250,7 +254,7 @@ static int extend_file(struct thread_data *td, struct fio_file *f)
goto err;
}
}
- if (td->o.fill_device && !td_write(td)) {
+ if ((td->o.fill_device || td->o.fill_quota) && !td_write(td)) {
fio_file_clear_size_known(f);
if (td_io_get_file_size(td, f))
goto err;
@@ -1044,14 +1048,15 @@ int setup_files(struct thread_data *td)
total_size += f->real_file_size;
}
- if (o->fill_device)
+ if (o->fill_device || o->fill_quota)
td->fill_device_size = get_fs_free_counts(td);
/*
* device/file sizes are zero and no size given, punt
*/
if ((!total_size || total_size == -1ULL) && !o->size &&
- !td_ioengine_flagged(td, FIO_NOIO) && !o->fill_device &&
+ !td_ioengine_flagged(td, FIO_NOIO) &&
+ !o->fill_device && !o->fill_quota &&
!(o->nr_files && (o->file_size_low || o->file_size_high))) {
log_err("%s: you need to specify size=\n", o->name);
td_verror(td, EINVAL, "total_file_size");
@@ -1221,7 +1226,7 @@ int setup_files(struct thread_data *td)
assert(f->filetype == FIO_TYPE_FILE);
fio_file_clear_extend(f);
- if (!o->fill_device) {
+ if (!o->fill_device && !o->fill_quota) {
old_len = f->real_file_size;
extend_len = f->io_size + f->file_offset -
old_len;
diff --git a/fio.1 b/fio.1
index cdd105d7..b1ddf58c 100644
--- a/fio.1
+++ b/fio.1
@@ -1583,6 +1583,14 @@ write. For a read workload, the mount point will be filled first then I/O
started on the result. This option doesn't make sense if operating on a raw
device node, since the size of that is already known by the file system.
Additionally, writing beyond end-of-device will not return ENOSPC there.
+.TP
+.BI fill_quota \fR=\fPbool
+Sets size to something really large and waits for EDQUOT (disk quota exceeded)
+as the terminating condition. It is done in the same way as fill_device option
+handles ENOSPC, so that the same assumptions and limitations apply. If both
+options fill_device and fill_quota are specified at the same time, fio will
+terminate when either entire free space or quota is used, whichever comes
+first.
.SS "I/O engine"
.TP
.BI ioengine \fR=\fPstr
diff --git a/init.c b/init.c
index 84325f1e..cadaf689 100644
--- a/init.c
+++ b/init.c
@@ -781,7 +781,7 @@ static int fixup_options(struct thread_data *td)
ret |= warnings_fatal;
}
- if (o->fill_device && !o->size)
+ if ((o->fill_device || o->fill_quota) && !o->size)
o->size = -1ULL;
if (o->verify != VERIFY_NONE) {
diff --git a/options.c b/options.c
index 251ad2c1..6f2356e0 100644
--- a/options.c
+++ b/options.c
@@ -2060,6 +2060,16 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
.category = FIO_OPT_C_FILE,
.group = FIO_OPT_G_INVALID,
},
+ {
+ .name = "fill_quota",
+ .lname = "Fill quota",
+ .type = FIO_OPT_BOOL,
+ .off1 = offsetof(struct thread_options, fill_quota),
+ .help = "Write until an EDQUOT error occurs",
+ .def = "0",
+ .category = FIO_OPT_C_FILE,
+ .group = FIO_OPT_G_INVALID,
+ },
{
.name = "filesize",
.lname = "File size",
diff --git a/thread_options.h b/thread_options.h
index 3fe48ecc..493d6beb 100644
--- a/thread_options.h
+++ b/thread_options.h
@@ -347,6 +347,8 @@ struct thread_options {
unsigned int job_max_open_zones;
fio_fp64_t zrt;
fio_fp64_t zrf;
+
+ unsigned int fill_quota;
};
#define FIO_TOP_STR_MAX 256
@@ -633,6 +635,8 @@ struct thread_options_pack {
uint32_t allow_mounted_write;
uint32_t zone_mode;
+
+ uint32_t fill_quota;
} __attribute__((packed));
extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
--
2.26.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] Add fill_quota option
2020-08-11 19:44 [PATCH] Add fill_quota option Martin Bukatovic
@ 2020-08-21 22:15 ` Sitsofe Wheeler
2020-08-28 23:53 ` Jens Axboe
1 sibling, 0 replies; 4+ messages in thread
From: Sitsofe Wheeler @ 2020-08-21 22:15 UTC (permalink / raw)
To: Martin Bukatovic; +Cc: fio
On Tue, 11 Aug 2020 at 20:45, Martin Bukatovic
<martin.bukatovic@gmail.com> wrote:
>
<snip>
>
> #define FIO_TOP_STR_MAX 256
> @@ -633,6 +635,8 @@ struct thread_options_pack {
> uint32_t allow_mounted_write;
>
> uint32_t zone_mode;
> +
> + uint32_t fill_quota;
> } __attribute__((packed));
If you're changing the wire format you'll have to bump FIO_SERVER_VER
in server.h;;;
>
> extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top);
> --
> 2.26.2
--
Sitsofe | http://sucs.org/~sits/
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add fill_quota option
2020-08-11 19:44 [PATCH] Add fill_quota option Martin Bukatovic
2020-08-21 22:15 ` Sitsofe Wheeler
@ 2020-08-28 23:53 ` Jens Axboe
[not found] ` <20200829190131.GA8262@dione.lan>
1 sibling, 1 reply; 4+ messages in thread
From: Jens Axboe @ 2020-08-28 23:53 UTC (permalink / raw)
To: Martin Bukatovic, fio
On 8/11/20 1:44 PM, Martin Bukatovic wrote:
> Option fill_quota causes fio to write until EDQUOT occurs (assuming rw=write),
> in the same way as fill_device option makes fio to write until ENOSPC.
Might be easier and saner to just accept EDQUOT by default, instead of
adding an option for it?
--
Jens Axboe
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] Add fill_quota option
[not found] ` <3e8f33c3-6d57-8932-b84e-374c0afd4779@kernel.dk>
@ 2020-08-29 20:34 ` Martin Bukatovic
0 siblings, 0 replies; 4+ messages in thread
From: Martin Bukatovic @ 2020-08-29 20:34 UTC (permalink / raw)
To: Jens Axboe; +Cc: fio
On Sat, Aug 29, 2020 at 01:44:07PM -0600, Jens Axboe wrote:
> On 8/29/20 1:01 PM, Martin Bukatovic wrote:
> > On Fri, Aug 28, 2020 at 05:53:34PM -0600, Jens Axboe wrote:
> >> Might be easier and saner to just accept EDQUOT by default, instead of
> >> adding an option for it?
> >
> > I proposed a new option to avoid changing behaviour of fill_device
> > option. But if that is not necessary, I agree that making fill_device to
> > stop on both ENOSPC and EDQUOT makes more sense.
>
> I don't think that's necessary, the option is really "stop writing when
> we're full", and there's no way to reach ENOSPC before EDQUOT vs
> the other way around.
>
> Hence I think it's totally fine to just include EDQUOT in the "stop
> successfully" part of the fill_device behavior.
Ok, I'm sending new version of the patch "Make fill_device to stop
writing on EDQUOT".
--
Martin Bukatovič
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-08-29 20:34 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-11 19:44 [PATCH] Add fill_quota option Martin Bukatovic
2020-08-21 22:15 ` Sitsofe Wheeler
2020-08-28 23:53 ` Jens Axboe
[not found] ` <20200829190131.GA8262@dione.lan>
[not found] ` <3e8f33c3-6d57-8932-b84e-374c0afd4779@kernel.dk>
2020-08-29 20:34 ` Martin Bukatovic
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.