Module Name: src Committed By: dholland Date: Sun Jan 29 07:02:07 UTC 2012
Modified Files: src/sys/kern: vfs_quotactl.c src/sys/sys: quotactl.h src/sys/ufs/ufs: ufs_quota.c ufs_quota.h ufs_quota2.c Log Message: Hack QUOTACTL_GETALL to return results without using proplib. (this interface is abusive and is going to be cleaned up in the immediate future) Note: this change requires a kernel version bump. To generate a diff of this commit: cvs rdiff -u -r1.22 -r1.23 src/sys/kern/vfs_quotactl.c cvs rdiff -u -r1.20 -r1.21 src/sys/sys/quotactl.h cvs rdiff -u -r1.94 -r1.95 src/sys/ufs/ufs/ufs_quota.c cvs rdiff -u -r1.16 -r1.17 src/sys/ufs/ufs/ufs_quota.h cvs rdiff -u -r1.17 -r1.18 src/sys/ufs/ufs/ufs_quota2.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/vfs_quotactl.c diff -u src/sys/kern/vfs_quotactl.c:1.22 src/sys/kern/vfs_quotactl.c:1.23 --- src/sys/kern/vfs_quotactl.c:1.22 Sun Jan 29 07:00:39 2012 +++ src/sys/kern/vfs_quotactl.c Sun Jan 29 07:02:06 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_quotactl.c,v 1.22 2012/01/29 07:00:39 dholland Exp $ */ +/* $NetBSD: vfs_quotactl.c,v 1.23 2012/01/29 07:02:06 dholland Exp $ */ /* * Copyright (c) 1991, 1993, 1994 @@ -80,8 +80,9 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.22 2012/01/29 07:00:39 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_quotactl.c,v 1.23 2012/01/29 07:02:06 dholland Exp $"); +#include <sys/malloc.h> /* XXX: temporary */ #include <sys/mount.h> #include <sys/quota.h> #include <sys/quotactl.h> @@ -437,14 +438,84 @@ err: return error; } +static prop_dictionary_t +vfs_quotactl_getall_makereply(id_t id, int def, + const struct quotaval *blocks, + const struct quotaval *files) +{ +#define INITQVNAMES_ALL { \ + QUOTADICT_LIMIT_HARD, \ + QUOTADICT_LIMIT_SOFT, \ + QUOTADICT_LIMIT_USAGE, \ + QUOTADICT_LIMIT_ETIME, \ + QUOTADICT_LIMIT_GTIME \ + } +#define N_QV 5 + + const char *val_names[] = INITQVNAMES_ALL; + uint64_t vals[N_QV]; + prop_dictionary_t dict1 = prop_dictionary_create(); + prop_dictionary_t dict2; + + if (dict1 == NULL) + return NULL; + + if (def) { + if (!prop_dictionary_set_cstring_nocopy(dict1, "id", + "default")) { + goto err; + } + } else { + if (!prop_dictionary_set_uint32(dict1, "id", id)) { + goto err; + } + } + + vals[0] = blocks->qv_hardlimit; + vals[1] = blocks->qv_softlimit; + vals[2] = blocks->qv_usage; + vals[3] = blocks->qv_expiretime; + vals[4] = blocks->qv_grace; + dict2 = limits64toprop(vals, val_names, N_QV); + if (dict2 == NULL) + goto err; + if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_BLOCK, dict2)) + goto err; + + + vals[0] = files->qv_hardlimit; + vals[1] = files->qv_softlimit; + vals[2] = files->qv_usage; + vals[3] = files->qv_expiretime; + vals[4] = files->qv_grace; + dict2 = limits64toprop(vals, val_names, N_QV); + if (dict2 == NULL) + goto err; + if (!prop_dictionary_set_and_rel(dict1, QUOTADICT_LTYPE_FILE, dict2)) + goto err; + + return dict1; + +err: + prop_object_release(dict1); + return NULL; +} + static int vfs_quotactl_getall(struct mount *mp, prop_dictionary_t cmddict, int q2type, prop_array_t datas) { struct quotakcursor cursor; + struct quota_getall_result result; struct vfs_quotactl_args args; + prop_array_t replies; + prop_dictionary_t dict; + unsigned i; int error, error2; + int skip = 0; + + KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); args.qc_type = QCT_CURSOROPEN; args.u.cursoropen.qc_cursor = &cursor; @@ -453,11 +524,75 @@ vfs_quotactl_getall(struct mount *mp, return error; } + result.qr_keys = NULL; + result.qr_vals = NULL; + args.qc_type = QCT_GETALL; args.u.getall.qc_cursor = &cursor; args.u.getall.qc_idtype = q2type; - args.u.getall.qc_cmddict = cmddict; + args.u.getall.qc_result = &result; error = VFS_QUOTACTL(mp, QUOTACTL_GETALL, &args); + /* + * XXX this is bogus but up until now *all* errors + * from inside quotactl_getall were suppressed by the + * dispatching code in ufs_quota.c. Fixing that causes + * repquota to break in an undesirable way; this is a + * workaround. + */ + if (error == ENODEV || error == ENXIO) { + skip = 1; + error = 0; + } + if (error) { + goto err; + } + + replies = prop_array_create(); + if (replies == NULL) { + error = ENOMEM; + goto err; + } + + if (skip) { + goto skip; + } + + dict = vfs_quotactl_getall_makereply(0, 1, &result.qr_defblocks, + &result.qr_deffiles); + if (!prop_array_add_and_rel(replies, dict)) { + error = ENOMEM; + goto err; + } + + for (i = 0; i < result.qr_num; i += 2) { + dict = vfs_quotactl_getall_makereply(result.qr_keys[i].qk_id,0, + &result.qr_vals[i], + &result.qr_vals[i+1]); + if (dict == NULL) { + error = ENOMEM; + goto err; + } + if (!prop_array_add_and_rel(replies, dict)) { + error = ENOMEM; + goto err; + } + } + +skip: + + if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { + error = ENOMEM; + goto err; + } + + error = 0; + err: + if (result.qr_keys) { + free(result.qr_keys, M_TEMP); + } + if (result.qr_vals) { + free(result.qr_vals, M_TEMP); + } args.qc_type = QCT_CURSORCLOSE; args.u.cursorclose.qc_cursor = &cursor; Index: src/sys/sys/quotactl.h diff -u src/sys/sys/quotactl.h:1.20 src/sys/sys/quotactl.h:1.21 --- src/sys/sys/quotactl.h:1.20 Sun Jan 29 07:00:39 2012 +++ src/sys/sys/quotactl.h Sun Jan 29 07:02:06 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: quotactl.h,v 1.20 2012/01/29 07:00:39 dholland Exp $ */ +/* $NetBSD: quotactl.h,v 1.21 2012/01/29 07:02:06 dholland Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -37,6 +37,8 @@ * use the <quota.h> API instead. */ +#include <sys/quota.h> + /* * Semi-opaque structure for cursors. This holds the cursor state in * userland; the size is exposed only to libquota, not to client code, @@ -104,7 +106,13 @@ struct vfs_quotactl_args { struct { struct quotakcursor *qc_cursor; int qc_idtype; - prop_dictionary_t qc_cmddict; + struct quota_getall_result { + struct quotaval qr_defblocks; + struct quotaval qr_deffiles; + struct quotakey *qr_keys; + struct quotaval *qr_vals; + unsigned qr_num; + } *qc_result; } getall; } u; }; Index: src/sys/ufs/ufs/ufs_quota.c diff -u src/sys/ufs/ufs/ufs_quota.c:1.94 src/sys/ufs/ufs/ufs_quota.c:1.95 --- src/sys/ufs/ufs/ufs_quota.c:1.94 Sun Jan 29 07:00:39 2012 +++ src/sys/ufs/ufs/ufs_quota.c Sun Jan 29 07:02:06 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_quota.c,v 1.94 2012/01/29 07:00:39 dholland Exp $ */ +/* $NetBSD: ufs_quota.c,v 1.95 2012/01/29 07:02:06 dholland 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.94 2012/01/29 07:00:39 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ufs_quota.c,v 1.95 2012/01/29 07:02:06 dholland Exp $"); #if defined(_KERNEL_OPT) #include "opt_quota.h" @@ -368,19 +368,16 @@ static int quota_handle_cmd_getall(struct mount *mp, struct lwp *l, struct vfs_quotactl_args *args) { - prop_array_t replies; struct ufsmount *ump = VFSTOUFS(mp); struct quotakcursor *cursor; int idtype; - prop_dictionary_t cmddict; + struct quota_getall_result *result; int error; KASSERT(args->qc_type == QCT_GETALL); cursor = args->u.getall.qc_cursor; idtype = args->u.getall.qc_idtype; - cmddict = args->u.getall.qc_cmddict; - - KASSERT(prop_object_type(cmddict) == PROP_TYPE_DICTIONARY); + result = args->u.getall.qc_result; if ((ump->um_flags & UFS_QUOTA2) == 0) return EOPNOTSUPP; @@ -390,21 +387,13 @@ quota_handle_cmd_getall(struct mount *mp if (error) return error; - replies = prop_array_create(); - if (replies == NULL) - return ENOMEM; - #ifdef QUOTA2 if (ump->um_flags & UFS_QUOTA2) { - error = quota2_handle_cmd_getall(ump, cursor, idtype, replies); + error = quota2_handle_cmd_getall(ump, cursor, idtype, result); } else #endif panic("quota_handle_cmd_getall: no support ?"); - if (!prop_dictionary_set_and_rel(cmddict, "data", replies)) { - error = ENOMEM; - } else { - error = 0; - } + return error; } Index: src/sys/ufs/ufs/ufs_quota.h diff -u src/sys/ufs/ufs/ufs_quota.h:1.16 src/sys/ufs/ufs/ufs_quota.h:1.17 --- src/sys/ufs/ufs/ufs_quota.h:1.16 Sun Jan 29 07:00:40 2012 +++ src/sys/ufs/ufs/ufs_quota.h Sun Jan 29 07:02:06 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_quota.h,v 1.16 2012/01/29 07:00:40 dholland Exp $ */ +/* $NetBSD: ufs_quota.h,v 1.17 2012/01/29 07:02:06 dholland Exp $ */ /* * Copyright (c) 1982, 1986, 1990, 1993, 1995 @@ -37,6 +37,7 @@ #include <ufs/ufs/quota2.h> struct quotakcursor; /* from <sys/quotactl.h> */ +struct quota_getall_result; /* ditto, but: XXX temporary */ /* link to this quota in the quota inode (for QUOTA2) */ @@ -132,7 +133,7 @@ int quota2_handle_cmd_put(struct ufsmoun const struct quotaval *); int quota2_handle_cmd_delete(struct ufsmount *, const struct quotakey *); int quota2_handle_cmd_getall(struct ufsmount *, struct quotakcursor *, int, - prop_array_t); + struct quota_getall_result *); int quota2_handle_cmd_cursoropen(struct ufsmount *, struct quotakcursor *); int quota2_handle_cmd_cursorclose(struct ufsmount *, struct quotakcursor *); int q2sync(struct mount *); Index: src/sys/ufs/ufs/ufs_quota2.c diff -u src/sys/ufs/ufs/ufs_quota2.c:1.17 src/sys/ufs/ufs/ufs_quota2.c:1.18 --- src/sys/ufs/ufs/ufs_quota2.c:1.17 Sun Jan 29 07:00:40 2012 +++ src/sys/ufs/ufs/ufs_quota2.c Sun Jan 29 07:02:06 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: ufs_quota2.c,v 1.17 2012/01/29 07:00:40 dholland Exp $ */ +/* $NetBSD: ufs_quota2.c,v 1.18 2012/01/29 07:02:06 dholland Exp $ */ /*- * Copyright (c) 2010 Manuel Bouyer * All rights reserved. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.17 2012/01/29 07:00:40 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ufs_quota2.c,v 1.18 2012/01/29 07:02:06 dholland Exp $"); #include <sys/buf.h> #include <sys/param.h> @@ -75,7 +75,9 @@ static int quota2_walk_list(struct ufsmo int (*func)(struct ufsmount *, uint64_t *, struct quota2_entry *, uint64_t, void *)); +#if 0 static prop_dictionary_t q2etoprop(struct quota2_entry *, int); +#endif static const char *limnames[] = INITQLNAMES; @@ -92,6 +94,7 @@ quota2_dict_update_q2e_limits(int objtyp q2e->q2e_val[objtype].q2v_grace = val->qv_grace; } +#if 0 static prop_dictionary_t q2etoprop(struct quota2_entry *q2e, int def) { @@ -127,6 +130,7 @@ err: prop_object_release(dict1); return NULL; } +#endif /* * Convert internal representation to FS-independent representation. @@ -824,17 +828,16 @@ out_dq: } static int -quota2_array_add_q2e(struct ufsmount *ump, int type, - int id, prop_array_t replies) +quota2_result_add_q2e(struct ufsmount *ump, int idtype, + int id, struct quota_getall_result *result, unsigned pos) { 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); + error = dqget(NULLVP, id, ump, idtype, &dq); if (error) return error; @@ -844,7 +847,7 @@ quota2_array_add_q2e(struct ufsmount *um dqrele(NULLVP, dq); return ENOENT; } - error = getq2e(ump, type, dq->dq2_lblkno, dq->dq2_blkoff, + error = getq2e(ump, idtype, dq->dq2_lblkno, dq->dq2_blkoff, &bp, &q2ep, 0); if (error) { mutex_exit(&dq->dq_interlock); @@ -856,11 +859,16 @@ quota2_array_add_q2e(struct ufsmount *um mutex_exit(&dq->dq_interlock); dqrele(NULLVP, dq); - dict = q2etoprop(&q2e, 0); - if (dict == NULL) - return ENOMEM; - if (!prop_array_add_and_rel(replies, dict)) - return ENOMEM; + result->qr_keys[pos].qk_idtype = idtype; + result->qr_keys[pos].qk_objtype = QUOTA_OBJTYPE_BLOCKS; + q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos].qk_id, + QL_BLOCK, &result->qr_vals[pos]); + + result->qr_keys[pos+1].qk_idtype = idtype; + result->qr_keys[pos+1].qk_objtype = QUOTA_OBJTYPE_FILES; + q2e_to_quotaval(&q2e, 0, &result->qr_keys[pos+1].qk_id, + QL_FILE, &result->qr_vals[pos+1]); + return 0; } @@ -989,39 +997,39 @@ quota2_getuids_callback(struct ufsmount int quota2_handle_cmd_getall(struct ufsmount *ump, struct quotakcursor *qkc, - int type, prop_array_t replies) + int idtype, struct quota_getall_result *result) { int error; struct ufsq2_cursor *cursor; struct quota2_header *q2h; struct quota2_entry q2e; struct buf *hbp; - prop_dictionary_t dict; uint64_t offset; int i, j; int quota2_hash_size; const int needswap = UFS_MPNEEDSWAP(ump); struct getuids gu; + id_t junkid; + unsigned num, maxnum; cursor = Q2CURSOR(qkc); if (cursor->q2c_magic != Q2C_MAGIC) { return EINVAL; } - if (ump->um_quotas[type] == NULLVP) + if (ump->um_quotas[idtype] == NULLVP) return ENODEV; + mutex_enter(&dqlock); - error = getq2h(ump, type, &hbp, &q2h, 0); + error = getq2h(ump, idtype, &hbp, &q2h, 0); 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)) { - error = ENOMEM; - goto error_bp; - } + q2e_to_quotaval(&q2e, 1, &junkid, QL_BLOCK, &result->qr_defblocks); + q2e_to_quotaval(&q2e, 1, &junkid, QL_FILE, &result->qr_deffiles); + /* * we can't directly get entries as we can't walk the list * with qdlock and grab dq_interlock to read the entries @@ -1032,7 +1040,7 @@ quota2_handle_cmd_getall(struct ufsmount quota2_hash_size = ufs_rw16(q2h->q2h_hash_size, needswap); for (i = 0; i < quota2_hash_size ; i++) { offset = q2h->q2h_entries[i]; - error = quota2_walk_list(ump, hbp, type, &offset, 0, &gu, + error = quota2_walk_list(ump, hbp, idtype, &offset, 0, &gu, quota2_getuids_callback); if (error) { if (gu.uids != NULL) @@ -1040,17 +1048,30 @@ quota2_handle_cmd_getall(struct ufsmount break; } } -error_bp: + mutex_exit(&dqlock); brelse(hbp, 0); if (error) return error; + + maxnum = gu.nuids*2; + result->qr_keys = malloc(maxnum * sizeof(result->qr_keys[0]), + M_TEMP, M_WAITOK); + result->qr_vals = malloc(maxnum * sizeof(result->qr_vals[0]), + M_TEMP, M_WAITOK); + + num = 0; for (j = 0; j < gu.nuids; j++) { - error = quota2_array_add_q2e(ump, type, - gu.uids[j], replies); - if (error && error != ENOENT) + error = quota2_result_add_q2e(ump, idtype, + gu.uids[j], result, j*2); + if (error == ENOENT) + continue; + if (error) break; + num += 2; } + result->qr_num = num; + free(gu.uids, M_TEMP); return error; }