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