[Dovecot] NFS(4) IMAP Quota

Martin Schanzenbach schanzen at in.tum.de
Tue Jun 29 18:26:56 EEST 2010


Hi *,

We use nfs4 in combination with dovecot. Also (hard)quotas are used on
the exports.
Using the dovecot quota fs plugin things did not work at all. There were
a few issues we encountered:

1. Nfs4 is not recognized. The problem is that the mount type is only
checked for "nfs" and not nfs4. This was an easy fix.

2. The (fs)path for nfs4 that is relayed to rquotad has to be without
the leading "/". This was an easy fix, too. (borrowed from linuxquota:
http://linuxquota.cvs.sourceforge.net/viewvc/linuxquota/quota-tools/rquota_client.c?view=markup )

3. Maybe because we do not use softquotas the quota active boolean
(rq_active) in the rquota struct is always false. So we hackishly
removed this check. This problem also occured here:
http://dovecot.org/pipermail/dovecot/2009-May/039593.html
Apparently quota-tools do not check for this either (not needed?).

4. As metioned above we only use hardquotas but the plugin only reports
softquotas. In my patch below I changed the behaviour: Check softquota
== 0. If true then use hardquota, else softquota.

Maybe you can use some of those fixes. I think at least #3 is
reproducible (see ml post). The hard vs softquota behaviour is certainly
a matter of discussion. The nfs4 "fixes" are actually more like feature
requests that I think should be added to the plugin in one way or
another.
I created a diff of my changes to quota-fs.c. The changes were tested
only for nfs3/4 though.


Cheers
Martin

For completeness:
BEGIN dovecot -n

# 1.2.12: /etc/dovecot/dovecot.conf
# OS: Linux 2.6.31-xen-r10-xen_domU x86_64 Gentoo Base System release
1.12.13 
protocols: imaps pop3s
listen: [::]
ssl_listen(default): *:1993
ssl_listen(imap): *:1993
ssl_listen(pop3): *:1995
<cert files omitted>
version_ignore: yes
login_dir: /var/run/dovecot/login
login_executable(default): /usr/libexec/dovecot/imap-login
login_executable(imap): /usr/libexec/dovecot/imap-login
login_executable(pop3): /usr/libexec/dovecot/pop3-login
login_max_processes_count: 256
mail_privileged_group: mail
mail_debug: yes
mmap_disable: yes
mail_nfs_index: yes
mail_executable(default): /usr/local/bin/dovecot_helper
mail_executable(imap): /usr/local/bin/dovecot_helper
mail_executable(pop3): /usr/local/bin/dovecot_helper_pop
mail_plugins(default): quota imap_quota
mail_plugins(imap): quota imap_quota
mail_plugins(pop3): 
mail_plugin_dir(default): /usr/lib64/dovecot/imap
mail_plugin_dir(imap): /usr/lib64/dovecot/imap
mail_plugin_dir(pop3): /usr/lib64/dovecot/pop3
pop3_uidl_format(default): %08Xu%08Xv
pop3_uidl_format(imap): %08Xu%08Xv
pop3_uidl_format(pop3): %v,%u
lda:
  postmaster_address: <omitted>
auth default:
  passdb:
    driver: pam
    args: *
  userdb:
    driver: passwd
plugin:
  quota: fs:user:noenforcing

-- END

The diff (-Naur):

--- quota-fs.c	2010-06-19 00:12:44.000000000 +0200
+++ quota-fs.c	2010-06-29 15:44:45.033517162 +0200
@@ -164,7 +164,7 @@
 	mount->fd = -1;
 #endif
 
-	if (strcmp(mount->type, "nfs") == 0) {
+	if (strcmp(mount->type, "nfs") == 0 || strcmp(mount->type, "nfs4") ==
0) {
 		if (strchr(mount->device_path, ':') == NULL) {
 			i_error("quota-fs: %s is not a valid NFS device path",
 				mount->device_path);
@@ -210,7 +210,7 @@
 
 #ifdef FS_QUOTA_SOLARIS
 #ifdef HAVE_RQUOTA
-	if (strcmp(mount->type, "nfs") == 0) {
+	if (strcmp(mount->type, "nfs") == 0 || strcmp(mount->type, "nfs4") ==
0) {
 		/* using rquota for this mount */
 	} else
 #endif
@@ -319,6 +319,11 @@
 
 	host = t_strdup_until(mount->device_path, path);
 	path++;
+	/* For NFSv4, we send the filesystem path without initial /. Server
prepends proper
+	 * NFS pseudoroot automatically and uses this for detection of NFSv4
mounts. */
+	if (strcmp(root->mount->type, "nfs4") == 0)
+		while (*path == '/')
+			path++;
 
 	if (root->root.quota->set->debug) {
 		i_info("quota-fs: host=%s, path=%s, uid=%s, %s",
@@ -366,17 +371,24 @@
 		/* convert the results from blocks to bytes */
 		const rquota *rq = &result.getquota_rslt_u.gqr_rquota;
 
-		if (rq->rq_active) {
-			if (bytes) {
-				*value_r = (uint64_t)rq->rq_curblocks *
-					(uint64_t)rq->rq_bsize;
+		if (bytes) {
+			*value_r = (uint64_t)rq->rq_curblocks *
+				(uint64_t)rq->rq_bsize;
+			if (rq->rq_bsoftlimit) {
 				*limit_r = (uint64_t)rq->rq_bsoftlimit *
 					(uint64_t)rq->rq_bsize;
 			} else {
-				*value_r = rq->rq_curfiles;
-				*limit_r = rq->rq_fsoftlimit;
+				*limit_r = (uint64_t)rq->rq_bhardlimit *
+					(uint64_t)rq->rq_bsize;
 			}
+		} else {
+			*value_r = rq->rq_curfiles;
+			if (rq->rq_fsoftlimit)
+				*limit_r = rq->rq_fsoftlimit;
+			else
+				*limit_r = rq->rq_fhardlimit;
 		}
+		
 		if (root->root.quota->set->debug) {
 			i_info("quota-fs: uid=%s, value=%llu, "
 			       "limit=%llu, active=%d", dec2str(root->uid),
@@ -419,7 +431,12 @@
 
 	host = t_strdup_until(mount->device_path, path);
 	path++;
-
+	/* For NFSv4, we send the filesystem path without initial /. Server
prepends proper
+	 * NFS pseudoroot automatically and uses this for detection of NFSv4
mounts. */
+	if (strcmp(root->mount->type, "nfs4") == 0)
+		while (*path == '/')
+			path++;
+	
 	if (root->root.quota->set->debug) {
 		i_info("quota-fs: host=%s, path=%s, gid=%s, %s",
 		       host, path, dec2str(root->gid),
@@ -761,7 +778,7 @@
 	bytes = strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0;
 
 #ifdef HAVE_RQUOTA
-	if (strcmp(root->mount->type, "nfs") == 0) {
+	if (strcmp(root->mount->type, "nfs") == 0 || strcmp(root->mount->type,
"nfs4") == 0) {
 		T_BEGIN {
 			ret = !root->user_disabled ?
 				do_rquota_user(root, bytes, value_r, &limit) :





More information about the dovecot mailing list