Whamcloud - gitweb
LU-12719 obdclass: serialize lwp list access
[fs/lustre-release.git] / lustre / quota / lproc_quota.c
index 581cf63..cfe7b9b 100644 (file)
  * 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Intel Corporation.
  * Use is subject to license terms.
  *
- * Copyright (c) 2011, Whamcloud, Inc.
- */
-/*
- * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
+ * Author: Johann Lombardi <johann.lombardi@intel.com>
+ * Author: Niu    Yawei    <yawei.niu@intel.com>
  */
 
 #define DEBUG_SUBSYSTEM S_LQUOTA
 #include <lprocfs_status.h>
 #include <obd.h>
 #include <linux/seq_file.h>
-#include <lustre_fsfilt.h>
-
 #include "lquota_internal.h"
 
-#ifdef LPROCFS
+#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_object *lqp_obj;
+       struct lu_env lqp_env;
+       struct dt_it *lqp_it;
+       __u64 lqp_cookie;
+       __u64 lqp_first_cookie;
 };
 
 /* global shared environment */
@@ -66,27 +61,20 @@ static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
 
        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));
+       if (lqp->lqp_it == NULL) /* reach the end */
                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) {
+       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.
                 *
@@ -100,17 +88,25 @@ static void *lprocfs_quota_seq_start(struct seq_file *p, loff_t *pos)
                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;
        }
-       while (offset--) {
-               rc = iops->next(&lqp->lqp_env, it);
-               if (rc != 0) /* Error or reach the end */
-                       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;
 }
 
@@ -128,7 +124,6 @@ static void lprocfs_quota_seq_stop(struct seq_file *p, void *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);
 }
 
 static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
@@ -147,12 +142,17 @@ static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
        if (v == SEQ_START_TOKEN)
                return lprocfs_quota_seq_start(p, pos);
 
+       if (lqp->lqp_it == NULL) /* reach the end */
+               return NULL;
+
        iops = &lqp->lqp_obj->do_index_ops->dio_it;
        it = (struct dt_it *)v;
 
        rc = iops->next(&lqp->lqp_env, it);
-       if (rc == 0)
+       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",
@@ -161,26 +161,44 @@ static void *lprocfs_quota_seq_next(struct seq_file *p, void *v, loff_t *pos)
        /* Reach the end or error */
        iops->put(&lqp->lqp_env, it);
        iops->fini(&lqp->lqp_env, it);
+       lqp->lqp_it = NULL;
        return NULL;
 }
 
+static inline const char *oid2name(__u32 oid)
+{
+       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";
+       }
+}
+
 /*
  * Output example:
  *
- * user_accounting:
+ * usr_accounting:
  * - id:      0
- *   usage:   { inodes:                  209, bytes:             26161152 }
+ *   usage:   { inodes:                  209, kbytes:             2616 }
  * - id:      840000038
- *   usage:   { inodes:                    1, bytes:             10485760 }
+ *   usage:   { inodes:                    1, kbytes:             1048 }
  */
 static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
 {
-       struct lquota_procfs    *lqp = p->private;
-       const struct dt_it_ops  *iops;
-       struct dt_it            *it;
-       struct dt_key           *key;
-       struct lquota_acct_rec   rec;
-       int                      rc;
+       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) {
@@ -188,14 +206,26 @@ static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
                return 0;
        }
 
-       if (v == SEQ_START_TOKEN) {
-               const struct lu_fid *fid = lu_object_fid(&lqp->lqp_obj->do_lu);
+       fid = lu_object_fid(&lqp->lqp_obj->do_lu);
 
-               LASSERT(fid_is_acct(fid));
-               if (fid_oid(fid) == ACCT_USER_OID)
-                       seq_printf(p, "user_accounting:\n");
-               else
-                       seq_printf(p, "group_accounting:\n");
+       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     rtype, qtype;
+
+                       rc = lquota_extract_fid(fid, &rtype, &qtype);
+                       if (rc)
+                               return rc;
+
+                       seq_printf(p, "global_pool%d_%s_%s\n", 0,
+                                  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;
        }
 
@@ -210,7 +240,7 @@ static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
                return PTR_ERR(key);
        }
 
-       rc = iops->rec(&lqp->lqp_env, it, (struct dt_rec *)&rec, 0);
+       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);
@@ -218,8 +248,18 @@ static int lprocfs_quota_seq_show(struct seq_file *p, void *v)
        }
 
        seq_printf(p, "- %-8s %llu\n", "id:", *((__u64 *)key));
-       seq_printf(p, "  %-8s { inodes: %20"LPF64"u, bytes: %20"LPF64"u }\n",
-                  "usage:", rec.ispace, rec.bspace);
+       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;
 }
 
@@ -232,10 +272,11 @@ struct seq_operations lprocfs_quota_seq_sops = {
 
 static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
 {
-       struct proc_dir_entry   *dp = PDE(inode);
        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 */
@@ -244,31 +285,53 @@ static int lprocfs_quota_seq_open(struct inode *inode, struct file *file)
                return -ENOMEM;
 
        /* store pointer to object we would like to iterate over */
-       lqp->lqp_obj = (struct dt_object *)dp->data;
+       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",
-                      lqp->lqp_obj->do_lu.lo_dev->ld_obd->obd_name, rc);
+                      obd_name, rc);
                goto out_lqp;
        }
 
-       if (LPROCFS_ENTRY_AND_CHECK(dp)) {
-               rc = -ENOENT;
+       rc = LPROCFS_ENTRY_CHECK(inode);
+       if (rc < 0)
                goto out_env;
-       }
 
        rc = seq_open(file, &lprocfs_quota_seq_sops);
        if (rc)
-               goto out_lprocfs;
+               goto out_env;
 
+       if (!lqp->lqp_obj) {
+               lqp->lqp_it = NULL;
+               goto out_seq;
+       }
+
+       /* 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;
+
+out_seq:
        seq = file->private_data;
        seq->private = lqp;
        return 0;
 
-out_lprocfs:
-       LPROCFS_EXIT();
 out_env:
        lu_env_fini(&lqp->lqp_env);
 out_lqp:
@@ -280,10 +343,13 @@ static int lprocfs_quota_seq_release(struct inode *inode, struct file *file)
 {
        struct seq_file         *seq = file->private_data;
        struct lquota_procfs    *lqp = seq->private;
-
-       LPROCFS_EXIT();
+       const struct dt_it_ops  *iops;
 
        LASSERT(lqp);
+       if (lqp->lqp_it != NULL) {
+               iops = &lqp->lqp_obj->do_index_ops->dio_it;
+               iops->fini(&lqp->lqp_env, lqp->lqp_it);
+       }
        lu_env_fini(&lqp->lqp_env);
        OBD_FREE_PTR(lqp);
 
@@ -297,4 +363,4 @@ struct file_operations lprocfs_quota_seq_fops = {
        .llseek         = seq_lseek,
        .release        = lprocfs_quota_seq_release,
 };
-#endif  /* LPROCFS */
+#endif /* CONFIG_PROC_FS */