X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fquota%2Flproc_quota.c;h=62215f96a02e83c16678525acf6f04e66bee50b5;hp=58d88f7d0ee5270b2c157ec6e32d5190dfd9a5ef;hb=20dfdeda5ea3f679b68c4a9fb6924c90a0a79cac;hpb=9f463e30893138845eb571cc32426e8d1e04a9fa diff --git a/lustre/quota/lproc_quota.c b/lustre/quota/lproc_quota.c index 58d88f7..62215f9 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, 2012, 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 @@ -42,633 +36,293 @@ #include #include -#include "quota_internal.h" - -#ifdef HAVE_QUOTA_SUPPORT +#include "lquota_internal.h" #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, id; - struct obd_device_target *obt; - ENTRY; - - LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA); - - obt = &obd->u.obt; - - OBD_ALLOC_PTR(oqctl); - if (!oqctl) - RETURN(-ENOMEM); - - if (!atomic_dec_and_test(&obt->obt_quotachecking)) { - CDEBUG(D_INFO, "other people are doing quotacheck\n"); - atomic_inc(&obt->obt_quotachecking); - RETURN(-EBUSY); - } - - id = UGQUOTA2LQC(type); - /* quota already turned on */ - if ((obt->obt_qctxt.lqc_flags & id) == id) { - rc = 0; - goto out; - } - if (obt->obt_qctxt.lqc_immutable) { - LCONSOLE_ERROR("Failed to turn Quota on, immutable mode " - "(is SOM enabled?)\n"); - goto out; - } - - 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) { - struct mds_obd *mds = &obd->u.mds; - - down(&mds->mds_qonoff_sem); - /* turn on cluster wide quota */ - rc = mds_admin_quota_on(obd, oqctl); - if (rc) - CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable admin quota failed. rc=%d\n", rc); - up(&mds->mds_qonoff_sem); - - } - if (!rc) { - /* turn on local quota */ - rc = fsfilt_quotactl(obd, sb, oqctl); - if (rc) - CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, - "auto-enable local quota failed. rc=%d\n", rc); - else - obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type); - } - - pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL); - -out: - atomic_inc(&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) - auto_quota_on(obd, type - 1, obt->obt_sb, is_mds); - - 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); +/* 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; +}; -int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer, - unsigned long count, 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; - 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; + 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; + offset--; + + if (lqp->lqp_obj == NULL) + /* accounting not enabled. */ + return NULL; + + /* initialize iterator */ + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = iops->init(&lqp->lqp_env, lqp->lqp_obj, 0, BYPASS_CAPA); + if (IS_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)); + return NULL; + } + + /* move on to the first valid record */ + rc = iops->load(&lqp->lqp_env, it, 0); + if (rc < 0) { /* Error */ + goto not_found; + } else if (rc == 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; + } + while (offset--) { + rc = iops->next(&lqp->lqp_env, it); + if (rc != 0) /* Error or reach the end */ + goto not_found; + } + return it; + +not_found: + iops->put(&lqp->lqp_env, it); + iops->fini(&lqp->lqp_env, it); + return NULL; } -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) +static void lprocfs_quota_seq_stop(struct seq_file *p, void *v) { - 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); + 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); + iops->fini(&lqp->lqp_env, it); } -EXPORT_SYMBOL(lprocfs_quota_rd_sync_blk); -int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer, - unsigned long count, 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; - int val, rc; - LASSERT(obd != NULL); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val < 0) - return -EINVAL; + struct lquota_procfs *lqp = p->private; + const struct dt_it_ops *iops; + struct dt_it *it; + int rc; - obd->u.obt.obt_qctxt.lqc_sync_blk = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_sync_blk); + LASSERT(lqp); -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); + ++*pos; + if (lqp->lqp_obj == NULL) + return 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); + if (v == SEQ_START_TOKEN) + return lprocfs_quota_seq_start(p, pos); -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); + iops = &lqp->lqp_obj->do_index_ops->dio_it; + it = (struct dt_it *)v; - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; + rc = iops->next(&lqp->lqp_env, it); + if (rc == 0) + return it; - if (val) - obd->u.obt.obt_qctxt.lqc_switch_qs = 1; - else - obd->u.obt.obt_qctxt.lqc_switch_qs = 0; + if (rc < 0) + CERROR("%s: seq_next failed: rc = %d\n", + lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc); - return count; + /* Reach the end or error */ + iops->put(&lqp->lqp_env, it); + iops->fini(&lqp->lqp_env, it); + return NULL; } -EXPORT_SYMBOL(lprocfs_quota_wr_switch_qs); -int lprocfs_quota_rd_boundary_factor(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_cqs_boundary_factor); -} -EXPORT_SYMBOL(lprocfs_quota_rd_boundary_factor); - -int lprocfs_quota_wr_boundary_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_boundary_factor = val; - return count; -} -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) -{ - struct obd_device *obd = (struct obd_device *)data; - LASSERT(obd != NULL); - - - 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); - - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; - - if (val < PTLRPC_MAX_BRW_SIZE || - val >= obd->u.obt.obt_qctxt.lqc_bunit_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_least_bunit); - -int lprocfs_quota_rd_least_iunit(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_least_iunit); + 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)) { + if (fid_oid(fid) == ACCT_USER_OID) + seq_printf(p, "usr_accounting:\n"); + else + seq_printf(p, "grp_accounting:\n"); + } 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: %20"LPF64"u, kbytes: %20"LPF64 + "u }\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: %20"LPF64"u, soft: %20"LPF64 + "u, granted: %20"LPF64"u, time: %20"LPF64"u }\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_least_iunit); - -int lprocfs_quota_wr_least_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 < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz) - return -EINVAL; - - obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val; - return count; -} -EXPORT_SYMBOL(lprocfs_quota_wr_least_iunit); +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 lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int lprocfs_quota_seq_open(struct inode *inode, struct file *file) { - 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 proc_dir_entry *dp = PDE(inode); + struct seq_file *seq; + int rc; + struct lquota_procfs *lqp; + + /* 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 *)dp->data; + + /* 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; + } + + if (LPROCFS_ENTRY_AND_CHECK(dp)) { + rc = -ENOENT; + goto out_env; + } + + rc = seq_open(file, &lprocfs_quota_seq_sops); + if (rc) + goto out_lprocfs; + + seq = file->private_data; + seq->private = lqp; + return 0; + +out_lprocfs: + LPROCFS_EXIT(); +out_env: + lu_env_fini(&lqp->lqp_env); +out_lqp: + OBD_FREE_PTR(lqp); + return rc; } -EXPORT_SYMBOL(lprocfs_quota_rd_qs_factor); -int lprocfs_quota_wr_qs_factor(struct file *file, const char *buffer, - unsigned long count, void *data) +static int lprocfs_quota_seq_release(struct inode *inode, struct file *file) { - struct obd_device *obd = (struct obd_device *)data; - int val, rc; - LASSERT(obd != NULL); + struct seq_file *seq = file->private_data; + struct lquota_procfs *lqp = seq->private; - rc = lprocfs_write_helper(buffer, count, &val); - if (rc) - return rc; + LPROCFS_EXIT(); - if (val < 2) - return -EINVAL; + LASSERT(lqp); + lu_env_fini(&lqp->lqp_env); + OBD_FREE_PTR(lqp); - obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val; - return count; + return seq_release(inode, file); } -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 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, }; - -int lquota_proc_setup(struct obd_device *obd, int is_master) -{ - 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); -} - -int lquota_proc_cleanup(struct lustre_quota_ctxt *qctxt) -{ - 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; -} - #endif /* LPROCFS */ -#endif