Hi,
After upgrading to vpopmail 5.4.33 I started seeing much more IO
requests. I see that in 5.4.32 the following code was added to
maildirquota.c:
/*
Maildir++ specification says to rebuild the maildirsize file if the
file is 5120 or more bytes, or is more than 15 minutes old
*/
ret = fstat(f, statptr);
if ((ret != -1) && ((statptr->st_size >= 5120) || (time(NULL) >
statptr->st_mtime + (15*60)))) {
unlink(filename);
close(f);
return -1;
}
I think this is not correct interpretation of the specs from
www.courier-mta.org/imap/README.maildirquota.html which says:
/If the numbers we got indicated that the Maildir++ *is over quota*,
some additional logic is in order: if we did not recalculate
//maildirsize//, if the numbers in //maildirsize//indicated that we are
over quota, then if //maildirsize//was more than one line long, or if
the timestamp on //maildirsize//indicated that it's at least 15 minutes
old, throw out the totals, and recalculate //maildirsize//from scratch./
I.e. the 15 minute logic should be applied only if the Maildir is
currently over quota. This logic was already implemented in
maildirquota.c dockeckquota() where it says if (maildirsize_nlines == 1
&& tm < stat_buf.st_mtime + 15*60), but it didn't work, because
/stat_buf/ is not set in maildirsize_read().
Please find attached a patch against 5.4.33, which I'm using in
production. In addition to the minimal fix (initializing stat_buf) it
has some documentation as well as some magic numbers converted to
constants -- feel free to use it however you like.
Best regards,
Teodor
!DSPAM:53b5788881086521514644!
diff -Nru vpopmail-5.4.33.orig/maildirquota.h vpopmail-5.4.33/maildirquota.h
--- vpopmail-5.4.33.orig/maildirquota.h 2011-02-28 19:00:45.000000000 +0200
+++ vpopmail-5.4.33/maildirquota.h 2014-07-03 18:09:48.000000000 +0300
@@ -12,6 +12,10 @@
#define QUOTA_WARN_PERCENT 90
+/* http://www.courier-mta.org/imap/README.maildirquota.html */
+#define MAILDIRSIZE_OVERLEN 5120
+#define MAILDIRSIZE_OLD_SECS 15*60
+
/* I've removed pretty much the whole file execept for
some public functions so as to not conflict with courier.
I"ve made the courier functions static.
diff -Nru vpopmail-5.4.33.orig/maildirquota.c vpopmail-5.4.33/maildirquota.c
--- vpopmail-5.4.33.orig/maildirquota.c 2011-02-28 19:00:45.000000000 +0200
+++ vpopmail-5.4.33/maildirquota.c 2014-07-03 18:14:54.000000000 +0300
@@ -333,7 +333,7 @@
unsigned *nlines, /* # of lines in maildirsize */
struct stat *statptr) /* The stats on maildirsize */
{
- char buf[5120];
+ char buf[MAILDIRSIZE_OVERLEN];
int f;
char *p;
unsigned l;
@@ -343,21 +343,13 @@
if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0)
return (-1);
+
+ if (fstat(f, statptr) < 0)
+ return (-1);
+
p=buf;
l=sizeof(buf);
- /*
- Maildir++ specification says to rebuild the maildirsize file if the
- file is 5120 or more bytes, or is more than 15 minutes old
- */
-
- ret = fstat(f, statptr);
- if ((ret != -1) && ((statptr->st_size >= 5120) || (time(NULL) > statptr->st_mtime + (15*60)))) {
- unlink(filename);
- close(f);
- return -1;
- }
-
while (l)
{
n=read(f, p, l);
@@ -409,6 +401,17 @@
return (0);
}
+/**
+ * Calculate quota usage in percent (%).
+ *
+ * @param[in] s Current maildir size in bytes.
+ * @param[in] n Current maildir message count.
+ * @param[in] *quota Current quota limit, e.g. 1000S or 1000C.
+ * @param[out] *percentage Quota usage in % (the bigger between size & count).
+ *
+ * @retval 0 within quota
+ * @retval -1 over quota
+ */
static int qcalc(storage_t s, storage_t n, const char *quota, int *percentage)
{
storage_t i;
@@ -595,7 +598,7 @@
n=qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
quota_type, percentage);
- if (n == 0)
+ if (n == 0) // within quota
{
free(checkfolder);
*maildirsize_fdptr=maildirsize_fd;
@@ -603,7 +606,16 @@
}
close(maildirsize_fd);
- if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60)
+ /*
+ * http://www.courier-mta.org/imap/README.maildirquota.html
+ *
+ * "if the numbers in maildirsize indicated that we are over quota,
+ * then if maildirsize was more than one line long, or if the timestamp
+ * on maildirsize indicated that it's at least 15 minutes old, throw out
+ * the totals, and recalculate maildirsize from scratch"
+ */
+ if (maildirsize_nlines == 1 &&
+ tm < stat_buf.st_mtime + MAILDIRSIZE_OLD_SECS)
return (n);
}