Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/bouyer-quota2]: src/sys/ufs/ufs Describe how the on-disk structures are ...



details:   https://anonhg.NetBSD.org/src/rev/63e2b7fceb10
branches:  bouyer-quota2
changeset: 761080:63e2b7fceb10
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Sat Jan 29 23:22:00 2011 +0000

description:
Describe how the on-disk structures are protected from concurent access,
and try to implement it.

diffstat:

 sys/ufs/ufs/quota2.h     |    8 +-
 sys/ufs/ufs/ufs_quota.c  |    6 +-
 sys/ufs/ufs/ufs_quota2.c |  169 +++++++++++++++++++++++++++++++++-------------
 3 files changed, 129 insertions(+), 54 deletions(-)

diffs (truncated from 332 to 300 lines):

diff -r ed36305134d5 -r 63e2b7fceb10 sys/ufs/ufs/quota2.h
--- a/sys/ufs/ufs/quota2.h      Sat Jan 29 17:42:37 2011 +0000
+++ b/sys/ufs/ufs/quota2.h      Sat Jan 29 23:22:00 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: quota2.h,v 1.1.2.3 2011/01/28 18:36:06 bouyer Exp $ */
+/* $NetBSD: quota2.h,v 1.1.2.4 2011/01/29 23:22:00 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -41,6 +41,12 @@
  * superblock
  */
 
+/*
+ * The quota file is comprised of 2 parts, the header and the entries.
+ * The header contains global informations, and head of list of quota entries.
+ * A quota entry can either be in the free list, or one of the hash lists.
+ */
+
 /* description of a block or inode quota */
 struct quota2_val {
        uint64_t q2v_hardlimit; /* absolute limit */
diff -r ed36305134d5 -r 63e2b7fceb10 sys/ufs/ufs/ufs_quota.c
--- a/sys/ufs/ufs/ufs_quota.c   Sat Jan 29 17:42:37 2011 +0000
+++ b/sys/ufs/ufs/ufs_quota.c   Sat Jan 29 23:22:00 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 bouyer Exp $        */
+/*     $NetBSD: ufs_quota.c,v 1.68.4.3 2011/01/29 23:22:00 bouyer Exp $        */
 
 /*
  * Copyright (c) 1982, 1986, 1990, 1993, 1995
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.2 2011/01/21 16:58:06 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.68.4.3 2011/01/29 23:22:00 bouyer Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -264,9 +264,7 @@
 
 #ifdef QUOTA2
        if (ump->um_flags & UFS_QUOTA2) {
-               mutex_enter(&dqlock);
                error = quota2_handle_cmd_getall(ump, type, replies);
-               mutex_exit(&dqlock);
        } else
 #endif
                panic("quota_handle_cmd_getall: no support ?");
diff -r ed36305134d5 -r 63e2b7fceb10 sys/ufs/ufs/ufs_quota2.c
--- a/sys/ufs/ufs/ufs_quota2.c  Sat Jan 29 17:42:37 2011 +0000
+++ b/sys/ufs/ufs/ufs_quota2.c  Sat Jan 29 23:22:00 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ufs_quota2.c,v 1.1.2.3 2011/01/28 18:36:06 bouyer Exp $ */
+/* $NetBSD: ufs_quota2.c,v 1.1.2.4 2011/01/29 23:22:00 bouyer Exp $ */
 /*-
   * Copyright (c) 2010 Manuel Bouyer
   * All rights reserved.
@@ -28,12 +28,13 @@
   */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.3 2011/01/28 18:36:06 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.1.2.4 2011/01/29 23:22:00 bouyer 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>
@@ -52,6 +53,16 @@
 #include <ufs/ufs/ufs_wapbl.h>
 #include <ufs/ufs/quota2_prop.h>
 
+/*
+ * LOCKING:
+ * Data in the entries are protected by the associated struct dquot's
+ * dq_interlock (this means we can't read or change a quota entry without
+ * grabing a dquot for it).
+ * The header and lists (including pointers in the data entries, and q2e_uid)
+ * are protected by the global dqlock.
+ * the locking order is dq_interlock -> dqlock
+ */
+
 static int getinoquota2(struct inode *, int, struct buf **,
     struct quota2_entry **);
 static int getq2h(struct ufsmount *, int, struct buf **,
@@ -71,6 +82,7 @@
        struct buf *bp;
        struct quota2_header *q2h;
 
+       KASSERT(mutex_owned(&dqlock));
        error = bread(ump->um_quotas[type], 0, ump->umq2_bsize,
            ump->um_cred[type], flags, &bp);
        if (error)
@@ -214,6 +226,7 @@
        u_long hash_mask;
        const int needswap = UFS_MPNEEDSWAP(ump);
 
+       KASSERT(mutex_owned(&dqlock));
        error = getq2h(ump, type, &hbp, &q2h, B_MODIFY);
        if (error)
                return error;
@@ -318,8 +331,10 @@
                                continue;
                        }
                        /* need to alloc a new on-disk quot */
+                       mutex_enter(&dqlock);
                        error = quota2_q2ealloc(ump, i, ino_ids[i], dq,
                            &bpp[i], &q2ep[i]);
+                       mutex_exit(&dqlock);
                        if (error)
                                return error;
                } else {
@@ -394,14 +409,51 @@
        return quota2_check(ip, Q2V_FILE, change, cred, flags);
 }
 
+static int
+quota2_array_add_q2e(struct ufsmount *ump, int type,
+    int id, prop_array_t replies)
+{
+       struct dquot *dq;
+       int error;
+       struct quota2_entry *q2ep, q2e;
+       struct buf  *bp;
+       const int needswap = UFS_MPNEEDSWAP(ump);
+       prop_dictionary_t dict;
+
+       error = dqget(NULLVP, id, ump, type, &dq);
+       if (error)
+               return error;
+
+       if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
+               dqrele(NULLVP, dq);
+               return ENOENT;
+       }
+       error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff,
+           &bp, &q2ep, 0);
+       if (error) {
+               dqrele(NULLVP, dq);
+               return error;
+       }
+       mutex_enter(&dq->dq_interlock);
+       quota2_ufs_rwq2e(q2ep, &q2e, needswap);
+       mutex_exit(&dq->dq_interlock);
+       dqrele(NULLVP, dq);
+       brelse(bp, 0);
+       dict = q2etoprop(&q2e, 0);
+       if (dict == NULL)
+               return ENOMEM;
+       if (!prop_array_add_and_rel(replies, dict))
+               return ENOMEM;
+       return 0;
+}
+
 int
 quota2_handle_cmd_get(struct ufsmount *ump, int type, int id,
     int defaultq, prop_array_t replies)
 {
-       struct dquot *dq;
        int error;
        struct quota2_header *q2h;
-       struct quota2_entry *q2ep, q2e;
+       struct quota2_entry q2e;
        struct buf *bp;
        prop_dictionary_t dict;
        const int needswap = UFS_MPNEEDSWAP(ump);
@@ -415,53 +467,46 @@
                        mutex_exit(&dqlock);
                        return error;
                }
-               q2ep = &q2h->q2h_defentry;
-       } else {
-               error = dqget(NULLVP, id, ump, type, &dq);
-
-               if (error)
-                       return error;
-
-               if (dq->dq2_lblkno == 0 && dq->dq2_blkoff == 0) {
-                       dqrele(NULLVP, dq);
-                       return ENOENT;
-               }
-               error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff,
-                   &bp, &q2ep, 0);
-               if (error)
-                       return error;
-       }
-       quota2_ufs_rwq2e(q2ep, &q2e, needswap);
-       dict = q2etoprop(&q2e, defaultq);
-       if (defaultq)
+               quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
                mutex_exit(&dqlock);
-       else
-               dqrele(NULLVP, dq);
-       brelse(bp, 0);
-       if (dict == NULL)
-               return ENOMEM;
+               brelse(bp, 0);
+               dict = q2etoprop(&q2e, defaultq);
+               if (dict == NULL)
+                       return ENOMEM;
+               if (!prop_array_add_and_rel(replies, dict))
+                       return ENOMEM;
+       } else
+               error = quota2_array_add_q2e(ump, type, id, replies);
        
-       if (!prop_array_add_and_rel(replies, dict)) {
-               error = ENOMEM;
-       }
        return error;
 }
 
+struct getuids {
+       long nuids; /* number of uids in array */
+       long size;  /* size of array */
+       uid_t *uids; /* array of uids, dynamically allocated */
+};
 
 static int
-quota2_getall_callback(struct ufsmount *ump, uint64_t *offp,
+quota2_getuids_callback(struct ufsmount *ump, uint64_t *offp,
     struct quota2_entry *q2ep, uint64_t off, void *v)
 {
-       prop_array_t replies = v;
-       prop_dictionary_t dict;
+       struct getuids *gu = v;
+       uid_t *newuids;
        const int needswap = UFS_MPNEEDSWAP(ump);
-       struct quota2_entry q2e;
 
-       quota2_ufs_rwq2e(q2ep, &q2e, needswap);
-       dict = q2etoprop(&q2e, 0);      
-       if (!prop_array_add_and_rel(replies, dict)) {
-               return ENOMEM;
+       if (gu->nuids == gu->size) {
+               newuids = realloc(gu->uids, gu->size + PAGE_SIZE, M_TEMP,
+                   M_WAITOK);
+               if (newuids == NULL) {
+                       free(gu->uids, M_TEMP);
+                       return ENOMEM;
+               }
+               gu->uids = newuids;
+               gu->size += (PAGE_SIZE / sizeof(uid_t));
        }
+       gu->uids[gu->nuids] = ufs_rw32(q2ep->q2e_uid, needswap);
+       gu->nuids++;
        return 0;
 }
 
@@ -470,34 +515,59 @@
 {
        int error;
        struct quota2_header *q2h;
-       struct quota2_entry q2e;
+       struct quota2_entry  q2e;
        struct buf *hbp;
        prop_dictionary_t dict;
        uint64_t offset;
-       int i;
+       int i, j;
        int quota2_hash_size;
        const int needswap = UFS_MPNEEDSWAP(ump);
+       struct getuids gu;
 
        if (ump->um_quotas[type] == NULLVP)
                return ENODEV;
+       mutex_enter(&dqlock);
        error = getq2h(ump, type, &hbp, &q2h, 0);
-       if (error)
+       if (error) {
+               mutex_exit(&dqlock);
                return error;
+       }
        quota2_ufs_rwq2e(&q2h->q2h_defentry, &q2e, needswap);
        dict = q2etoprop(&q2e, 1);
        if (!prop_array_add_and_rel(replies, dict)) {
-               brelse(hbp, 0);
-               return ENOMEM;
+               error = ENOMEM;
+               goto error_bp;
        }
+       /*
+        * we can't directly get entries as we can't walk the list
+        * with qdlock and grab dq_interlock to read the entries
+        * at the same time. So just walk the lists to build a list of uid,
+        * and then read entries for these uids
+        */
+       memset(&gu, 0, sizeof(gu));
        quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap);
        for (i = 0; i < quota2_hash_size ; i++) {
-               offset = q2h->q2h_entries[i], needswap;
-               error = quota2_walk_list(ump, hbp, type, &offset, 0, replies,
-                   quota2_getall_callback);
-               if (error)
+               offset = q2h->q2h_entries[i];



Home | Main Index | Thread Index | Old Index