Module Name:    src
Committed By:   dholland
Date:           Sun Jan 29 07:07:22 UTC 2012

Modified Files:
        src/sys/kern: vfs_quotactl.c
        src/sys/sys: quotactl.h
        src/sys/ufs/ufs: ufs_quota.c ufs_quota.h ufs_quota2.c

Log Message:
Call QUOTACTL_GETALL in a loop to get results 8 at a time. Make
the QUOTACTL_GETALL interface less abusive.

Note: this change requires a kernel version bump.


To generate a diff of this commit:
cvs rdiff -u -r1.26 -r1.27 src/sys/kern/vfs_quotactl.c
cvs rdiff -u -r1.23 -r1.24 src/sys/sys/quotactl.h
cvs rdiff -u -r1.95 -r1.96 src/sys/ufs/ufs/ufs_quota.c
cvs rdiff -u -r1.17 -r1.18 src/sys/ufs/ufs/ufs_quota.h
cvs rdiff -u -r1.22 -r1.23 src/sys/ufs/ufs/ufs_quota2.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/vfs_quotactl.c
diff -u src/sys/kern/vfs_quotactl.c:1.26 src/sys/kern/vfs_quotactl.c:1.27
--- src/sys/kern/vfs_quotactl.c:1.26	Sun Jan 29 07:06:37 2012
+++ src/sys/kern/vfs_quotactl.c	Sun Jan 29 07:07:22 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_quotactl.c,v 1.26 2012/01/29 07:06:37 dholland Exp $	*/
+/*	$NetBSD: vfs_quotactl.c,v 1.27 2012/01/29 07:07:22 dholland Exp $	*/
 
 /*
  * Copyright (c) 1991, 1993, 1994
@@ -80,7 +80,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.26 2012/01/29 07:06:37 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.27 2012/01/29 07:07:22 dholland Exp $");
 
 #include <sys/malloc.h> /* XXX: temporary */
 #include <sys/mount.h>
@@ -525,16 +525,18 @@ vfs_quotactl_getall(struct mount *mp,
 			prop_array_t datas)
 {
 	struct quotakcursor cursor;
-	struct quota_getall_result result;
+	struct quotakey *keys;
+	struct quotaval *vals;
+	unsigned loopmax = 8;
+	unsigned loopnum;
 	struct vfs_quotactl_args args;
 	prop_array_t replies;
-	prop_dictionary_t thisreply;
 	struct quotakey *key;
 	struct quotaval *val;
 	id_t lastid;
+	prop_dictionary_t thisreply;
 	unsigned i;
 	int error, error2;
-	int skip = 0;
 
 	KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
 
@@ -545,30 +547,8 @@ vfs_quotactl_getall(struct mount *mp,
 		return error;
 	}
 
-	result.qr_keys = NULL;
-	result.qr_vals = NULL;
-	result.qr_num = 0;
-	result.qr_max = 0x7fffffff; /* XXX bogus; but temporary */
-
-	args.qc_type = QCT_GETALL;
-	args.u.getall.qc_cursor = &cursor;
-	args.u.getall.qc_idtype = q2type;
-	args.u.getall.qc_result = &result;
-	error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
-	/*
-	 * XXX this is bogus but up until now *all* errors
-	 * from inside quotactl_getall were suppressed by the
-	 * dispatching code in ufs_quota.c. Fixing that causes
-	 * repquota to break in an undesirable way; this is a
-	 * workaround.
-	 */
-	if (error == ENODEV || error == ENXIO) {
-		skip = 1;
-		error = 0;
-	}
-	if (error) {
-		goto err;
-	}
+	keys = malloc(loopmax * sizeof(keys[0]), M_TEMP, M_WAITOK);
+	vals = malloc(loopmax * sizeof(vals[0]), M_TEMP, M_WAITOK);
 
 	replies = prop_array_create();
 	if (replies == NULL) {
@@ -576,43 +556,72 @@ vfs_quotactl_getall(struct mount *mp,
 		goto err;
 	}
 
-	if (skip) {
-		goto skip;
-	}
-
 	thisreply = NULL;
 	lastid = 0; /* value not actually referenced */
-	for (i = 0; i < result.qr_num; i++) {
-		key = &result.qr_keys[i];
-		val = &result.qr_vals[i];
-
-		if (thisreply == NULL || key->qk_id != lastid) {
-			lastid = key->qk_id;
-			thisreply = vfs_quotactl_getall_makereply(key);
-			if (thisreply == NULL) {
-				error = ENOMEM;
-				goto err;
-			}
-			/*
-			 * Note: while we release our reference to
-			 * thisreply here, we can (and do) continue to
-			 * use the pointer in the loop because the
-			 * copy attached to the replies array is not
-			 * going away.
-			 */
-			if (!prop_array_add_and_rel(replies, thisreply)) {
-				error = ENOMEM;
-				goto err;
-			}
+
+	while (1) {
+		args.qc_type = QCT_GETALL;
+		args.u.getall.qc_cursor = &cursor;
+		args.u.getall.qc_keys = keys;
+		args.u.getall.qc_vals = vals;
+		args.u.getall.qc_maxnum = loopmax;
+		args.u.getall.qc_ret = &loopnum;
+		args.u.getall.qc_idtype = q2type;	/* XXX */
+
+		error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
+		/*
+		 * XXX this is bogus but up until now *all* errors
+		 * from inside quotactl_getall were suppressed by the
+		 * dispatching code in ufs_quota.c. Fixing that causes
+		 * repquota to break in an undesirable way; this is a
+		 * workaround.
+		 */
+		if (error == ENODEV || error == ENXIO) {
+			error = 0;
+			break;
 		}
 
-		error = vfs_quotactl_getall_addreply(thisreply, key, val);
 		if (error) {
 			goto err;
 		}
-	}
 
-skip:
+		if (loopnum == 0) {
+			/* end of iteration */
+			break;
+		}
+
+		for (i = 0; i < loopnum; i++) {
+			key = &keys[i];
+			val = &vals[i];
+
+			if (thisreply == NULL || key->qk_id != lastid) {
+				lastid = key->qk_id;
+				thisreply = vfs_quotactl_getall_makereply(key);
+				if (thisreply == NULL) {
+					error = ENOMEM;
+					goto err;
+				}
+				/*
+				 * Note: while we release our reference to
+				 * thisreply here, we can (and do) continue to
+				 * use the pointer in the loop because the
+				 * copy attached to the replies array is not
+				 * going away.
+				 */
+				if (!prop_array_add_and_rel(replies,
+							    thisreply)) {
+					error = ENOMEM;
+					goto err;
+				}
+			}
+
+			error = vfs_quotactl_getall_addreply(thisreply,
+							     key, val);
+			if (error) {
+				goto err;
+			}
+		}
+	}
 
 	if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) {
 		error = ENOMEM;
@@ -621,12 +630,8 @@ skip:
 
 	error = 0;
  err:
-	if (result.qr_keys) {
-		free(result.qr_keys, M_TEMP);
-	}
-	if (result.qr_vals) {
-		free(result.qr_vals, M_TEMP);
-	}
+	free(keys, M_TEMP);
+	free(vals, M_TEMP);
 
 	args.qc_type = QCT_CURSORCLOSE;
 	args.u.cursorclose.qc_cursor = &cursor;

Index: src/sys/sys/quotactl.h
diff -u src/sys/sys/quotactl.h:1.23 src/sys/sys/quotactl.h:1.24
--- src/sys/sys/quotactl.h:1.23	Sun Jan 29 07:06:01 2012
+++ src/sys/sys/quotactl.h	Sun Jan 29 07:07:22 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quotactl.h,v 1.23 2012/01/29 07:06:01 dholland Exp $	*/
+/*	$NetBSD: quotactl.h,v 1.24 2012/01/29 07:07:22 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -37,8 +37,6 @@
  * use the <quota.h> API instead.
  */
 
-#include <sys/quota.h>
-
 /*
  * Semi-opaque structure for cursors. This holds the cursor state in
  * userland; the size is exposed only to libquota, not to client code,
@@ -105,13 +103,11 @@ struct vfs_quotactl_args {
 		} cursorclose;
 		struct {
 			struct quotakcursor *qc_cursor;
+			struct quotakey *qc_keys;
+			struct quotaval *qc_vals;
+			unsigned qc_maxnum;
+			unsigned *qc_ret;
 			int qc_idtype;
-			struct quota_getall_result {
-				struct quotakey *qr_keys;
-				struct quotaval *qr_vals;
-				unsigned qr_num;
-				unsigned qr_max;
-			} *qc_result;
 		} getall;
 	} u;
 };

Index: src/sys/ufs/ufs/ufs_quota.c
diff -u src/sys/ufs/ufs/ufs_quota.c:1.95 src/sys/ufs/ufs/ufs_quota.c:1.96
--- src/sys/ufs/ufs/ufs_quota.c:1.95	Sun Jan 29 07:02:06 2012
+++ src/sys/ufs/ufs/ufs_quota.c	Sun Jan 29 07:07:22 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_quota.c,v 1.95 2012/01/29 07:02:06 dholland Exp $	*/
+/*	$NetBSD: ufs_quota.c,v 1.96 2012/01/29 07:07:22 dholland Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993, 1995
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.95 2012/01/29 07:02:06 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.96 2012/01/29 07:07:22 dholland Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -370,14 +370,20 @@ quota_handle_cmd_getall(struct mount *mp
 {
 	struct ufsmount *ump = VFSTOUFS(mp);
 	struct quotakcursor *cursor;
+	struct quotakey *keys;
+	struct quotaval *vals;
+	unsigned maxnum;
+	unsigned *ret;
 	int idtype;
-	struct quota_getall_result *result;
 	int error;
 
 	KASSERT(args->qc_type == QCT_GETALL);
 	cursor = args->u.getall.qc_cursor;
+	keys = args->u.getall.qc_keys;
+	vals = args->u.getall.qc_vals;
+	maxnum = args->u.getall.qc_maxnum;
+	ret = args->u.getall.qc_ret;
 	idtype = args->u.getall.qc_idtype;
-	result = args->u.getall.qc_result;
 
 	if ((ump->um_flags & UFS_QUOTA2) == 0)
 		return EOPNOTSUPP;
@@ -389,7 +395,8 @@ quota_handle_cmd_getall(struct mount *mp
 		
 #ifdef QUOTA2
 	if (ump->um_flags & UFS_QUOTA2) {
-		error = quota2_handle_cmd_getall(ump, cursor, idtype, result);
+		error = quota2_handle_cmd_getall(ump, cursor, idtype,
+						 keys, vals, maxnum, ret);
 	} else
 #endif
 		panic("quota_handle_cmd_getall: no support ?");

Index: src/sys/ufs/ufs/ufs_quota.h
diff -u src/sys/ufs/ufs/ufs_quota.h:1.17 src/sys/ufs/ufs/ufs_quota.h:1.18
--- src/sys/ufs/ufs/ufs_quota.h:1.17	Sun Jan 29 07:02:06 2012
+++ src/sys/ufs/ufs/ufs_quota.h	Sun Jan 29 07:07:22 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_quota.h,v 1.17 2012/01/29 07:02:06 dholland Exp $	*/
+/*	$NetBSD: ufs_quota.h,v 1.18 2012/01/29 07:07:22 dholland Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993, 1995
@@ -37,7 +37,6 @@
 #include <ufs/ufs/quota2.h>
 
 struct quotakcursor; /* from <sys/quotactl.h> */
-struct quota_getall_result; /* ditto, but: XXX temporary */
 
 
 /* link to this quota in the quota inode (for QUOTA2) */
@@ -133,7 +132,7 @@ int quota2_handle_cmd_put(struct ufsmoun
     const struct quotaval *);
 int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *);
 int quota2_handle_cmd_getall(struct ufsmount *, struct quotakcursor *, int,
-    struct quota_getall_result *);
+    struct quotakey *, struct quotaval *, unsigned, unsigned *);
 int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *);
 int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *);
 int q2sync(struct mount *);

Index: src/sys/ufs/ufs/ufs_quota2.c
diff -u src/sys/ufs/ufs/ufs_quota2.c:1.22 src/sys/ufs/ufs/ufs_quota2.c:1.23
--- src/sys/ufs/ufs/ufs_quota2.c:1.22	Sun Jan 29 07:06:02 2012
+++ src/sys/ufs/ufs/ufs_quota2.c	Sun Jan 29 07:07:22 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 dholland Exp $ */
+/* $NetBSD: ufs_quota2.c,v 1.23 2012/01/29 07:07:22 dholland Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -26,7 +26,7 @@
   */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.23 2012/01/29 07:07:22 dholland Exp $");
 
 #include <sys/buf.h>
 #include <sys/param.h>
@@ -829,7 +829,7 @@ out_dq:
 
 static int
 quota2_result_add_q2e(struct ufsmount *ump, int idtype,
-    int id, struct quota_getall_result *result, unsigned pos,
+    int id, struct quotakey *keys, struct quotaval *vals, unsigned pos,
     int skipfirst, int skiplast)
 {
 	struct dquot *dq;
@@ -861,18 +861,18 @@ quota2_result_add_q2e(struct ufsmount *u
 	dqrele(NULLVP, dq);
 
 	if (skipfirst == 0) {
-		result->qr_keys[pos].qk_idtype = idtype;
-		result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
-		q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
-				QL_BLOCK, &result->qr_vals[pos]);
+		keys[pos].qk_idtype = idtype;
+		keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
+		q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id,
+				QL_BLOCK, &vals[pos]);
 		pos++;
 	}
 
 	if (skiplast == 0) {
-		result->qr_keys[pos].qk_idtype = idtype;
-		result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
-		q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
-				QL_FILE, &result->qr_vals[pos]);
+		keys[pos].qk_idtype = idtype;
+		keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
+		q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id,
+				QL_FILE, &vals[pos]);
 		pos++;
 	}
 
@@ -1042,7 +1042,8 @@ quota2_getuids_callback(struct ufsmount 
 
 int
 quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc,
-    int idtype, struct quota_getall_result *result)
+    int idtype, struct quotakey *keys, struct quotaval *vals,
+    unsigned maxreturn, unsigned *ret)
 {
 	int error;
 	struct ufsq2_cursor *cursor;
@@ -1054,13 +1055,12 @@ quota2_handle_cmd_getall(struct ufsmount
 	int quota2_hash_size;
 	const int needswap = UFS_MPNEEDSWAP(ump);
 	struct getuids gu;
+	long excess;
 	id_t junkid;
-	struct quotakey bkey, fkey;
-	struct quotaval bval, fval;
-	int dobval = 0, dofval = 0;
+	struct quotaval qv;
 	unsigned num, maxnum;
 	int skipfirst, skiplast;
-	int maxreturn, numreturn;
+	int numreturn;
 
 	cursor = Q2CURSOR(qkc);
 	error = q2cursor_check(cursor);
@@ -1072,7 +1072,6 @@ quota2_handle_cmd_getall(struct ufsmount
 		return ENODEV;
 	}
 
-	maxreturn = result->qr_max;
 	numreturn = 0;
 
 	mutex_enter(&dqlock);
@@ -1085,19 +1084,19 @@ quota2_handle_cmd_getall(struct ufsmount
 	if (cursor->q2c_defaults_done == 0) {
 		quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
 		if (cursor->q2c_blocks_done == 0) {
-			q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &bval);
-			bkey.qk_idtype = idtype;
-			bkey.qk_id = QUOTA_DEFAULTID;
-			bkey.qk_objtype = QUOTA_OBJTYPE_BLOCKS;
-			dobval = 1;
+			q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv);
+			keys[numreturn].qk_idtype = idtype;
+			keys[numreturn].qk_id = QUOTA_DEFAULTID;
+			keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
+			vals[numreturn++] = qv;
 			cursor->q2c_blocks_done = 1;
 		}
 		if (cursor->q2c_blocks_done == 1) {
-			q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &fval);
-			fkey.qk_idtype = idtype;
-			fkey.qk_id = QUOTA_DEFAULTID;
-			fkey.qk_objtype = QUOTA_OBJTYPE_FILES;
-			dofval = 1;
+			q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv);
+			keys[numreturn].qk_idtype = idtype;
+			keys[numreturn].qk_id = QUOTA_DEFAULTID;
+			keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES;
+			vals[numreturn++] = qv;
 			cursor->q2c_blocks_done = 0;
 			cursor->q2c_defaults_done = 1;
 		}
@@ -1126,26 +1125,31 @@ quota2_handle_cmd_getall(struct ufsmount
 	if (gu.limit == 0 && (maxreturn - numreturn) > 0) {
 		gu.limit = 1;
 	}
-	if (dobval && gu.limit > 0)
-		gu.limit--;
-	if (dofval && gu.limit > 0)
-		gu.limit--;
 	for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) {
 		offset = q2h->q2h_entries[i];
 		gu.seen = 0;
 		error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu,
 		    quota2_getuids_callback);
+		if (error && error != Q2WL_ABORT) {
+			if (gu.uids != NULL)
+				free(gu.uids, M_TEMP);
+			break;
+		}
 		if (error == Q2WL_ABORT) {
 			/* got enough uids for now */
 			error = 0;
-			break;
 		}
-		if (error) {
-			if (gu.uids != NULL)
-				free(gu.uids, M_TEMP);
+		if (gu.nuids > gu.limit) {
+			excess = gu.nuids - gu.limit;
+			KASSERT(excess < gu.seen);
+			gu.seen -= excess;
+			gu.nuids -= excess;
+		}
+		if (gu.nuids == gu.limit) {
 			break;
 		}
 	}
+	KASSERT(gu.nuids <= gu.limit);
 	cursor->q2c_hashpos = i;
 	cursor->q2c_uidpos = gu.seen;
 
@@ -1156,28 +1160,6 @@ fail:
 		return error;
 
 	maxnum = gu.nuids*2;
-	if (dobval)
-		maxnum++;
-	if (dofval)
-		maxnum++;
-	result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]),
-				 M_TEMP, M_WAITOK);
-	result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]),
-				 M_TEMP, M_WAITOK);
-
-	if (dobval && numreturn < maxreturn) {
-		result->qr_keys[numreturn] = bkey;
-		result->qr_vals[numreturn] = bval;
-		numreturn++;
-	}
-	if (dofval && numreturn < maxreturn) {
-		result->qr_keys[numreturn] = fkey;
-		result->qr_vals[numreturn] = fval;
-		numreturn++;
-	}
-	if (numreturn == maxreturn) {
-		return 0;
-	}
 
 	/*
 	 * If we've already sent back the blocks value for the first id,
@@ -1188,11 +1170,11 @@ fail:
 	 * leave off the last result entry (skiplast).
 	 */
 	skipfirst = (cursor->q2c_blocks_done != 0);
-	skiplast = skipfirst == 0 && (result->qr_max < maxnum);
+	skiplast = skipfirst == 0 && (maxreturn < maxnum);
 	num = 0;
 	for (j = 0; j < gu.nuids; j++) {
 		error = quota2_result_add_q2e(ump, idtype,
-		    gu.uids[j], result, numreturn + j*2,
+		    gu.uids[j], keys, vals, numreturn + j*2,
 		    j == 0 && skipfirst,
 		    j + 1 == gu.nuids && skiplast);
 		if (error == ENOENT)
@@ -1206,11 +1188,12 @@ fail:
 		}
 	}
 	numreturn += num;
-	result->qr_num = numreturn;
+	*ret = numreturn;
 
 	cursor->q2c_blocks_done = skiplast;
 
-	free(gu.uids, M_TEMP);
+	if (gu.uids != NULL)
+		free(gu.uids, M_TEMP);
 	return error;
 }
 

Reply via email to