Sun Jan 29 07:05:13 2012 UTC ()
Teach quota2 QUOTACTL_GETALL to acecpt a limit on how much it sends back.
Pass in a dummy limit for now.

Note: this change requires a kernel version bump.


(dholland)
diff -r1.23 -r1.24 src/sys/kern/vfs_quotactl.c
diff -r1.21 -r1.22 src/sys/sys/quotactl.h
diff -r1.20 -r1.21 src/sys/ufs/ufs/ufs_quota2.c

cvs diff -r1.23 -r1.24 src/sys/kern/vfs_quotactl.c (expand / switch to unified diff)

--- src/sys/kern/vfs_quotactl.c 2012/01/29 07:02:06 1.23
+++ src/sys/kern/vfs_quotactl.c 2012/01/29 07:05:12 1.24
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: vfs_quotactl.c,v 1.23 2012/01/29 07:02:06 dholland Exp $ */ 1/* $NetBSD: vfs_quotactl.c,v 1.24 2012/01/29 07:05:12 dholland Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1991, 1993, 1994 4 * Copyright (c) 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * (c) UNIX System Laboratories, Inc. 6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed 7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph 8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc. 10 * the permission of UNIX System Laboratories, Inc.
11 * 11 *
12 * Redistribution and use in source and binary forms, with or without 12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions 13 * modification, are permitted provided that the following conditions
14 * are met: 14 * are met:
@@ -70,27 +70,27 @@ @@ -70,27 +70,27 @@
70 * 70 *
71 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95 71 * @(#)ufs_quota.c 8.5 (Berkeley) 5/20/95
72 * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp 72 * From NetBSD: ufs_quota.c,v 1.70 2011/03/24 17:05:46 bouyer Exp
73 */ 73 */
74 74
75/* 75/*
76 * Note that both of the copyrights above are moderately spurious; 76 * Note that both of the copyrights above are moderately spurious;
77 * this code should almost certainly have the Copyright 2010 Manuel 77 * this code should almost certainly have the Copyright 2010 Manuel
78 * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c. 78 * Bouyer notice and license found in e.g. sys/ufs/ufs/quota2_subr.c.
79 * However, they're what was on the files this code was sliced out of. 79 * However, they're what was on the files this code was sliced out of.
80 */ 80 */
81 81
82#include <sys/cdefs.h> 82#include <sys/cdefs.h>
83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.23 2012/01/29 07:02:06 dholland Exp $"); 83__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.24 2012/01/29 07:05:12 dholland Exp $");
84 84
85#include <sys/malloc.h> /* XXX: temporary */ 85#include <sys/malloc.h> /* XXX: temporary */
86#include <sys/mount.h> 86#include <sys/mount.h>
87#include <sys/quota.h> 87#include <sys/quota.h>
88#include <sys/quotactl.h> 88#include <sys/quotactl.h>
89#include <quota/quotaprop.h> 89#include <quota/quotaprop.h>
90 90
91static int 91static int
92vfs_quotactl_getversion(struct mount *mp, 92vfs_quotactl_getversion(struct mount *mp,
93 prop_dictionary_t cmddict, int q2type, 93 prop_dictionary_t cmddict, int q2type,
94 prop_array_t datas) 94 prop_array_t datas)
95{ 95{
96 prop_array_t replies; 96 prop_array_t replies;
@@ -516,26 +516,28 @@ vfs_quotactl_getall(struct mount *mp, @@ -516,26 +516,28 @@ vfs_quotactl_getall(struct mount *mp,
516 int skip = 0; 516 int skip = 0;
517 517
518 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); 518 KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY);
519 519
520 args.qc_type = QCT_CURSOROPEN; 520 args.qc_type = QCT_CURSOROPEN;
521 args.u.cursoropen.qc_cursor = &cursor; 521 args.u.cursoropen.qc_cursor = &cursor;
522 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args); 522 error = VFS_QUOTACTL(mp, QUOTACTL_CURSOROPEN, &args);
523 if (error) { 523 if (error) {
524 return error; 524 return error;
525 } 525 }
526 526
527 result.qr_keys = NULL; 527 result.qr_keys = NULL;
528 result.qr_vals = NULL; 528 result.qr_vals = NULL;
 529 result.qr_num = 0;
 530 result.qr_max = 0x7fffffff; /* XXX bogus; but temporary */
529 531
530 args.qc_type = QCT_GETALL; 532 args.qc_type = QCT_GETALL;
531 args.u.getall.qc_cursor = &cursor; 533 args.u.getall.qc_cursor = &cursor;
532 args.u.getall.qc_idtype = q2type; 534 args.u.getall.qc_idtype = q2type;
533 args.u.getall.qc_result = &result; 535 args.u.getall.qc_result = &result;
534 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); 536 error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args);
535 /* 537 /*
536 * XXX this is bogus but up until now *all* errors 538 * XXX this is bogus but up until now *all* errors
537 * from inside quotactl_getall were suppressed by the 539 * from inside quotactl_getall were suppressed by the
538 * dispatching code in ufs_quota.c. Fixing that causes 540 * dispatching code in ufs_quota.c. Fixing that causes
539 * repquota to break in an undesirable way; this is a 541 * repquota to break in an undesirable way; this is a
540 * workaround. 542 * workaround.
541 */ 543 */

cvs diff -r1.21 -r1.22 src/sys/sys/quotactl.h (expand / switch to unified diff)

--- src/sys/sys/quotactl.h 2012/01/29 07:02:06 1.21
+++ src/sys/sys/quotactl.h 2012/01/29 07:05:12 1.22
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: quotactl.h,v 1.21 2012/01/29 07:02:06 dholland Exp $ */ 1/* $NetBSD: quotactl.h,v 1.22 2012/01/29 07:05:12 dholland Exp $ */
2/*- 2/*-
3 * Copyright (c) 2011 The NetBSD Foundation, Inc. 3 * Copyright (c) 2011 The NetBSD Foundation, Inc.
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * This code is derived from software contributed to The NetBSD Foundation 6 * This code is derived from software contributed to The NetBSD Foundation
7 * by David A. Holland. 7 * by David A. Holland.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
@@ -102,19 +102,20 @@ struct vfs_quotactl_args { @@ -102,19 +102,20 @@ struct vfs_quotactl_args {
102 } cursoropen; 102 } cursoropen;
103 struct { 103 struct {
104 struct quotakcursor *qc_cursor; 104 struct quotakcursor *qc_cursor;
105 } cursorclose; 105 } cursorclose;
106 struct { 106 struct {
107 struct quotakcursor *qc_cursor; 107 struct quotakcursor *qc_cursor;
108 int qc_idtype; 108 int qc_idtype;
109 struct quota_getall_result { 109 struct quota_getall_result {
110 struct quotaval qr_defblocks; 110 struct quotaval qr_defblocks;
111 struct quotaval qr_deffiles; 111 struct quotaval qr_deffiles;
112 struct quotakey *qr_keys; 112 struct quotakey *qr_keys;
113 struct quotaval *qr_vals; 113 struct quotaval *qr_vals;
114 unsigned qr_num; 114 unsigned qr_num;
 115 unsigned qr_max;
115 } *qc_result; 116 } *qc_result;
116 } getall; 117 } getall;
117 } u; 118 } u;
118}; 119};
119 120
120#endif /* _SYS_QUOTACTL_H_ */ 121#endif /* _SYS_QUOTACTL_H_ */

cvs diff -r1.20 -r1.21 src/sys/ufs/ufs/ufs_quota2.c (expand / switch to unified diff)

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:04:21 1.20
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:05:12 1.21
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ufs_quota2.c,v 1.20 2012/01/29 07:04:21 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 dholland Exp $ */
2/*- 2/*-
3 * Copyright (c) 2010 Manuel Bouyer 3 * Copyright (c) 2010 Manuel Bouyer
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
@@ -16,27 +16,27 @@ @@ -16,27 +16,27 @@
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.20 2012/01/29 07:04:21 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 dholland Exp $");
30 30
31#include <sys/buf.h> 31#include <sys/buf.h>
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/kernel.h> 33#include <sys/kernel.h>
34#include <sys/systm.h> 34#include <sys/systm.h>
35#include <sys/malloc.h> 35#include <sys/malloc.h>
36#include <sys/namei.h> 36#include <sys/namei.h>
37#include <sys/file.h> 37#include <sys/file.h>
38#include <sys/proc.h> 38#include <sys/proc.h>
39#include <sys/vnode.h> 39#include <sys/vnode.h>
40#include <sys/mount.h> 40#include <sys/mount.h>
41#include <sys/fstrans.h> 41#include <sys/fstrans.h>
42#include <sys/kauth.h> 42#include <sys/kauth.h>
@@ -819,27 +819,28 @@ quota2_handle_cmd_delete(struct ufsmount @@ -819,27 +819,28 @@ quota2_handle_cmd_delete(struct ufsmount
819out_dqlock: 819out_dqlock:
820 mutex_exit(&dqlock); 820 mutex_exit(&dqlock);
821out_wapbl: 821out_wapbl:
822 UFS_WAPBL_END(ump->um_mountp); 822 UFS_WAPBL_END(ump->um_mountp);
823out_il: 823out_il:
824 mutex_exit(&dq->dq_interlock); 824 mutex_exit(&dq->dq_interlock);
825out_dq: 825out_dq:
826 dqrele(NULLVP, dq); 826 dqrele(NULLVP, dq);
827 return error; 827 return error;
828} 828}
829 829
830static int 830static int
831quota2_result_add_q2e(struct ufsmount *ump, int idtype, 831quota2_result_add_q2e(struct ufsmount *ump, int idtype,
832 int id, struct quota_getall_result *result, unsigned pos) 832 int id, struct quota_getall_result *result, unsigned pos,
 833 int skipfirst, int skiplast)
833{ 834{
834 struct dquot *dq; 835 struct dquot *dq;
835 int error; 836 int error;
836 struct quota2_entry *q2ep, q2e; 837 struct quota2_entry *q2ep, q2e;
837 struct buf *bp; 838 struct buf *bp;
838 const int needswap = UFS_MPNEEDSWAP(ump); 839 const int needswap = UFS_MPNEEDSWAP(ump);
839 840
840 error = dqget(NULLVP, id, ump, idtype, &dq); 841 error = dqget(NULLVP, id, ump, idtype, &dq);
841 if (error) 842 if (error)
842 return error; 843 return error;
843 844
844 mutex_enter(&dq->dq_interlock); 845 mutex_enter(&dq->dq_interlock);
845 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 846 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
@@ -849,35 +850,41 @@ quota2_result_add_q2e(struct ufsmount *u @@ -849,35 +850,41 @@ quota2_result_add_q2e(struct ufsmount *u
849 } 850 }
850 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 851 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
851 &bp, &q2ep, 0); 852 &bp, &q2ep, 0);
852 if (error) { 853 if (error) {
853 mutex_exit(&dq->dq_interlock); 854 mutex_exit(&dq->dq_interlock);
854 dqrele(NULLVP, dq); 855 dqrele(NULLVP, dq);
855 return error; 856 return error;
856 } 857 }
857 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 858 quota2_ufs_rwq2e(q2ep, &q2e, needswap);
858 brelse(bp, 0); 859 brelse(bp, 0);
859 mutex_exit(&dq->dq_interlock); 860 mutex_exit(&dq->dq_interlock);
860 dqrele(NULLVP, dq); 861 dqrele(NULLVP, dq);
861 862
862 result->qr_keys[pos].qk_idtype = idtype; 863 if (skipfirst == 0) {
863 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 864 result->qr_keys[pos].qk_idtype = idtype;
864 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id, 865 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
865 QL_BLOCK, &result->qr_vals[pos]); 866 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
866 867 QL_BLOCK, &result->qr_vals[pos]);
867 result->qr_keys[pos+1].qk_idtype = idtype; 868 pos++;
868 result->qr_keys[pos+1].qk_objtype = QUOTA_OBJTYPE_FILES; 869 }
869 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos+1].qk_id, 870
870 QL_FILE, &result->qr_vals[pos+1]); 871 if (skiplast == 0) {
 872 result->qr_keys[pos].qk_idtype = idtype;
 873 result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES;
 874 q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id,
 875 QL_FILE, &result->qr_vals[pos]);
 876 pos++;
 877 }
871 878
872 return 0; 879 return 0;
873} 880}
874 881
875static int 882static int
876quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 883quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
877 struct quotaval *ret) 884 struct quotaval *ret)
878{ 885{
879 struct dquot *dq; 886 struct dquot *dq;
880 int error; 887 int error;
881 struct quota2_entry *q2ep, q2e; 888 struct quota2_entry *q2ep, q2e;
882 struct buf *bp; 889 struct buf *bp;
883 const int needswap = UFS_MPNEEDSWAP(ump); 890 const int needswap = UFS_MPNEEDSWAP(ump);
@@ -987,26 +994,27 @@ q2cursor_check(struct ufsq2_cursor *curs @@ -987,26 +994,27 @@ q2cursor_check(struct ufsq2_cursor *curs
987 } 994 }
988 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { 995 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
989 return EINVAL; 996 return EINVAL;
990 } 997 }
991 return 0; 998 return 0;
992} 999}
993 1000
994struct getuids { 1001struct getuids {
995 long nuids; /* number of uids in array */ 1002 long nuids; /* number of uids in array */
996 long size; /* size of array */ 1003 long size; /* size of array */
997 uid_t *uids; /* array of uids, dynamically allocated */ 1004 uid_t *uids; /* array of uids, dynamically allocated */
998 long skip; 1005 long skip;
999 long seen; 1006 long seen;
 1007 long limit;
1000}; 1008};
1001 1009
1002static int 1010static int
1003quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 1011quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
1004 struct quota2_entry *q2ep, uint64_t off, void *v) 1012 struct quota2_entry *q2ep, uint64_t off, void *v)
1005{ 1013{
1006 struct getuids *gu = v; 1014 struct getuids *gu = v;
1007 uid_t *newuids; 1015 uid_t *newuids;
1008#ifdef FFS_EI 1016#ifdef FFS_EI
1009 const int needswap = UFS_MPNEEDSWAP(ump); 1017 const int needswap = UFS_MPNEEDSWAP(ump);
1010#endif 1018#endif
1011 1019
1012 if (gu->skip > 0) { 1020 if (gu->skip > 0) {
@@ -1016,46 +1024,50 @@ quota2_getuids_callback(struct ufsmount  @@ -1016,46 +1024,50 @@ quota2_getuids_callback(struct ufsmount
1016 if (gu->nuids == gu->size) { 1024 if (gu->nuids == gu->size) {
1017 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP, 1025 newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP,
1018 M_WAITOK); 1026 M_WAITOK);
1019 if (newuids == NULL) { 1027 if (newuids == NULL) {
1020 free(gu->uids, M_TEMP); 1028 free(gu->uids, M_TEMP);
1021 return ENOMEM; 1029 return ENOMEM;
1022 } 1030 }
1023 gu->uids = newuids; 1031 gu->uids = newuids;
1024 gu->size += (PAGE_SIZE / sizeof(uid_t)); 1032 gu->size += (PAGE_SIZE / sizeof(uid_t));
1025 } 1033 }
1026 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 1034 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
1027 gu->nuids++; 1035 gu->nuids++;
1028 gu->seen++; 1036 gu->seen++;
 1037 if (gu->nuids == gu->limit) {
 1038 return Q2WL_ABORT;
 1039 }
1029 return 0; 1040 return 0;
1030} 1041}
1031 1042
1032int 1043int
1033quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, 1044quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc,
1034 int idtype, struct quota_getall_result *result) 1045 int idtype, struct quota_getall_result *result)
1035{ 1046{
1036 int error; 1047 int error;
1037 struct ufsq2_cursor *cursor; 1048 struct ufsq2_cursor *cursor;
1038 struct quota2_header *q2h; 1049 struct quota2_header *q2h;
1039 struct quota2_entry q2e; 1050 struct quota2_entry q2e;
1040 struct buf *hbp; 1051 struct buf *hbp;
1041 uint64_t offset; 1052 uint64_t offset;
1042 int i, j; 1053 int i, j;
1043 int quota2_hash_size; 1054 int quota2_hash_size;
1044 const int needswap = UFS_MPNEEDSWAP(ump); 1055 const int needswap = UFS_MPNEEDSWAP(ump);
1045 struct getuids gu; 1056 struct getuids gu;
1046 id_t junkid; 1057 id_t junkid;
1047 struct quotaval qv; 1058 struct quotaval qv;
1048 unsigned num, maxnum; 1059 unsigned num, maxnum;
 1060 int skipfirst, skiplast;
1049 1061
1050 cursor = Q2CURSOR(qkc); 1062 cursor = Q2CURSOR(qkc);
1051 error = q2cursor_check(cursor); 1063 error = q2cursor_check(cursor);
1052 if (error) { 1064 if (error) {
1053 return error; 1065 return error;
1054 } 1066 }
1055 1067
1056 if (ump->um_quotas[idtype] == NULLVP) { 1068 if (ump->um_quotas[idtype] == NULLVP) {
1057 return ENODEV; 1069 return ENODEV;
1058 } 1070 }
1059 1071
1060 mutex_enter(&dqlock); 1072 mutex_enter(&dqlock);
1061 error = getq2h(ump, idtype, &hbp, &q2h, 0); 1073 error = getq2h(ump, idtype, &hbp, &q2h, 0);
@@ -1088,64 +1100,87 @@ quota2_handle_cmd_getall(struct ufsmount @@ -1088,64 +1100,87 @@ quota2_handle_cmd_getall(struct ufsmount
1088 memset(&gu, 0, sizeof(gu)); 1100 memset(&gu, 0, sizeof(gu));
1089 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 1101 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1090 1102
1091 /* if the table size has changed, make the caller start over */ 1103 /* if the table size has changed, make the caller start over */
1092 if (cursor->q2c_hashsize == 0) { 1104 if (cursor->q2c_hashsize == 0) {
1093 cursor->q2c_hashsize = quota2_hash_size; 1105 cursor->q2c_hashsize = quota2_hash_size;
1094 } else if (cursor->q2c_hashsize != quota2_hash_size) { 1106 } else if (cursor->q2c_hashsize != quota2_hash_size) {
1095 error = EDEADLK; 1107 error = EDEADLK;
1096 goto fail; 1108 goto fail;
1097 } 1109 }
1098 1110
1099 gu.skip = cursor->q2c_uidpos; 1111 gu.skip = cursor->q2c_uidpos;
1100 gu.seen = 0; 1112 gu.seen = 0;
 1113 gu.limit = result->qr_max / 2;
 1114 if (gu.limit == 0 && result->qr_max > 0) {
 1115 gu.limit = 1;
 1116 }
1101 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { 1117 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) {
1102 offset = q2h->q2h_entries[i]; 1118 offset = q2h->q2h_entries[i];
1103 gu.seen = 0; 1119 gu.seen = 0;
1104 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, 1120 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu,
1105 quota2_getuids_callback); 1121 quota2_getuids_callback);
 1122 if (error == Q2WL_ABORT) {
 1123 /* got enough uids for now */
 1124 error = 0;
 1125 break;
 1126 }
1106 if (error) { 1127 if (error) {
1107 if (gu.uids != NULL) 1128 if (gu.uids != NULL)
1108 free(gu.uids, M_TEMP); 1129 free(gu.uids, M_TEMP);
1109 break; 1130 break;
1110 } 1131 }
1111 } 1132 }
1112 cursor->q2c_hashpos = i; 1133 cursor->q2c_hashpos = i;
1113 cursor->q2c_uidpos = gu.seen; 1134 cursor->q2c_uidpos = gu.seen;
1114 1135
1115fail: 1136fail:
1116 mutex_exit(&dqlock); 1137 mutex_exit(&dqlock);
1117 brelse(hbp, 0); 1138 brelse(hbp, 0);
1118 if (error) 1139 if (error)
1119 return error; 1140 return error;
1120 1141
1121 maxnum = gu.nuids*2; 1142 maxnum = gu.nuids*2;
1122 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), 1143 result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]),
1123 M_TEMP, M_WAITOK); 1144 M_TEMP, M_WAITOK);
1124 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), 1145 result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]),
1125 M_TEMP, M_WAITOK); 1146 M_TEMP, M_WAITOK);
1126 1147
 1148 /*
 1149 * If we've already sent back the blocks value for the first id,
 1150 * don't send it again (skipfirst).
 1151 *
 1152 * If we have an odd number of available result slots and we
 1153 * aren't going to skip the first result entry, we need to
 1154 * leave off the last result entry (skiplast).
 1155 */
 1156 skipfirst = (cursor->q2c_blocks_done != 0);
 1157 skiplast = skipfirst == 0 && (result->qr_max < maxnum);
1127 num = 0; 1158 num = 0;
1128 for (j = 0; j < gu.nuids; j++) { 1159 for (j = 0; j < gu.nuids; j++) {
1129 error = quota2_result_add_q2e(ump, idtype, 1160 error = quota2_result_add_q2e(ump, idtype,
1130 gu.uids[j], result, j*2); 1161 gu.uids[j], result, j*2,
 1162 j == 0 && skipfirst,
 1163 j + 1 == gu.nuids && skiplast);
1131 if (error == ENOENT) 1164 if (error == ENOENT)
1132 continue; 1165 continue;
1133 if (error) 1166 if (error)
1134 break; 1167 break;
1135 num += 2; 1168 num += 2;
1136 } 1169 }
1137 result->qr_num = num; 1170 result->qr_num = num;
1138 1171
 1172 cursor->q2c_blocks_done = skiplast;
 1173
1139 free(gu.uids, M_TEMP); 1174 free(gu.uids, M_TEMP);
1140 return error; 1175 return error;
1141} 1176}
1142 1177
1143int 1178int
1144quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) 1179quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1145{ 1180{
1146 struct ufsq2_cursor *cursor; 1181 struct ufsq2_cursor *cursor;
1147 1182
1148 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); 1183 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1149 cursor = Q2CURSOR(qkc); 1184 cursor = Q2CURSOR(qkc);
1150 1185
1151 cursor->q2c_magic = Q2C_MAGIC; 1186 cursor->q2c_magic = Q2C_MAGIC;