Sun Jan 29 07:21:00 2012 UTC ()
Clean up quota2 cursoring, as promised earlier.


(dholland)
diff -r1.29 -r1.30 src/sys/ufs/ufs/ufs_quota2.c

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

--- src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:20:27 1.29
+++ src/sys/ufs/ufs/ufs_quota2.c 2012/01/29 07:21:00 1.30
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ufs_quota2.c,v 1.29 2012/01/29 07:20:27 dholland Exp $ */ 1/* $NetBSD: ufs_quota2.c,v 1.30 2012/01/29 07:21:00 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,33 +16,32 @@ @@ -16,33 +16,32 @@
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.29 2012/01/29 07:20:27 dholland Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.30 2012/01/29 07:21:00 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> 
36#include <sys/namei.h> 35#include <sys/namei.h>
37#include <sys/file.h> 36#include <sys/file.h>
38#include <sys/proc.h> 37#include <sys/proc.h>
39#include <sys/vnode.h> 38#include <sys/vnode.h>
40#include <sys/mount.h> 39#include <sys/mount.h>
41#include <sys/fstrans.h> 40#include <sys/fstrans.h>
42#include <sys/kauth.h> 41#include <sys/kauth.h>
43#include <sys/wapbl.h> 42#include <sys/wapbl.h>
44#include <sys/quota.h> 43#include <sys/quota.h>
45#include <sys/quotactl.h> 44#include <sys/quotactl.h>
46 45
47#include <ufs/ufs/quota2.h> 46#include <ufs/ufs/quota2.h>
48#include <ufs/ufs/inode.h> 47#include <ufs/ufs/inode.h>
@@ -784,79 +783,62 @@ quota2_handle_cmd_delete(struct ufsmount @@ -784,79 +783,62 @@ quota2_handle_cmd_delete(struct ufsmount
784 783
785out_dqlock: 784out_dqlock:
786 mutex_exit(&dqlock); 785 mutex_exit(&dqlock);
787out_wapbl: 786out_wapbl:
788 UFS_WAPBL_END(ump->um_mountp); 787 UFS_WAPBL_END(ump->um_mountp);
789out_il: 788out_il:
790 mutex_exit(&dq->dq_interlock); 789 mutex_exit(&dq->dq_interlock);
791out_dq: 790out_dq:
792 dqrele(NULLVP, dq); 791 dqrele(NULLVP, dq);
793 return error; 792 return error;
794} 793}
795 794
796static int 795static int
797quota2_result_add_q2e(struct ufsmount *ump, int idtype, 796quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
798 int id, struct quotakey *keys, struct quotaval *vals, unsigned pos, 797 struct quota2_entry *ret)
799 int skipfirst, int skiplast) 
800{ 798{
801 struct dquot *dq; 799 struct dquot *dq;
802 int error; 800 int error;
803 struct quota2_entry *q2ep, q2e; 801 struct quota2_entry *q2ep;
804 struct buf *bp; 802 struct buf *bp;
805 const int needswap = UFS_MPNEEDSWAP(ump); 803 const int needswap = UFS_MPNEEDSWAP(ump);
806 804
807 error = dqget(NULLVP, id, ump, idtype, &dq); 805 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
808 if (error) 806 if (error)
809 return error; 807 return error;
810 808
811 mutex_enter(&dq->dq_interlock); 809 mutex_enter(&dq->dq_interlock);
812 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) { 810 if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
813 mutex_exit(&dq->dq_interlock); 811 mutex_exit(&dq->dq_interlock);
814 dqrele(NULLVP, dq); 812 dqrele(NULLVP, dq);
815 return ENOENT; 813 return ENOENT;
816 } 814 }
817 error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, 815 error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
818 &bp, &q2ep, 0); 816 &bp, &q2ep, 0);
819 if (error) { 817 if (error) {
820 mutex_exit(&dq->dq_interlock); 818 mutex_exit(&dq->dq_interlock);
821 dqrele(NULLVP, dq); 819 dqrele(NULLVP, dq);
822 return error; 820 return error;
823 } 821 }
824 quota2_ufs_rwq2e(q2ep, &q2e, needswap); 822 quota2_ufs_rwq2e(q2ep, ret, needswap);
825 brelse(bp, 0); 823 brelse(bp, 0);
826 mutex_exit(&dq->dq_interlock); 824 mutex_exit(&dq->dq_interlock);
827 dqrele(NULLVP, dq); 825 dqrele(NULLVP, dq);
828 826
829 if (skipfirst == 0) { 
830 keys[pos].qk_idtype = idtype; 
831 keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 
832 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, 
833 QL_BLOCK, &vals[pos]); 
834 pos++; 
835 } 
836 
837 if (skiplast == 0) { 
838 keys[pos].qk_idtype = idtype; 
839 keys[pos].qk_objtype = QUOTA_OBJTYPE_FILES; 
840 q2e_to_quotaval(&q2e, 0, &keys[pos].qk_id, 
841 QL_FILE, &vals[pos]); 
842 pos++; 
843 } 
844 
845 return 0; 827 return 0;
846} 828}
847 829
848static int 830static int
849quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk, 831quota2_fetch_quotaval(struct ufsmount *ump, const struct quotakey *qk,
850 struct quotaval *ret) 832 struct quotaval *ret)
851{ 833{
852 struct dquot *dq; 834 struct dquot *dq;
853 int error; 835 int error;
854 struct quota2_entry *q2ep, q2e; 836 struct quota2_entry *q2ep, q2e;
855 struct buf *bp; 837 struct buf *bp;
856 const int needswap = UFS_MPNEEDSWAP(ump); 838 const int needswap = UFS_MPNEEDSWAP(ump);
857 id_t id2; 839 id_t id2;
858 840
859 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq); 841 error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
860 if (error) 842 if (error)
861 return error; 843 return error;
862 844
@@ -913,47 +895,97 @@ quota2_handle_cmd_get(struct ufsmount *u @@ -913,47 +895,97 @@ quota2_handle_cmd_get(struct ufsmount *u
913 mutex_enter(&dqlock); 895 mutex_enter(&dqlock);
914 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0); 896 error = getq2h(ump, qk->qk_idtype, &bp, &q2h, 0);
915 if (error) { 897 if (error) {
916 mutex_exit(&dqlock); 898 mutex_exit(&dqlock);
917 return error; 899 return error;
918 } 900 }
919 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 901 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
920 mutex_exit(&dqlock); 902 mutex_exit(&dqlock);
921 brelse(bp, 0); 903 brelse(bp, 0);
922 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2, 904 q2e_to_quotaval(&q2e, qk->qk_id == QUOTA_DEFAULTID, &id2,
923 qk->qk_objtype, ret); 905 qk->qk_objtype, ret);
924 (void)id2; 906 (void)id2;
925 } else 907 } else
926 error = quota2_fetch_q2e(ump, qk, ret); 908 error = quota2_fetch_quotaval(ump, qk, ret);
927  909
928 return error; 910 return error;
929} 911}
930 912
 913/*
 914 * Cursor structure we used.
 915 *
 916 * This will get stored in userland between calls so we must not assume
 917 * it isn't arbitrarily corrupted.
 918 */
931struct ufsq2_cursor { 919struct ufsq2_cursor {
932 uint32_t q2c_magic; /* magic number */ 920 uint32_t q2c_magic; /* magic number */
933 int q2c_hashsize; /* size of hash table at last go */ 921 int q2c_hashsize; /* size of hash table at last go */
934 922
935 int q2c_users_done; /* true if we've returned all user data */ 923 int q2c_users_done; /* true if we've returned all user data */
936 int q2c_groups_done; /* true if we've returned all group data */ 924 int q2c_groups_done; /* true if we've returned all group data */
937 int q2c_defaults_done; /* true if we've returned the default values */ 925 int q2c_defaults_done; /* true if we've returned the default values */
938 int q2c_hashpos; /* slot to start at in hash table */ 926 int q2c_hashpos; /* slot to start at in hash table */
939 int q2c_uidpos; /* number of ids we've handled */ 927 int q2c_uidpos; /* number of ids we've handled */
940 int q2c_blocks_done; /* true if we've returned the blocks value */ 928 int q2c_blocks_done; /* true if we've returned the blocks value */
941}; 929};
942 930
 931/*
 932 * State of a single cursorget call, or at least the part of it that
 933 * needs to be passed around.
 934 */
 935struct q2cursor_state {
 936 /* data return pointers */
 937 struct quotakey *keys;
 938 struct quotaval *vals;
 939
 940 /* key/value counters */
 941 unsigned maxkeyvals;
 942 unsigned numkeys; /* number of keys assigned */
 943
 944 /* ID to key/value conversion state */
 945 int skipfirst; /* if true skip first key/value */
 946 int skiplast; /* if true skip last key/value */
 947
 948 /* ID counters */
 949 unsigned maxids; /* maximum number of IDs to handle */
 950 unsigned numids; /* number of IDs handled */
 951};
 952
 953/*
 954 * Additional structure for getids callback.
 955 */
 956struct q2cursor_getids {
 957 struct q2cursor_state *state;
 958 int idtype;
 959 unsigned skip; /* number of ids to skip over */
 960 unsigned new_skip; /* number of ids to skip over next time */
 961 unsigned skipped; /* number skipped so far */
 962};
 963
 964/*
 965 * Cursor-related functions
 966 */
 967
 968/* magic number */
943#define Q2C_MAGIC (0xbeebe111) 969#define Q2C_MAGIC (0xbeebe111)
944 970
 971/* extract cursor from caller form */
945#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0]) 972#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
946 973
 974/*
 975 * Check that a cursor we're handed is something like valid. If
 976 * someone munges it and it still passes these checks, they'll get
 977 * partial or odd results back but won't break anything.
 978 */
947static int 979static int
948q2cursor_check(struct ufsq2_cursor *cursor) 980q2cursor_check(struct ufsq2_cursor *cursor)
949{ 981{
950 if (cursor->q2c_magic != Q2C_MAGIC) { 982 if (cursor->q2c_magic != Q2C_MAGIC) {
951 return EINVAL; 983 return EINVAL;
952 } 984 }
953 if (cursor->q2c_hashsize < 0) { 985 if (cursor->q2c_hashsize < 0) {
954 return EINVAL; 986 return EINVAL;
955 } 987 }
956 988
957 if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) { 989 if (cursor->q2c_users_done != 0 && cursor->q2c_users_done != 1) {
958 return EINVAL; 990 return EINVAL;
959 } 991 }
@@ -962,260 +994,393 @@ q2cursor_check(struct ufsq2_cursor *curs @@ -962,260 +994,393 @@ q2cursor_check(struct ufsq2_cursor *curs
962 } 994 }
963 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) { 995 if (cursor->q2c_defaults_done != 0 && cursor->q2c_defaults_done != 1) {
964 return EINVAL; 996 return EINVAL;
965 } 997 }
966 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) { 998 if (cursor->q2c_hashpos < 0 || cursor->q2c_uidpos < 0) {
967 return EINVAL; 999 return EINVAL;
968 } 1000 }
969 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) { 1001 if (cursor->q2c_blocks_done != 0 && cursor->q2c_blocks_done != 1) {
970 return EINVAL; 1002 return EINVAL;
971 } 1003 }
972 return 0; 1004 return 0;
973} 1005}
974 1006
975struct getuids { 1007/*
976 long nuids; /* number of uids in array */ 1008 * Set up the q2cursor state.
977 long maxuids; /* number of uids allocated */ 1009 */
978 uid_t *uids; /* array of uids, dynamically allocated */ 1010static void
979 long skip; 1011q2cursor_initstate(struct q2cursor_state *state, struct quotakey *keys,
980 long seen; 1012 struct quotaval *vals, unsigned maxkeyvals, int blocks_done)
981 long limit; 1013{
982}; 1014 state->keys = keys;
 1015 state->vals = vals;
 1016
 1017 state->maxkeyvals = maxkeyvals;
 1018 state->numkeys = 0;
 1019
 1020 /*
 1021 * For each ID there are two quotavals to return. If the
 1022 * maximum number of entries to return is odd, we might want
 1023 * to skip the first quotaval of the first ID, or the last
 1024 * quotaval of the last ID, but not both. So the number of IDs
 1025 * we want is (up to) half the number of return slots we have,
 1026 * rounded up.
 1027 */
 1028
 1029 state->maxids = (state->maxkeyvals + 1) / 2;
 1030 state->numids = 0;
 1031 if (state->maxkeyvals % 2) {
 1032 if (blocks_done) {
 1033 state->skipfirst = 1;
 1034 state->skiplast = 0;
 1035 } else {
 1036 state->skipfirst = 0;
 1037 state->skiplast = 1;
 1038 }
 1039 } else {
 1040 state->skipfirst = 0;
 1041 state->skiplast = 0;
 1042 }
 1043}
 1044
 1045/*
 1046 * Choose which idtype we're going to work on. If doing a full
 1047 * iteration, we do users first, then groups, but either might be
 1048 * disabled or marked to skip via cursorsetidtype(), so don't make
 1049 * silly assumptions.
 1050 */
 1051static int
 1052q2cursor_pickidtype(struct ufsq2_cursor *cursor, int *idtype_ret)
 1053{
 1054 if (cursor->q2c_users_done == 0) {
 1055 *idtype_ret = QUOTA_IDTYPE_USER;
 1056 } else if (cursor->q2c_groups_done == 0) {
 1057 *idtype_ret = QUOTA_IDTYPE_GROUP;
 1058 } else {
 1059 return EAGAIN;
 1060 }
 1061 return 0;
 1062}
 1063
 1064/*
 1065 * Add an ID to the current state. Sets up either one or two keys to
 1066 * refer to it, depending on whether it's first/last and the setting
 1067 * of skipfirst. (skiplast does not need to be explicitly tested)
 1068 */
 1069static void
 1070q2cursor_addid(struct q2cursor_state *state, int idtype, id_t id)
 1071{
 1072 KASSERT(state->numids < state->maxids);
 1073 KASSERT(state->numkeys < state->maxkeyvals);
983 1074
 1075 if (!state->skipfirst || state->numkeys > 0) {
 1076 state->keys[state->numkeys].qk_idtype = idtype;
 1077 state->keys[state->numkeys].qk_id = id;
 1078 state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
 1079 state->numkeys++;
 1080 }
 1081 if (state->numkeys < state->maxkeyvals) {
 1082 state->keys[state->numkeys].qk_idtype = idtype;
 1083 state->keys[state->numkeys].qk_id = id;
 1084 state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_FILES;
 1085 state->numkeys++;
 1086 } else {
 1087 KASSERT(state->skiplast);
 1088 }
 1089 state->numids++;
 1090}
 1091
 1092/*
 1093 * Callback function for getting IDs. Update counting and call addid.
 1094 */
984static int 1095static int
985quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp, 1096q2cursor_getids_callback(struct ufsmount *ump, uint64_t *offp,
986 struct quota2_entry *q2ep, uint64_t off, void *v) 1097 struct quota2_entry *q2ep, uint64_t off, void *v)
987{ 1098{
988 struct getuids *gu = v; 1099 struct q2cursor_getids *gi = v;
989 uid_t *newuids; 1100 id_t id;
990 long newmax; 
991#ifdef FFS_EI 1101#ifdef FFS_EI
992 const int needswap = UFS_MPNEEDSWAP(ump); 1102 const int needswap = UFS_MPNEEDSWAP(ump);
993#endif 1103#endif
994 1104
995 if (gu->skip > 0) { 1105 if (gi->skipped < gi->skip) {
996 gu->skip--; 1106 gi->skipped++;
997 return 0; 1107 return 0;
998 } 1108 }
999 if (gu->nuids == gu->maxuids) { 1109 id = ufs_rw32(q2ep->q2e_uid, needswap);
1000 newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t); 1110 q2cursor_addid(gi->state, gi->idtype, id);
1001 newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]), 1111 gi->new_skip++;
1002 M_TEMP, M_WAITOK); 1112 if (gi->state->numids >= gi->state->maxids) {
1003 if (newuids == NULL) { 1113 /* got enough ids, stop now */
1004 return ENOMEM; 
1005 } 
1006 gu->uids = newuids; 
1007 gu->maxuids = newmax; 
1008 } 
1009 gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap); 
1010 gu->nuids++; 
1011 gu->seen++; 
1012 if (gu->nuids == gu->limit) { 
1013 return Q2WL_ABORT; 1114 return Q2WL_ABORT;
1014 } 1115 }
1015 return 0; 1116 return 0;
1016} 1117}
1017 1118
1018int 1119/*
1019quota2_handle_cmd_cursorget(struct ufsmount *ump, struct quotakcursor *qkc, 1120 * Fill in a batch of quotakeys by scanning one or more hash chains.
1020 struct quotakey *keys, struct quotaval *vals, unsigned maxreturn, 1121 */
1021 unsigned *ret) 1122static int
 1123q2cursor_getkeys(struct ufsmount *ump, int idtype, struct ufsq2_cursor *cursor,
 1124 struct q2cursor_state *state,
 1125 int *hashsize_ret, struct quota2_entry *default_q2e_ret)
1022{ 1126{
1023 int error; 1127 const int needswap = UFS_MPNEEDSWAP(ump);
1024 struct ufsq2_cursor *cursor; 
1025 struct quota2_header *q2h; 
1026 struct quota2_entry q2e; 
1027 struct buf *hbp; 1128 struct buf *hbp;
1028 uint64_t offset; 1129 struct quota2_header *q2h;
1029 int idtype; 
1030 int can_switch_idtype; 
1031 int i, j; 
1032 int quota2_hash_size; 1130 int quota2_hash_size;
1033 const int needswap = UFS_MPNEEDSWAP(ump); 1131 struct q2cursor_getids gi;
1034 struct getuids gu; 1132 uint64_t offset;
1035 long excess; 1133 int error;
1036 id_t junkid; 
1037 struct quotaval qv; 
1038 unsigned num, maxnum; 
1039 int skipfirst, skiplast; 
1040 int numreturn; 
1041 
1042 cursor = Q2CURSOR(qkc); 
1043 error = q2cursor_check(cursor); 
1044 if (error) { 
1045 return error; 
1046 } 
1047 
1048 CTASSERT(USRQUOTA == QUOTA_IDTYPE_USER); 
1049 CTASSERT(GRPQUOTA == QUOTA_IDTYPE_GROUP); 
1050 
1051 if (cursor->q2c_users_done == 0 && 
1052 ump->um_quotas[USRQUOTA] == NULLVP) { 
1053 cursor->q2c_users_done = 1; 
1054 } 
1055 if (cursor->q2c_groups_done == 0 && 
1056 ump->um_quotas[GRPQUOTA] == NULLVP) { 
1057 cursor->q2c_groups_done = 1; 
1058 } 
1059 
1060restart: 
1061 
1062 if (cursor->q2c_users_done == 0) { 
1063 idtype = QUOTA_IDTYPE_USER; 
1064 can_switch_idtype = 1; 
1065 } else if (cursor->q2c_groups_done == 0) { 
1066 idtype = QUOTA_IDTYPE_GROUP; 
1067 can_switch_idtype = 0; 
1068 } else { 
1069 /* nothing more to do, return 0 */ 
1070 *ret = 0; 
1071 return 0; 
1072 } 
1073 
1074 KASSERT(ump->um_quotas[idtype] != NULLVP); 
1075 1134
1076 numreturn = 0; 1135 /*
 1136 * Read the header block.
 1137 */
1077 1138
1078 mutex_enter(&dqlock); 1139 mutex_enter(&dqlock);
1079 error = getq2h(ump, idtype, &hbp, &q2h, 0); 1140 error = getq2h(ump, idtype, &hbp, &q2h, 0);
1080 if (error) { 1141 if (error) {
1081 mutex_exit(&dqlock); 1142 mutex_exit(&dqlock);
1082 return error; 1143 return error;
1083 } 1144 }
1084 1145
1085 if (cursor->q2c_defaults_done == 0) { 
1086 quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); 
1087 if (cursor->q2c_blocks_done == 0) { 
1088 q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); 
1089 keys[numreturn].qk_idtype = idtype; 
1090 keys[numreturn].qk_id = QUOTA_DEFAULTID; 
1091 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_BLOCKS; 
1092 vals[numreturn++] = qv; 
1093 cursor->q2c_blocks_done = 1; 
1094 } 
1095 if (cursor->q2c_blocks_done == 1) { 
1096 q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); 
1097 keys[numreturn].qk_idtype = idtype; 
1098 keys[numreturn].qk_id = QUOTA_DEFAULTID; 
1099 keys[numreturn].qk_objtype = QUOTA_OBJTYPE_FILES; 
1100 vals[numreturn++] = qv; 
1101 cursor->q2c_blocks_done = 0; 
1102 cursor->q2c_defaults_done = 1; 
1103 } 
1104 } 
1105 
1106 /* 
1107 * we can't directly get entries as we can't walk the list 
1108 * with qdlock and grab dq_interlock to read the entries 
1109 * at the same time. So just walk the lists to build a list of uid, 
1110 * and then read entries for these uids 
1111 */ 
1112 memset(&gu, 0, sizeof(gu)); 
1113 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); 
1114 
1115 /* if the table size has changed, make the caller start over */ 1146 /* if the table size has changed, make the caller start over */
 1147 quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
1116 if (cursor->q2c_hashsize == 0) { 1148 if (cursor->q2c_hashsize == 0) {
1117 cursor->q2c_hashsize = quota2_hash_size; 1149 cursor->q2c_hashsize = quota2_hash_size;
1118 } else if (cursor->q2c_hashsize != quota2_hash_size) { 1150 } else if (cursor->q2c_hashsize != quota2_hash_size) {
1119 error = EDEADLK; 1151 error = EDEADLK;
1120 goto fail; 1152 goto scanfail;
1121 } 1153 }
1122 1154
1123 gu.skip = cursor->q2c_uidpos; 1155 /* grab the entry with the default values out of the header */
1124 gu.seen = 0; 1156 quota2_ufs_rwq2e(&q2h->q2h_defentry, default_q2e_ret, needswap);
1125 gu.limit = (maxreturn - numreturn) / 2; 1157
1126 if (gu.limit == 0 && (maxreturn - numreturn) > 0) { 1158 /* If we haven't done the defaults yet, that goes first. */
1127 gu.limit = 1; 1159 if (cursor->q2c_defaults_done == 0) {
1128 } 1160 q2cursor_addid(state, idtype, QUOTA_DEFAULTID);
1129 for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { 1161 cursor->q2c_defaults_done = 1;
1130 offset = q2h->q2h_entries[i]; 1162 }
1131 gu.seen = 0; 1163
1132 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, 1164 gi.state = state;
1133 quota2_getuids_callback); 1165 gi.idtype = idtype;
1134 if (error && error != Q2WL_ABORT) { 1166
1135 if (gu.uids != NULL) 1167 while (state->numids < state->maxids) {
1136 free(gu.uids, M_TEMP); 1168 if (cursor->q2c_hashpos >= quota2_hash_size) {
 1169 /* nothing more left */
1137 break; 1170 break;
1138 } 1171 }
 1172
 1173 /* scan this hash chain */
 1174 gi.skip = cursor->q2c_uidpos;
 1175 gi.new_skip = gi.skip;
 1176 gi.skipped = 0;
 1177 offset = q2h->q2h_entries[cursor->q2c_hashpos];
 1178
 1179 error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gi,
 1180 q2cursor_getids_callback);
1139 if (error == Q2WL_ABORT) { 1181 if (error == Q2WL_ABORT) {
1140 /* got enough uids for now */ 1182 /* callback stopped before reading whole chain */
 1183 cursor->q2c_uidpos = gi.new_skip;
 1184 /* not an error */
1141 error = 0; 1185 error = 0;
1142 } 1186 } else if (error) {
1143 if (gu.nuids > gu.limit) { 
1144 excess = gu.nuids - gu.limit; 
1145 KASSERT(excess < gu.seen); 
1146 gu.seen -= excess; 
1147 gu.nuids -= excess; 
1148 } 
1149 if (gu.nuids == gu.limit) { 
1150 break; 1187 break;
 1188 } else {
 1189 /* read whole chain, advance to next */
 1190 cursor->q2c_uidpos = 0;
 1191 cursor->q2c_hashpos++;
1151 } 1192 }
1152 } 1193 }
1153 KASSERT(gu.nuids <= gu.limit); 
1154 cursor->q2c_hashpos = i; 
1155 cursor->q2c_uidpos = gu.seen; 
1156 1194
1157fail: 1195scanfail:
1158 mutex_exit(&dqlock); 1196 mutex_exit(&dqlock);
1159 brelse(hbp, 0); 1197 brelse(hbp, 0);
1160 if (error) 1198 if (error)
1161 return error; 1199 return error;
1162 1200
1163 if (gu.nuids == 0) { 1201 *hashsize_ret = quota2_hash_size;
1164 if (idtype == QUOTA_IDTYPE_USER) 1202 return 0;
1165 cursor->q2c_users_done = 1; 1203}
1166 else 1204
1167 cursor->q2c_groups_done = 1; 1205/*
1168 if (can_switch_idtype) { 1206 * Fetch the quotavals for the quotakeys.
1169 goto restart; 1207 */
 1208static int
 1209q2cursor_getvals(struct ufsmount *ump, struct q2cursor_state *state,
 1210 const struct quota2_entry *default_q2e)
 1211{
 1212 int hasid;
 1213 id_t loadedid, id;
 1214 unsigned pos;
 1215 struct quota2_entry q2e;
 1216 int objtype;
 1217 int error;
 1218
 1219 hasid = 0;
 1220 loadedid = 0;
 1221 for (pos = 0; pos < state->numkeys; pos++) {
 1222 id = state->keys[pos].qk_id;
 1223 if (!hasid || id != loadedid) {
 1224 hasid = 1;
 1225 loadedid = id;
 1226 if (id == QUOTA_DEFAULTID) {
 1227 q2e = *default_q2e;
 1228 } else {
 1229 error = quota2_fetch_q2e(ump,
 1230 &state->keys[pos],
 1231 &q2e);
 1232 if (error == ENOENT) {
 1233 /* something changed - start over */
 1234 error = EDEADLK;
 1235 }
 1236 if (error) {
 1237 return error;
 1238 }
 1239 }
1170 } 1240 }
 1241
 1242
 1243 objtype = state->keys[pos].qk_objtype;
 1244 KASSERT(objtype >= 0 && objtype < N_QL);
 1245 q2val_to_quotaval(&q2e.q2e_val[objtype], &state->vals[pos]);
1171 } 1246 }
1172 1247
1173 maxnum = gu.nuids*2; 1248 return 0;
 1249}
 1250
 1251/*
 1252 * Handle cursorget.
 1253 *
 1254 * We can't just read keys and values directly, because we can't walk
 1255 * the list with qdlock and grab dq_interlock to read the entries at
 1256 * the same time. So we're going to do two passes: one to figure out
 1257 * which IDs we want and fill in the keys, and then a second to use
 1258 * the keys to fetch the values.
 1259 */
 1260int
 1261quota2_handle_cmd_cursorget(struct ufsmount *ump, struct quotakcursor *qkc,
 1262 struct quotakey *keys, struct quotaval *vals, unsigned maxreturn,
 1263 unsigned *ret)
 1264{
 1265 int error;
 1266 struct ufsq2_cursor *cursor;
 1267 struct ufsq2_cursor newcursor;
 1268 struct q2cursor_state state;
 1269 struct quota2_entry default_q2e;
 1270 int idtype;
 1271 int quota2_hash_size;
1174 1272
1175 /* 1273 /*
1176 * If we've already sent back the blocks value for the first id, 1274 * Convert and validate the cursor.
1177 * don't send it again (skipfirst). 
1178 * 
1179 * If we have an odd number of available result slots and we 
1180 * aren't going to skip the first result entry, we need to 
1181 * leave off the last result entry (skiplast). 
1182 */ 1275 */
1183 skipfirst = (cursor->q2c_blocks_done != 0); 1276 cursor = Q2CURSOR(qkc);
1184 skiplast = skipfirst == 0 && (maxreturn < maxnum); 1277 error = q2cursor_check(cursor);
1185 num = 0; 1278 if (error) {
1186 for (j = 0; j < gu.nuids; j++) { 1279 return error;
1187 error = quota2_result_add_q2e(ump, idtype, 1280 }
1188 gu.uids[j], keys, vals, numreturn + j*2, 1281
1189 j == 0 && skipfirst, 1282 /*
1190 j + 1 == gu.nuids && skiplast); 1283 * Make sure our on-disk codes match the values of the
1191 if (error == ENOENT) 1284 * FS-independent ones. This avoids the need for explicit
1192 continue; 1285 * conversion (which would be a NOP anyway and thus easily
1193 if (error) 1286 * left out or called in the wrong places...)
1194 break; 1287 */
1195 if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) { 1288 CTASSERT(QUOTA_IDTYPE_USER == USRQUOTA);
1196 num += 1; 1289 CTASSERT(QUOTA_IDTYPE_GROUP == GRPQUOTA);
 1290 CTASSERT(QUOTA_OBJTYPE_BLOCKS == QL_BLOCK);
 1291 CTASSERT(QUOTA_OBJTYPE_FILES == QL_FILE);
 1292
 1293 /*
 1294 * If some of the idtypes aren't configured/enabled, arrange
 1295 * to skip over them.
 1296 */
 1297 if (cursor->q2c_users_done == 0 &&
 1298 ump->um_quotas[USRQUOTA] == NULLVP) {
 1299 cursor->q2c_users_done = 1;
 1300 }
 1301 if (cursor->q2c_groups_done == 0 &&
 1302 ump->um_quotas[GRPQUOTA] == NULLVP) {
 1303 cursor->q2c_groups_done = 1;
 1304 }
 1305
 1306 /* Loop over, potentially, both idtypes */
 1307 while (1) {
 1308
 1309 /* Choose id type */
 1310 error = q2cursor_pickidtype(cursor, &idtype);
 1311 if (error == EAGAIN) {
 1312 /* nothing more to do, return 0 */
 1313 *ret = 0;
 1314 return 0;
 1315 }
 1316 KASSERT(ump->um_quotas[idtype] != NULLVP);
 1317
 1318 /*
 1319 * Initialize the per-call iteration state. Copy the
 1320 * cursor state so we can update it in place but back
 1321 * out on error.
 1322 */
 1323 q2cursor_initstate(&state, keys, vals, maxreturn,
 1324 cursor->q2c_blocks_done);
 1325 newcursor = *cursor;
 1326
 1327 /* Assign keys */
 1328 error = q2cursor_getkeys(ump, idtype, &newcursor, &state,
 1329 &quota2_hash_size, &default_q2e);
 1330 if (error) {
 1331 return error;
 1332 }
 1333
 1334 /* Now fill in the values. */
 1335 error = q2cursor_getvals(ump, &state, &default_q2e);
 1336 if (error) {
 1337 return error;
 1338 }
 1339
 1340 /*
 1341 * Now that we aren't going to fail and lose what we
 1342 * did so far, we can update the cursor state.
 1343 */
 1344
 1345 if (newcursor.q2c_hashpos >= quota2_hash_size) {
 1346 if (idtype == QUOTA_IDTYPE_USER)
 1347 cursor->q2c_users_done = 1;
 1348 else
 1349 cursor->q2c_groups_done = 1;
 1350
 1351 /* start over on another id type */
 1352 cursor->q2c_hashsize = 0;
 1353 cursor->q2c_defaults_done = 0;
 1354 cursor->q2c_hashpos = 0;
 1355 cursor->q2c_uidpos = 0;
 1356 cursor->q2c_blocks_done = 0;
1197 } else { 1357 } else {
1198 num += 2; 1358 *cursor = newcursor;
 1359 cursor->q2c_blocks_done = state.skiplast;
1199 } 1360 }
1200 } 
1201 numreturn += num; 
1202 *ret = numreturn; 
1203 1361
1204 cursor->q2c_blocks_done = skiplast; 1362 /*
 1363 * If we have something to return, return it.
 1364 * Otherwise, continue to the other idtype, if any,
 1365 * and only return zero at end of iteration.
 1366 */
 1367 if (state.numkeys > 0) {
 1368 break;
 1369 }
 1370 }
1205 1371
1206 if (gu.uids != NULL) 1372 *ret = state.numkeys;
1207 free(gu.uids, M_TEMP); 1373 return 0;
1208 return error; 
1209} 1374}
1210 1375
1211int 1376int
1212quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) 1377quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc)
1213{ 1378{
1214 struct ufsq2_cursor *cursor; 1379 struct ufsq2_cursor *cursor;
1215 1380
1216 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); 1381 CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space));
1217 cursor = Q2CURSOR(qkc); 1382 cursor = Q2CURSOR(qkc);
1218 1383
1219 cursor->q2c_magic = Q2C_MAGIC; 1384 cursor->q2c_magic = Q2C_MAGIC;
1220 cursor->q2c_hashsize = 0; 1385 cursor->q2c_hashsize = 0;
1221 1386