| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ufs_quota2.c,v 1.21 2012/01/29 07:05:12 dholland Exp $ */ | | 1 | /* $NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 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.21 2012/01/29 07:05:12 dholland Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.22 2012/01/29 07:06:02 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> |
| @@ -1045,139 +1045,178 @@ quota2_handle_cmd_getall(struct ufsmount | | | @@ -1045,139 +1045,178 @@ quota2_handle_cmd_getall(struct ufsmount |
1045 | int idtype, struct quota_getall_result *result) | | 1045 | int idtype, struct quota_getall_result *result) |
1046 | { | | 1046 | { |
1047 | int error; | | 1047 | int error; |
1048 | struct ufsq2_cursor *cursor; | | 1048 | struct ufsq2_cursor *cursor; |
1049 | struct quota2_header *q2h; | | 1049 | struct quota2_header *q2h; |
1050 | struct quota2_entry q2e; | | 1050 | struct quota2_entry q2e; |
1051 | struct buf *hbp; | | 1051 | struct buf *hbp; |
1052 | uint64_t offset; | | 1052 | uint64_t offset; |
1053 | int i, j; | | 1053 | int i, j; |
1054 | int quota2_hash_size; | | 1054 | int quota2_hash_size; |
1055 | const int needswap = UFS_MPNEEDSWAP(ump); | | 1055 | const int needswap = UFS_MPNEEDSWAP(ump); |
1056 | struct getuids gu; | | 1056 | struct getuids gu; |
1057 | id_t junkid; | | 1057 | id_t junkid; |
1058 | struct quotaval qv; | | 1058 | struct quotakey bkey, fkey; |
| | | 1059 | struct quotaval bval, fval; |
| | | 1060 | int dobval = 0, dofval = 0; |
1059 | unsigned num, maxnum; | | 1061 | unsigned num, maxnum; |
1060 | int skipfirst, skiplast; | | 1062 | int skipfirst, skiplast; |
| | | 1063 | int maxreturn, numreturn; |
1061 | | | 1064 | |
1062 | cursor = Q2CURSOR(qkc); | | 1065 | cursor = Q2CURSOR(qkc); |
1063 | error = q2cursor_check(cursor); | | 1066 | error = q2cursor_check(cursor); |
1064 | if (error) { | | 1067 | if (error) { |
1065 | return error; | | 1068 | return error; |
1066 | } | | 1069 | } |
1067 | | | 1070 | |
1068 | if (ump->um_quotas[idtype] == NULLVP) { | | 1071 | if (ump->um_quotas[idtype] == NULLVP) { |
1069 | return ENODEV; | | 1072 | return ENODEV; |
1070 | } | | 1073 | } |
1071 | | | 1074 | |
| | | 1075 | maxreturn = result->qr_max; |
| | | 1076 | numreturn = 0; |
| | | 1077 | |
1072 | mutex_enter(&dqlock); | | 1078 | mutex_enter(&dqlock); |
1073 | error = getq2h(ump, idtype, &hbp, &q2h, 0); | | 1079 | error = getq2h(ump, idtype, &hbp, &q2h, 0); |
1074 | if (error) { | | 1080 | if (error) { |
1075 | mutex_exit(&dqlock); | | 1081 | mutex_exit(&dqlock); |
1076 | return error; | | 1082 | return error; |
1077 | } | | 1083 | } |
1078 | | | 1084 | |
1079 | if (cursor->q2c_defaults_done == 0) { | | 1085 | if (cursor->q2c_defaults_done == 0) { |
1080 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); | | 1086 | quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap); |
1081 | if (cursor->q2c_blocks_done == 0) { | | 1087 | if (cursor->q2c_blocks_done == 0) { |
1082 | q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &qv); | | 1088 | q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &bval); |
1083 | result->qr_defblocks = qv; | | 1089 | bkey.qk_idtype = idtype; |
| | | 1090 | bkey.qk_id = QUOTA_DEFAULTID; |
| | | 1091 | bkey.qk_objtype = QUOTA_OBJTYPE_BLOCKS; |
| | | 1092 | dobval = 1; |
1084 | cursor->q2c_blocks_done = 1; | | 1093 | cursor->q2c_blocks_done = 1; |
1085 | } | | 1094 | } |
1086 | if (cursor->q2c_blocks_done == 1) { | | 1095 | if (cursor->q2c_blocks_done == 1) { |
1087 | q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &qv); | | 1096 | q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &fval); |
1088 | result->qr_deffiles = qv; | | 1097 | fkey.qk_idtype = idtype; |
| | | 1098 | fkey.qk_id = QUOTA_DEFAULTID; |
| | | 1099 | fkey.qk_objtype = QUOTA_OBJTYPE_FILES; |
| | | 1100 | dofval = 1; |
1089 | cursor->q2c_blocks_done = 0; | | 1101 | cursor->q2c_blocks_done = 0; |
1090 | cursor->q2c_defaults_done = 1; | | 1102 | cursor->q2c_defaults_done = 1; |
1091 | } | | 1103 | } |
1092 | } | | 1104 | } |
1093 | | | 1105 | |
1094 | /* | | 1106 | /* |
1095 | * we can't directly get entries as we can't walk the list | | 1107 | * we can't directly get entries as we can't walk the list |
1096 | * with qdlock and grab dq_interlock to read the entries | | 1108 | * with qdlock and grab dq_interlock to read the entries |
1097 | * at the same time. So just walk the lists to build a list of uid, | | 1109 | * at the same time. So just walk the lists to build a list of uid, |
1098 | * and then read entries for these uids | | 1110 | * and then read entries for these uids |
1099 | */ | | 1111 | */ |
1100 | memset(&gu, 0, sizeof(gu)); | | 1112 | memset(&gu, 0, sizeof(gu)); |
1101 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); | | 1113 | quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); |
1102 | | | 1114 | |
1103 | /* if the table size has changed, make the caller start over */ | | 1115 | /* if the table size has changed, make the caller start over */ |
1104 | if (cursor->q2c_hashsize == 0) { | | 1116 | if (cursor->q2c_hashsize == 0) { |
1105 | cursor->q2c_hashsize = quota2_hash_size; | | 1117 | cursor->q2c_hashsize = quota2_hash_size; |
1106 | } else if (cursor->q2c_hashsize != quota2_hash_size) { | | 1118 | } else if (cursor->q2c_hashsize != quota2_hash_size) { |
1107 | error = EDEADLK; | | 1119 | error = EDEADLK; |
1108 | goto fail; | | 1120 | goto fail; |
1109 | } | | 1121 | } |
1110 | | | 1122 | |
1111 | gu.skip = cursor->q2c_uidpos; | | 1123 | gu.skip = cursor->q2c_uidpos; |
1112 | gu.seen = 0; | | 1124 | gu.seen = 0; |
1113 | gu.limit = result->qr_max / 2; | | 1125 | gu.limit = (maxreturn - numreturn) / 2; |
1114 | if (gu.limit == 0 && result->qr_max > 0) { | | 1126 | if (gu.limit == 0 && (maxreturn - numreturn) > 0) { |
1115 | gu.limit = 1; | | 1127 | gu.limit = 1; |
1116 | } | | 1128 | } |
| | | 1129 | if (dobval && gu.limit > 0) |
| | | 1130 | gu.limit--; |
| | | 1131 | if (dofval && gu.limit > 0) |
| | | 1132 | gu.limit--; |
1117 | for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { | | 1133 | for (i = cursor->q2c_hashpos; i < quota2_hash_size ; i++) { |
1118 | offset = q2h->q2h_entries[i]; | | 1134 | offset = q2h->q2h_entries[i]; |
1119 | gu.seen = 0; | | 1135 | gu.seen = 0; |
1120 | error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, | | 1136 | error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, |
1121 | quota2_getuids_callback); | | 1137 | quota2_getuids_callback); |
1122 | if (error == Q2WL_ABORT) { | | 1138 | if (error == Q2WL_ABORT) { |
1123 | /* got enough uids for now */ | | 1139 | /* got enough uids for now */ |
1124 | error = 0; | | 1140 | error = 0; |
1125 | break; | | 1141 | break; |
1126 | } | | 1142 | } |
1127 | if (error) { | | 1143 | if (error) { |
1128 | if (gu.uids != NULL) | | 1144 | if (gu.uids != NULL) |
1129 | free(gu.uids, M_TEMP); | | 1145 | free(gu.uids, M_TEMP); |
1130 | break; | | 1146 | break; |
1131 | } | | 1147 | } |
1132 | } | | 1148 | } |
1133 | cursor->q2c_hashpos = i; | | 1149 | cursor->q2c_hashpos = i; |
1134 | cursor->q2c_uidpos = gu.seen; | | 1150 | cursor->q2c_uidpos = gu.seen; |
1135 | | | 1151 | |
1136 | fail: | | 1152 | fail: |
1137 | mutex_exit(&dqlock); | | 1153 | mutex_exit(&dqlock); |
1138 | brelse(hbp, 0); | | 1154 | brelse(hbp, 0); |
1139 | if (error) | | 1155 | if (error) |
1140 | return error; | | 1156 | return error; |
1141 | | | 1157 | |
1142 | maxnum = gu.nuids*2; | | 1158 | maxnum = gu.nuids*2; |
| | | 1159 | if (dobval) |
| | | 1160 | maxnum++; |
| | | 1161 | if (dofval) |
| | | 1162 | maxnum++; |
1143 | result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), | | 1163 | result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), |
1144 | M_TEMP, M_WAITOK); | | 1164 | M_TEMP, M_WAITOK); |
1145 | result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), | | 1165 | result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), |
1146 | M_TEMP, M_WAITOK); | | 1166 | M_TEMP, M_WAITOK); |
1147 | | | 1167 | |
| | | 1168 | if (dobval && numreturn < maxreturn) { |
| | | 1169 | result->qr_keys[numreturn] = bkey; |
| | | 1170 | result->qr_vals[numreturn] = bval; |
| | | 1171 | numreturn++; |
| | | 1172 | } |
| | | 1173 | if (dofval && numreturn < maxreturn) { |
| | | 1174 | result->qr_keys[numreturn] = fkey; |
| | | 1175 | result->qr_vals[numreturn] = fval; |
| | | 1176 | numreturn++; |
| | | 1177 | } |
| | | 1178 | if (numreturn == maxreturn) { |
| | | 1179 | return 0; |
| | | 1180 | } |
| | | 1181 | |
1148 | /* | | 1182 | /* |
1149 | * If we've already sent back the blocks value for the first id, | | 1183 | * If we've already sent back the blocks value for the first id, |
1150 | * don't send it again (skipfirst). | | 1184 | * don't send it again (skipfirst). |
1151 | * | | 1185 | * |
1152 | * If we have an odd number of available result slots and we | | 1186 | * 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 | | 1187 | * aren't going to skip the first result entry, we need to |
1154 | * leave off the last result entry (skiplast). | | 1188 | * leave off the last result entry (skiplast). |
1155 | */ | | 1189 | */ |
1156 | skipfirst = (cursor->q2c_blocks_done != 0); | | 1190 | skipfirst = (cursor->q2c_blocks_done != 0); |
1157 | skiplast = skipfirst == 0 && (result->qr_max < maxnum); | | 1191 | skiplast = skipfirst == 0 && (result->qr_max < maxnum); |
1158 | num = 0; | | 1192 | num = 0; |
1159 | for (j = 0; j < gu.nuids; j++) { | | 1193 | for (j = 0; j < gu.nuids; j++) { |
1160 | error = quota2_result_add_q2e(ump, idtype, | | 1194 | error = quota2_result_add_q2e(ump, idtype, |
1161 | gu.uids[j], result, j*2, | | 1195 | gu.uids[j], result, numreturn + j*2, |
1162 | j == 0 && skipfirst, | | 1196 | j == 0 && skipfirst, |
1163 | j + 1 == gu.nuids && skiplast); | | 1197 | j + 1 == gu.nuids && skiplast); |
1164 | if (error == ENOENT) | | 1198 | if (error == ENOENT) |
1165 | continue; | | 1199 | continue; |
1166 | if (error) | | 1200 | if (error) |
1167 | break; | | 1201 | break; |
1168 | num += 2; | | 1202 | if ((j == 0 && skipfirst) || (j + 1 == gu.nuids && skiplast)) { |
| | | 1203 | num += 1; |
| | | 1204 | } else { |
| | | 1205 | num += 2; |
| | | 1206 | } |
1169 | } | | 1207 | } |
1170 | result->qr_num = num; | | 1208 | numreturn += num; |
| | | 1209 | result->qr_num = numreturn; |
1171 | | | 1210 | |
1172 | cursor->q2c_blocks_done = skiplast; | | 1211 | cursor->q2c_blocks_done = skiplast; |
1173 | | | 1212 | |
1174 | free(gu.uids, M_TEMP); | | 1213 | free(gu.uids, M_TEMP); |
1175 | return error; | | 1214 | return error; |
1176 | } | | 1215 | } |
1177 | | | 1216 | |
1178 | int | | 1217 | int |
1179 | quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) | | 1218 | quota2_handle_cmd_cursoropen(struct ufsmount *ump, struct quotakcursor *qkc) |
1180 | { | | 1219 | { |
1181 | struct ufsq2_cursor *cursor; | | 1220 | struct ufsq2_cursor *cursor; |
1182 | | | 1221 | |
1183 | CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); | | 1222 | CTASSERT(sizeof(*cursor) <= sizeof(qkc->u.qkc_space)); |