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; }