Add fill_quota option
PATCH 1/1 Add fill_quota option
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.
--- 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(-)
HOWTO +9 -0
@@ -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 ~~~~~~~~~~
backend.c +6 -3
@@ -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 ; }
cconv.c +2 -0
@@ -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);
eta.c +1 -1
@@ -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 ;
filesetup.c +11 -6
@@ -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;
fio.1 +8 -0
@@ -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
init.c +1 -1
@@ -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 ) {
options.c +10 -0
@@ -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",
thread_options.h +4 -0
@@ -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);
Signature · 1 line
2.26.2
Quoted 1 line · Martin Bukatovic
<snip>
thread_options.h struct thread_options_pack { · line 640
Quoted 9 lines
#define
FIO_TOP_STR_MAX256thread_options.h +2
-0@@ -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;;;
Quoted 4 lines
(quoted diff) +0
-1extern void convert_thread_options_to_cpu(struct thread_options *o, struct thread_options_pack *top); --2.26.2
Signature · 1 line
Sitsofe | http://sucs.org/~sits/
Quoted 2 lines · Martin Bukatovic
Option
fill_quotacauses fio to write until EDQUOT occurs (assuming rw=write), in the same way asfill_deviceoption makes fio to write until ENOSPC.
Might be easier and saner to just accept EDQUOT by default, instead of adding an option for it?
Signature · 1 line
Jens Axboe
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 9 lines · Jens Axboe
Quoted 7 lines · Martin Bukatovic
Quoted 2 lines · Jens Axboe
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_deviceoption. But if that is not necessary, I agree that makingfill_deviceto stop on both ENOSPC and EDQUOT makes more sense.
Quoted 6 lines
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_devicebehavior.
Ok, I'm sending new version of the patch "Make fill_device to stop writing on EDQUOT".
Signature · 1 line
Martin Bukatovič