Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/ufs/ufs Clean up quota2 cursoring, as promised earlier.
details: https://anonhg.NetBSD.org/src/rev/551f589f9ef0
branches: trunk
changeset: 773214:551f589f9ef0
user: dholland <dholland%NetBSD.org@localhost>
date: Sun Jan 29 07:21:00 2012 +0000
description:
Clean up quota2 cursoring, as promised earlier.
diffstat:
sys/ufs/ufs/ufs_quota2.c | 593 ++++++++++++++++++++++++++++++----------------
1 files changed, 379 insertions(+), 214 deletions(-)
diffs (truncated from 721 to 300 lines):
diff -r 8df68715d1a1 -r 551f589f9ef0 sys/ufs/ufs/ufs_quota2.c
--- a/sys/ufs/ufs/ufs_quota2.c Sun Jan 29 07:20:27 2012 +0000
+++ b/sys/ufs/ufs/ufs_quota2.c Sun Jan 29 07:21:00 2012 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_quota2.c,v 1.29 2012/01/29 07:20:27 dholland Exp $ */
+/* $NetBSD: ufs_quota2.c,v 1.30 2012/01/29 07:21:00 dholland Exp $ */
/*-
* Copyright (c) 2010 Manuel Bouyer
* All rights reserved.
@@ -26,13 +26,12 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.29 2012/01/29 07:20:27 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.30 2012/01/29 07:21:00 dholland Exp $");
#include <sys/buf.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
#include <sys/namei.h>
#include <sys/file.h>
#include <sys/proc.h>
@@ -794,17 +793,16 @@
}
static int
-quota2_result_add_q2e(struct ufsmount *ump, int idtype,
- int id, struct quotakey *keys, struct quotaval *vals, unsigned pos,
- int skipfirst, int skiplast)
+quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
+ struct quota2_entry *ret)
{
struct dquot *dq;
int error;
- struct quota2_entry *q2ep, q2e;
- struct buf *bp;
+ struct quota2_entry *q2ep;
+ struct buf *bp;
const int needswap = UFS_MPNEEDSWAP(ump);
- error = dqget(NULLVP, id, ump, idtype, &dq);
+ error = dqget(NULLVP, qk->qk_id, ump, qk->qk_idtype, &dq);
if (error)
return error;
@@ -814,39 +812,23 @@
dqrele(NULLVP, dq);
return ENOENT;
}
- error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff,
+ error = getq2e(ump, qk->qk_idtype, dq->dq2_lblkno, dq->dq2_blkoff,
&bp, &q2ep, 0);
if (error) {
mutex_exit(&dq->dq_interlock);
dqrele(NULLVP, dq);
return error;
}
- quota2_ufs_rwq2e(q2ep, &q2e, needswap);
+ quota2_ufs_rwq2e(q2ep, ret, needswap);
brelse(bp, 0);
mutex_exit(&dq->dq_interlock);
dqrele(NULLVP, dq);
- if (skipfirst == 0) {
- 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) {
- 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++;
- }
-
return 0;
}
static int
-quota2_fetch_q2e(struct ufsmount *ump, const struct quotakey *qk,
+quota2_fetch_quotaval(struct ufsmount *ump, const struct quotakey *qk,
struct quotaval *ret)
{
struct dquot *dq;
@@ -923,11 +905,17 @@
qk->qk_objtype, ret);
(void)id2;
} else
- error = quota2_fetch_q2e(ump, qk, ret);
+ error = quota2_fetch_quotaval(ump, qk, ret);
return error;
}
+/*
+ * Cursor structure we used.
+ *
+ * This will get stored in userland between calls so we must not assume
+ * it isn't arbitrarily corrupted.
+ */
struct ufsq2_cursor {
uint32_t q2c_magic; /* magic number */
int q2c_hashsize; /* size of hash table at last go */
@@ -940,10 +928,54 @@
int q2c_blocks_done; /* true if we've returned the blocks value */
};
+/*
+ * State of a single cursorget call, or at least the part of it that
+ * needs to be passed around.
+ */
+struct q2cursor_state {
+ /* data return pointers */
+ struct quotakey *keys;
+ struct quotaval *vals;
+
+ /* key/value counters */
+ unsigned maxkeyvals;
+ unsigned numkeys; /* number of keys assigned */
+
+ /* ID to key/value conversion state */
+ int skipfirst; /* if true skip first key/value */
+ int skiplast; /* if true skip last key/value */
+
+ /* ID counters */
+ unsigned maxids; /* maximum number of IDs to handle */
+ unsigned numids; /* number of IDs handled */
+};
+
+/*
+ * Additional structure for getids callback.
+ */
+struct q2cursor_getids {
+ struct q2cursor_state *state;
+ int idtype;
+ unsigned skip; /* number of ids to skip over */
+ unsigned new_skip; /* number of ids to skip over next time */
+ unsigned skipped; /* number skipped so far */
+};
+
+/*
+ * Cursor-related functions
+ */
+
+/* magic number */
#define Q2C_MAGIC (0xbeebe111)
+/* extract cursor from caller form */
#define Q2CURSOR(qkc) ((struct ufsq2_cursor *)&qkc->u.qkc_space[0])
+/*
+ * Check that a cursor we're handed is something like valid. If
+ * someone munges it and it still passes these checks, they'll get
+ * partial or odd results back but won't break anything.
+ */
static int
q2cursor_check(struct ufsq2_cursor *cursor)
{
@@ -972,49 +1004,259 @@
return 0;
}
-struct getuids {
- long nuids; /* number of uids in array */
- long maxuids; /* number of uids allocated */
- uid_t *uids; /* array of uids, dynamically allocated */
- long skip;
- long seen;
- long limit;
-};
+/*
+ * Set up the q2cursor state.
+ */
+static void
+q2cursor_initstate(struct q2cursor_state *state, struct quotakey *keys,
+ struct quotaval *vals, unsigned maxkeyvals, int blocks_done)
+{
+ state->keys = keys;
+ state->vals = vals;
+
+ state->maxkeyvals = maxkeyvals;
+ state->numkeys = 0;
+
+ /*
+ * For each ID there are two quotavals to return. If the
+ * maximum number of entries to return is odd, we might want
+ * to skip the first quotaval of the first ID, or the last
+ * quotaval of the last ID, but not both. So the number of IDs
+ * we want is (up to) half the number of return slots we have,
+ * rounded up.
+ */
+
+ state->maxids = (state->maxkeyvals + 1) / 2;
+ state->numids = 0;
+ if (state->maxkeyvals % 2) {
+ if (blocks_done) {
+ state->skipfirst = 1;
+ state->skiplast = 0;
+ } else {
+ state->skipfirst = 0;
+ state->skiplast = 1;
+ }
+ } else {
+ state->skipfirst = 0;
+ state->skiplast = 0;
+ }
+}
+/*
+ * Choose which idtype we're going to work on. If doing a full
+ * iteration, we do users first, then groups, but either might be
+ * disabled or marked to skip via cursorsetidtype(), so don't make
+ * silly assumptions.
+ */
static int
-quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
+q2cursor_pickidtype(struct ufsq2_cursor *cursor, int *idtype_ret)
+{
+ if (cursor->q2c_users_done == 0) {
+ *idtype_ret = QUOTA_IDTYPE_USER;
+ } else if (cursor->q2c_groups_done == 0) {
+ *idtype_ret = QUOTA_IDTYPE_GROUP;
+ } else {
+ return EAGAIN;
+ }
+ return 0;
+}
+
+/*
+ * Add an ID to the current state. Sets up either one or two keys to
+ * refer to it, depending on whether it's first/last and the setting
+ * of skipfirst. (skiplast does not need to be explicitly tested)
+ */
+static void
+q2cursor_addid(struct q2cursor_state *state, int idtype, id_t id)
+{
+ KASSERT(state->numids < state->maxids);
+ KASSERT(state->numkeys < state->maxkeyvals);
+
+ if (!state->skipfirst || state->numkeys > 0) {
+ state->keys[state->numkeys].qk_idtype = idtype;
+ state->keys[state->numkeys].qk_id = id;
+ state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_BLOCKS;
+ state->numkeys++;
+ }
+ if (state->numkeys < state->maxkeyvals) {
+ state->keys[state->numkeys].qk_idtype = idtype;
+ state->keys[state->numkeys].qk_id = id;
+ state->keys[state->numkeys].qk_objtype = QUOTA_OBJTYPE_FILES;
+ state->numkeys++;
+ } else {
+ KASSERT(state->skiplast);
+ }
+ state->numids++;
+}
+
+/*
+ * Callback function for getting IDs. Update counting and call addid.
+ */
+static int
+q2cursor_getids_callback(struct ufsmount *ump, uint64_t *offp,
struct quota2_entry *q2ep, uint64_t off, void *v)
{
- struct getuids *gu = v;
- uid_t *newuids;
- long newmax;
+ struct q2cursor_getids *gi = v;
+ id_t id;
#ifdef FFS_EI
const int needswap = UFS_MPNEEDSWAP(ump);
#endif
- if (gu->skip > 0) {
- gu->skip--;
+ if (gi->skipped < gi->skip) {
+ gi->skipped++;
return 0;
}
- if (gu->nuids == gu->maxuids) {
- newmax = gu->maxuids + PAGE_SIZE / sizeof(uid_t);
- newuids = realloc(gu->uids, newmax * sizeof(gu->uids[0]),
- M_TEMP, M_WAITOK);
- if (newuids == NULL) {
- return ENOMEM;
- }
- gu->uids = newuids;
- gu->maxuids = newmax;
- }
- gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
- gu->nuids++;
- gu->seen++;
- if (gu->nuids == gu->limit) {
+ id = ufs_rw32(q2ep->q2e_uid, needswap);
+ q2cursor_addid(gi->state, gi->idtype, id);
Home |
Main Index |
Thread Index |
Old Index