I'm always wonder why do we have to allocate space for quota-file as normal file. Because of this we have to grab i_mutex on each quota write. And still getting in to risk of ENOSPC. The later is really annoying issue for me(when i run fsstress tests). Let's live the i_mutex's story for another day and consider the simplest one. Why don't we preallocate a space for quota file during creation. In fact we may imagine some reasonable quota-file size expectation (65538 * 64) = 4Mb, At least this may be sufficient for most use-cases.
>From ef72d4ad7d23db734a7ce74b350cdd47a594130b Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> Date: Sun, 7 Mar 2010 20:08:51 +0300 Subject: [PATCH] quota: prealloc space for new quota file. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- convertquota.c | 4 ++-- quotacheck.c | 2 +- quotaio.c | 15 ++++++++++++++- quotaio.h | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/convertquota.c b/convertquota.c index 1572cb9..2304be6 100644 --- a/convertquota.c +++ b/convertquota.c @@ -287,7 +287,7 @@ static int convert_format(int type, struct mntent *mnt) type2name(type), mnt->mnt_dir); return -1; } - if (!(qn = new_io(mnt, type, QF_VFSV0))) { + if (!(qn = new_io(mnt, type, QF_VFSV0, 8192*1024))) { errstr(_("Cannot create file for %ss for new format on %s: %s\n"), type2name(type), mnt->mnt_dir, strerror(errno)); end_io(qo); @@ -320,7 +320,7 @@ static int convert_endian(int type, struct mntent *mnt) close(ofd); return -1; } - if (!(qn = new_io(mnt, type, QF_VFSV0))) { + if (!(qn = new_io(mnt, type, QF_VFSV0, 8192*1024))) { errstr(_("Cannot create file for %ss for new format on %s: %s\n"), type2name(type), mnt->mnt_dir, strerror(errno)); close(ofd); diff --git a/quotacheck.c b/quotacheck.c index b5f7e2e..2b49820 100644 --- a/quotacheck.c +++ b/quotacheck.c @@ -794,7 +794,7 @@ static int dump_to_file(struct mntent *mnt, int type) struct quota_handle *h; debug(FL_DEBUG, _("Dumping gathered data for %ss.\n"), type2name(type)); - if (!(h = new_io(mnt, type, cfmt))) { + if (!(h = new_io(mnt, type, cfmt, 8192*1024))) { errstr(_("Cannot initialize IO on new quotafile: %s\n"), strerror(errno)); return -1; diff --git a/quotaio.c b/quotaio.c index d74a37d..540e89b 100644 --- a/quotaio.c +++ b/quotaio.c @@ -166,7 +166,7 @@ out_handle: /* * Create new quotafile of specified format on given filesystem */ -struct quota_handle *new_io(struct mntent *mnt, int type, int fmt) +struct quota_handle *new_io(struct mntent *mnt, int type, int fmt, int prealloc) { char *qfname; int fd; @@ -212,6 +212,19 @@ struct quota_handle *new_io(struct mntent *mnt, int type, int fmt) free(h); goto out_fd; } + if (prealloc) { + char zbuf[4096]; + int len, ret; + memset(zbuf, 0, sizeof(zbuf)); + while (prealloc) { + len = (sizeof(zbuf) < prealloc) ? sizeof(zbuf) : prealloc; + ret = write(fd, zbuf, len); + if (ret < 0) + goto out_fd; + prealloc -= len; + } + lseek(fd, 0, SEEK_SET); + } return h; out_fd: close(fd); diff --git a/quotaio.h b/quotaio.h index f6eef50..c66db43 100644 --- a/quotaio.h +++ b/quotaio.h @@ -169,7 +169,7 @@ static inline void mark_quotafile_info_dirty(struct quota_handle *h) struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags); /* Create new quotafile of specified format on given filesystem */ -struct quota_handle *new_io(struct mntent *mnt, int type, int fmt); +struct quota_handle *new_io(struct mntent *mnt, int type, int fmt, int prealloc); /* Close quotafile */ int end_io(struct quota_handle *h); -- 1.6.3.3