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