* GPL HEADER END
*/
/*
- * Copyright (c) 2012 Intel, Inc.
+ * Copyright (c) 2011, 2017, Intel Corporation.
* Use is subject to license terms.
*
* Author: Johann Lombardi <johann.lombardi@intel.com>
#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 */
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.
*
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;
}
/* 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)
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",
/* 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:
*
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");
+ seq_printf(p, "%s:\n", oid2name(fid_oid(fid)));
} else if (fid_seq(fid) == FID_SEQ_QUOTA_GLB) {
int poolid, rtype, qtype;
return rc;
seq_printf(p, "global_pool%d_%s_%s\n", poolid,
- RES_NAME(rtype), QTYPE_NAME(qtype));
+ 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");
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:",
+ 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: %20"LPF64"u, soft: %20"LPF64
- "u, granted: %20"LPF64"u, time: %20"LPF64"u }\n",
+ 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,
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 */
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:
{
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);
.llseek = seq_lseek,
.release = lprocfs_quota_seq_release,
};
-#endif /* LPROCFS */
+#endif /* CONFIG_PROC_FS */