X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fquota%2Flproc_quota.c;h=ecee4a9bfb869a0181f8cf6b92b427224b5d5a2a;hb=792be6ca54810b04bdc4fd4f61e4b05fc701e587;hp=ce0f8ba9a8c2207b460e101bef6a9ee6c8c61f27;hpb=498ee35323fcacf829f4e77c91e7700cb3660111;p=fs%2Flustre-release.git diff --git a/lustre/quota/lproc_quota.c b/lustre/quota/lproc_quota.c index ce0f8ba..ecee4a9 100644 --- a/lustre/quota/lproc_quota.c +++ b/lustre/quota/lproc_quota.c @@ -1,6 +1,4 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: - * +/* * GPL HEADER START * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -16,22 +14,18 @@ * in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * version 2 along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA * * GPL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved + * Copyright (c) 2011, 2015, Intel Corporation. * Use is subject to license terms. - */ -/* - * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. + * + * Author: Johann Lombardi + * Author: Niu Yawei */ #define DEBUG_SUBSYSTEM S_LQUOTA @@ -40,646 +34,326 @@ #include #include #include -#include - -#include "quota_internal.h" - -#ifdef HAVE_QUOTA_SUPPORT - -#ifdef LPROCFS -int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_bunit_sz); -} -EXPORT_SYMBOL(lprocfs_quota_rd_bunit); - -int lprocfs_quota_wr_bunit(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val % QUOTABLOCK_SIZE || - val <= obd->u.obt.obt_qctxt.lqc_btune_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_bunit_sz = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_bunit); - -int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_btune_sz); -} -EXPORT_SYMBOL(lprocfs_quota_rd_btune); - -int lprocfs_quota_wr_btune(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE || - val >= obd->u.obt.obt_qctxt.lqc_bunit_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_btune_sz = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_btune); - -int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_iunit_sz); -} -EXPORT_SYMBOL(lprocfs_quota_rd_iunit); - -int lprocfs_quota_wr_iunit(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_iunit_sz = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_iunit); - -int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_itune_sz); -} -EXPORT_SYMBOL(lprocfs_quota_rd_itune); - -int lprocfs_quota_wr_itune(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val <= MIN_QLIMIT || - val >= obd->u.obt.obt_qctxt.lqc_iunit_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_itune_sz = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_itune); - -#define USER_QUOTA 1 -#define GROUP_QUOTA 2 - -#define MAX_STYPE_SIZE 5 - -int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - char stype[MAX_STYPE_SIZE + 1] = ""; - int oq_type; - struct obd_device_target *obt; - - LASSERT(obd != NULL); - - obt = &obd->u.obt; - - /* Collect the needed information */ - oq_type = obd->u.obt.obt_qctxt.lqc_flags; - - /* Transform the collected data into a user-readable string */ - if (oq_type & LQC_USRQUOTA_FLAG) - strcat(stype, "u"); - if (oq_type & LQC_GRPQUOTA_FLAG) - strcat(stype, "g"); - - strcat(stype, "3"); - - return snprintf(page, count, "%s\n", stype); -} -EXPORT_SYMBOL(lprocfs_quota_rd_type); - -static int auto_quota_on(struct obd_device *obd, int type, - struct super_block *sb, int is_master) -{ - struct obd_quotactl *oqctl; - struct lvfs_run_ctxt saved; - int rc = 0, rc1 = 0, id; - struct obd_device_target *obt = &obd->u.obt; - struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt; - struct mds_obd *mds = NULL; - ENTRY; - - LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA); - - OBD_ALLOC_PTR(oqctl); - if (!oqctl) - RETURN(-ENOMEM); - - down(&obt->obt_quotachecking); - id = UGQUOTA2LQC(type); - /* quota already turned on */ - if ((obt->obt_qctxt.lqc_flags & id) == id) - GOTO(out, rc); - - if (obt->obt_qctxt.lqc_immutable) { - LCONSOLE_ERROR("Failed to turn Quota on, immutable mode " - "(is SOM enabled?)\n"); - GOTO(out, rc = -ECANCELED); - } - - oqctl->qc_type = type; - oqctl->qc_cmd = Q_QUOTAON; - oqctl->qc_id = obt->obt_qfmt; - - push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); - - if (is_master) { - mds = &obd->u.mds; - down(&mds->mds_qonoff_sem); - /* turn on cluster wide quota */ - rc1 = mds_admin_quota_on(obd, oqctl); - if (rc1 && rc1 != -EALREADY) { - CDEBUG(rc1 == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable admin quota failed. rc=%d\n", rc1); - GOTO(out_ctxt, rc1); - } - } - - /* turn on local quota */ - rc = fsfilt_quotactl(obd, sb, oqctl); - if (!rc) { - obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type); - build_lqs(obd); - } else if (rc == -EBUSY && quota_is_on(qctxt, oqctl)) { - CWARN("mds local quota[%d] is on already\n", oqctl->qc_type); - rc = -EALREADY; - } else { - CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable local quota failed. rc=%d\n", rc); - if (rc1 == -EALREADY) { - oqctl->qc_cmd = Q_QUOTAOFF; - mds_admin_quota_off(obd, oqctl); - } - GOTO(out_ctxt, rc); - } - - EXIT; - -out_ctxt: - if (mds != NULL) - up(&mds->mds_qonoff_sem); - pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); - -out: - up(&obt->obt_quotachecking); - OBD_FREE_PTR(oqctl); - return rc; -} - -int lprocfs_quota_wr_type(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - struct obd_device_target *obt; - int type = 0, is_mds; - unsigned long i; - char stype[MAX_STYPE_SIZE + 1] = ""; - - LASSERT(obd != NULL); - - obt = &obd->u.obt; - - is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME); - - if (count > MAX_STYPE_SIZE) - return -EINVAL; - - if (copy_from_user(stype, buffer, count)) - return -EFAULT; - - for (i = 0 ; i < count ; i++) { - switch (stype[i]) { - case 'u' : - type |= USER_QUOTA; - break; - case 'g' : - type |= GROUP_QUOTA; - break; - case '1' : - case '2' : - CWARN("quota_type options 1 and 2 are obsolete, " - "they will be ignored\n"); - break; - case '3' : /* the only valid version spec, do nothing */ - default : /* just skip stray symbols like \n */ - break; - } - } - - if (type != 0) { - int rc = auto_quota_on(obd, type - 1, obt->obt_sb, is_mds); - - if (rc && rc != -EALREADY) - return rc; - } - - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_type); - -int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%d\n", - obd->u.obt.obt_qctxt.lqc_switch_seconds); -} -EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds); - -int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val <= 10) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_switch_seconds = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds); - -int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "%d\n", - obd->u.obt.obt_qctxt.lqc_sync_blk); -} -EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk); - -int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val < 0) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_sync_blk = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk); - -int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - return snprintf(page, count, "changing qunit size is %s\n", - obd->u.obt.obt_qctxt.lqc_switch_qs ? - "enabled" : "disabled"); -} -EXPORT_SYMBOL(lprocfs_quota_rd_switch_qs); - -int lprocfs_quota_wr_switch_qs(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val) - obd->u.obt.obt_qctxt.lqc_switch_qs = 1; - else - obd->u.obt.obt_qctxt.lqc_switch_qs = 0; - - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs); +#include "lquota_internal.h" + +#ifdef CONFIG_PROC_FS +/* structure allocated at seq_open time and release when seq_release is called. + * It is passed to seq_start/stop/next/show which can thus use the same lu_env + * to be used with the iterator API */ +struct lquota_procfs { + struct dt_object *lqp_obj; + struct lu_env lqp_env; + struct dt_it *lqp_it; + __u64 lqp_cookie; + __u64 lqp_first_cookie; +}; -int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off, - int count, int *eof, void *data) +/* global shared environment */ +static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos) { - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor); + struct lquota_procfs *lqp = p->private; + const struct dt_it_ops *iops; + struct dt_it *it; + loff_t offset = *pos; + int rc; + + LASSERT(lqp); + + if (offset == 0) + return SEQ_START_TOKEN; + + if (lqp->lqp_obj == NULL) + /* accounting not enabled. */ + return NULL; + + if (lqp->lqp_it == NULL) /* reach the end */ + return NULL; + + offset--; + /* move on to the the last processed entry */ + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = lqp->lqp_it; + rc = iops->load(&lqp->lqp_env, it, lqp->lqp_cookie); + if (rc == 0 && offset == 0) { + /* + * Iterator didn't find record with exactly the key requested. + * + * It is currently either + * + * - positioned above record with key less than + * requested - skip it. + * - or not positioned at all (is in IAM_IT_SKEWED + * state) - position it on the next item. + */ + rc = iops->next(&lqp->lqp_env, it); + if (rc != 0) + goto not_found; + lqp->lqp_cookie = iops->store(&lqp->lqp_env, it); + } else if (rc <= 0) { + goto not_found; + } + + /* The id entry could be deleted while iteration, and above ->load() + * operation will reset cursor to the first cookie (ldiskfs), we + * need to break in such situation. */ + if (offset == 0) + lqp->lqp_first_cookie = lqp->lqp_cookie; + else if (lqp->lqp_cookie == lqp->lqp_first_cookie) + goto not_found; + + return it; + +not_found: + iops->put(&lqp->lqp_env, it); + iops->fini(&lqp->lqp_env, it); + lqp->lqp_it = NULL; + return NULL; } -EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor); -int lprocfs_quota_wr_boundary_factor(struct file *file, const char *buffer, - unsigned long count, void *data) +static void lprocfs_quota_seq_stop(struct seq_file *p, void *v) { - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val < 2) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val; - return count; + struct lquota_procfs *lqp = p->private; + const struct dt_it_ops *iops; + struct dt_it *it; + + if (lqp->lqp_obj == NULL || v == NULL || v == SEQ_START_TOKEN) + return; + + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = (struct dt_it *)v; + /* if something wrong happened during ->seq_show, we need to release + * the iterator here */ + iops->put(&lqp->lqp_env, it); } -EXPORT_SYMBOL(lprocfs_quota_wr_boundary_factor); -int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off, - int count, int *eof, void *data) +static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos) { - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); + struct lquota_procfs *lqp = p->private; + const struct dt_it_ops *iops; + struct dt_it *it; + int rc; + LASSERT(lqp); - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_cqs_least_bunit); -} -EXPORT_SYMBOL(lprocfs_quota_rd_least_bunit); - -int lprocfs_quota_wr_least_bunit(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); + ++*pos; + if (lqp->lqp_obj == NULL) + return NULL; - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; + if (v == SEQ_START_TOKEN) + return lprocfs_quota_seq_start(p, pos); - if (val < PTLRPC_MAX_BRW_SIZE || - val >= obd->u.obt.obt_qctxt.lqc_bunit_sz) - return -EINVAL; + if (lqp->lqp_it == NULL) /* reach the end */ + return NULL; - obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit); + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = (struct dt_it *)v; -int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); + rc = iops->next(&lqp->lqp_env, it); + if (rc == 0) { + lqp->lqp_cookie = iops->store(&lqp->lqp_env, it); + return it; + } + if (rc < 0) + CERROR("%s: seq_next failed: rc = %d\n", + lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc); - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_cqs_least_iunit); + /* Reach the end or error */ + iops->put(&lqp->lqp_env, it); + iops->fini(&lqp->lqp_env, it); + lqp->lqp_it = NULL; + return NULL; } -EXPORT_SYMBOL(lprocfs_quota_rd_least_iunit); -int lprocfs_quota_wr_least_iunit(struct file *file, const char *buffer, - unsigned long count, void *data) +static inline const char *oid2name(__u32 oid) { - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val; - return count; + switch (oid) { + case ACCT_USER_OID: + return "usr_accounting"; + case ACCT_GROUP_OID: + return "grp_accounting"; + case ACCT_PROJECT_OID: + return "prj_accounting"; + break; + default: + return "unknown_accounting"; + } } -EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit); -int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off, - int count, int *eof, void *data) +/* + * Output example: + * + * usr_accounting: + * - id: 0 + * usage: { inodes: 209, kbytes: 2616 } + * - id: 840000038 + * usage: { inodes: 1, kbytes: 1048 } + */ +static int lprocfs_quota_seq_show(struct seq_file *p, void *v) { - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - - return snprintf(page, count, "%lu\n", - obd->u.obt.obt_qctxt.lqc_cqs_qs_factor); + struct lquota_procfs *lqp = p->private; + struct lquota_thread_info *qti = lquota_info(&lqp->lqp_env); + const struct dt_it_ops *iops; + struct dt_it *it; + struct dt_key *key; + struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec; + const struct lu_fid *fid; + int rc; + + LASSERT(lqp); + if (lqp->lqp_obj == NULL) { + seq_printf(p, "not supported\n"); + return 0; + } + + fid = lu_object_fid(&lqp->lqp_obj->do_lu); + + if (v == SEQ_START_TOKEN) { + if (fid_is_acct(fid)) { + seq_printf(p, "%s:\n", oid2name(fid_oid(fid))); + } else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) { + int poolid, rtype, qtype; + + rc = lquota_extract_fid(fid, &poolid, &rtype, &qtype); + if (rc) + return rc; + + seq_printf(p, "global_pool%d_%s_%s\n", poolid, + RES_NAME(rtype), qtype_name(qtype)); + } else if (fid_seq(fid) == FID_SEQ_LOCAL_NAME) { + /* global index copy object */ + seq_printf(p, "global_index_copy:\n"); + } else { + return -ENOTSUPP; + } + return 0; + } + + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = (struct dt_it *)v; + + key = iops->key(&lqp->lqp_env, it); + if (IS_ERR(key)) { + CERROR("%s: failed to get key: rc = %ld\n", + lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, + PTR_ERR(key)); + return PTR_ERR(key); + } + + rc = iops->rec(&lqp->lqp_env, it, rec, 0); + if (rc) { + CERROR("%s: failed to get rec: rc = %d\n", + lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc); + return rc; + } + + seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key)); + if (fid_is_acct(fid)) + seq_printf(p, " %-8s { inodes: %20llu, kbytes: %20llu }\n", "usage:", + ((struct lquota_acct_rec *)rec)->ispace, + toqb(((struct lquota_acct_rec *)rec)->bspace)); + else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB || + fid_seq(fid) == FID_SEQ_LOCAL_NAME) + seq_printf(p, " %-8s { hard: %20llu, soft: %20llu, granted: %20llu, time: %20llu }\n", + "limits:", + ((struct lquota_glb_rec *)rec)->qbr_hardlimit, + ((struct lquota_glb_rec *)rec)->qbr_softlimit, + ((struct lquota_glb_rec *)rec)->qbr_granted, + ((struct lquota_glb_rec *)rec)->qbr_time); + return 0; } -EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor); - -int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer, - unsigned long count, void *data) -{ - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - if (val < 2) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_qs_factor); - -struct lprocfs_vars lprocfs_quota_common_vars[] = { - { "quota_bunit_sz", lprocfs_quota_rd_bunit, - lprocfs_quota_wr_bunit, 0}, - { "quota_btune_sz", lprocfs_quota_rd_btune, - lprocfs_quota_wr_btune, 0}, - { "quota_iunit_sz", lprocfs_quota_rd_iunit, - lprocfs_quota_wr_iunit, 0}, - { "quota_itune_sz", lprocfs_quota_rd_itune, - lprocfs_quota_wr_itune, 0}, - { "quota_type", lprocfs_quota_rd_type, - lprocfs_quota_wr_type, 0}, - { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds, - lprocfs_quota_wr_switch_seconds, 0 }, - { "quota_sync_blk", lprocfs_quota_rd_sync_blk, - lprocfs_quota_wr_sync_blk, 0}, - { NULL } -}; - -struct lprocfs_vars lprocfs_quota_master_vars[] = { - { "quota_switch_qs", lprocfs_quota_rd_switch_qs, - lprocfs_quota_wr_switch_qs, 0 }, - { "quota_boundary_factor", lprocfs_quota_rd_boundary_factor, - lprocfs_quota_wr_boundary_factor, 0 }, - { "quota_least_bunit", lprocfs_quota_rd_least_bunit, - lprocfs_quota_wr_least_bunit, 0 }, - { "quota_least_iunit", lprocfs_quota_rd_least_iunit, - lprocfs_quota_wr_least_iunit, 0 }, - { "quota_qs_factor", lprocfs_quota_rd_qs_factor, - lprocfs_quota_wr_qs_factor, 0 }, - { NULL } +struct seq_operations lprocfs_quota_seq_sops = { + .start = lprocfs_quota_seq_start, + .stop = lprocfs_quota_seq_stop, + .next = lprocfs_quota_seq_next, + .show = lprocfs_quota_seq_show, }; -int lquota_proc_setup(struct obd_device *obd, int is_master) +static int lprocfs_quota_seq_open(struct inode *inode, struct file *file) { - struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt; - int rc = 0; - ENTRY; - - LASSERT(lquota_type_proc_dir && obd); - qctxt->lqc_proc_dir = lprocfs_register(obd->obd_name, - lquota_type_proc_dir, - lprocfs_quota_common_vars, obd); - if (IS_ERR(qctxt->lqc_proc_dir)) { - rc = PTR_ERR(qctxt->lqc_proc_dir); - CERROR("error %d setting up lprocfs for %s\n", rc, - obd->obd_name); - qctxt->lqc_proc_dir = NULL; - GOTO(out, rc); - } - - if (is_master) { - rc = lprocfs_add_vars(qctxt->lqc_proc_dir, - lprocfs_quota_master_vars, obd); - if (rc) { - CERROR("error %d setting up lprocfs for %s" - "(quota master)\n", rc, obd->obd_name); - GOTO(out_free_proc, rc); - } - } - - qctxt->lqc_stats = lprocfs_alloc_stats(LQUOTA_LAST_STAT - - LQUOTA_FIRST_STAT, 0); - if (!qctxt->lqc_stats) - GOTO(out_free_proc, rc = -ENOMEM); - - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_ACQ, - LPROCFS_CNTR_AVGMINMAX, "sync_acq_req", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_SYNC_REL, - LPROCFS_CNTR_AVGMINMAX, "sync_rel_req", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_ACQ, - LPROCFS_CNTR_AVGMINMAX, "async_acq_req", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ASYNC_REL, - LPROCFS_CNTR_AVGMINMAX, "async_rel_req", "us"); - - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_BLK, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_blk_quota(lquota_chkquota)", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_CHK_INO, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_ino_quota(lquota_chkquota)", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_BLK, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_blk_quota(lquota_pending_commit)", - "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_FOR_COMMIT_INO, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_ino_quota(lquota_pending_commit)", - "us"); - - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_BLK_QUOTA, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_pending_blk_quota_req" - "(qctxt_wait_pending_dqacq)", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_WAIT_PENDING_INO_QUOTA, - LPROCFS_CNTR_AVGMINMAX, - "wait_for_pending_ino_quota_req" - "(qctxt_wait_pending_dqacq)", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_BLK_QUOTA, - LPROCFS_CNTR_AVGMINMAX, - "nowait_for_pending_blk_quota_req" - "(qctxt_wait_pending_dqacq)", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_NOWAIT_PENDING_INO_QUOTA, - LPROCFS_CNTR_AVGMINMAX, - "nowait_for_pending_ino_quota_req" - "(qctxt_wait_pending_dqacq)", "us"); - - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_QUOTA_CTL, - LPROCFS_CNTR_AVGMINMAX, "quota_ctl", "us"); - lprocfs_counter_init(qctxt->lqc_stats, LQUOTA_ADJUST_QUNIT, - LPROCFS_CNTR_AVGMINMAX, "adjust_qunit", "us"); - - lprocfs_register_stats(qctxt->lqc_proc_dir, "stats", qctxt->lqc_stats); - - RETURN(rc); - -out_free_proc: - lprocfs_remove(&qctxt->lqc_proc_dir); -out: - RETURN(rc); + struct seq_file *seq; + int rc; + struct lquota_procfs *lqp; + const struct dt_it_ops *iops; + struct dt_it *it; + + /* Allocate quota procfs data. This structure will be passed to + * seq_start/stop/next/show via seq->private */ + OBD_ALLOC_PTR(lqp); + if (lqp == NULL) + return -ENOMEM; + + /* store pointer to object we would like to iterate over */ + lqp->lqp_obj = (struct dt_object *)PDE_DATA(inode); + + /* Initialize the common environment to be used in the seq operations */ + rc = lu_env_init(&lqp->lqp_env, LCT_LOCAL); + if (rc) { + char *obd_name = "quota"; + + if (lqp->lqp_obj != NULL) + obd_name = lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name; + + CERROR("%s: error initializing procfs quota env: rc = %d\n", + obd_name, rc); + goto out_lqp; + } + + rc = LPROCFS_ENTRY_CHECK(inode); + if (rc < 0) + goto out_env; + + rc = seq_open(file, &lprocfs_quota_seq_sops); + if (rc) + goto out_env; + + /* initialize iterator */ + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0); + if (IS_ERR(it)) { + rc = PTR_ERR(it); + CERROR("%s: failed to initialize iterator: rc = %ld\n", + lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, + PTR_ERR(it)); + seq_release(inode, file); + goto out_env; + } + lqp->lqp_it = it; + lqp->lqp_cookie = 0; + + seq = file->private_data; + seq->private = lqp; + return 0; + +out_env: + lu_env_fini(&lqp->lqp_env); +out_lqp: + OBD_FREE_PTR(lqp); + return rc; } -int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt) +static int lprocfs_quota_seq_release(struct inode *inode, struct file *file) { - if (!qctxt || !qctxt->lqc_proc_dir) - return -EINVAL; - - if (qctxt->lqc_stats != NULL) - lprocfs_free_stats(&qctxt->lqc_stats); - - lprocfs_remove(&qctxt->lqc_proc_dir); - return 0; + struct seq_file *seq = file->private_data; + struct lquota_procfs *lqp = seq->private; + const struct dt_it_ops *iops; + + LASSERT(lqp); + iops = &lqp->lqp_obj->do_index_ops->dio_it; + if (lqp->lqp_it != NULL) + iops->fini(&lqp->lqp_env, lqp->lqp_it); + lu_env_fini(&lqp->lqp_env); + OBD_FREE_PTR(lqp); + + return seq_release(inode, file); } -#endif /* LPROCFS */ -#endif +struct file_operations lprocfs_quota_seq_fops = { + .owner = THIS_MODULE, + .open = lprocfs_quota_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = lprocfs_quota_seq_release, +}; +#endif /* CONFIG_PROC_FS */