All of lore.kernel.org
 help / color / mirror / Atom feed
From: Martin Bukatovic <martin.bukatovic@gmail.com>
To: fio@vger.kernel.org
Subject: [PATCH] Add fill_quota option
Date: Tue, 11 Aug 2020 21:44:45 +0200	[thread overview]
Message-ID: <20200811194445.GA152146@dione.lan> (raw)

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


             reply	other threads:[~2020-08-11 19:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-11 19:44 Martin Bukatovic [this message]
2020-08-21 22:15 ` [PATCH] Add fill_quota option 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200811194445.GA152146@dione.lan \
    --to=martin.bukatovic@gmail.com \
    --cc=fio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.