* GPL HEADER END
*/
/*
- * Copyright (c) 2012, Intel Corporation.
+ * Copyright (c) 2012, 2014, Intel Corporation.
* Use is subject to license terms.
*
* Author: Johann Lombardi <johann.lombardi@intel.com>
* freed via qsd_fini().
*/
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-
#define DEBUG_SUBSYSTEM S_LQUOTA
#include <obd_class.h>
#include "qsd_internal.h"
-cfs_mem_cache_t *upd_kmem;
+struct kmem_cache *upd_kmem;
struct lu_kmem_descr qsd_caches[] = {
{
LU_KEY_INIT_GENERIC(qsd);
/* some procfs helpers */
-static int lprocfs_qsd_rd_state(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int qsd_state_seq_show(struct seq_file *m, void *data)
{
- struct qsd_instance *qsd = (struct qsd_instance *)data;
+ struct qsd_instance *qsd = m->private;
char enabled[5];
int rc;
if (strlen(enabled) == 0)
strcat(enabled, "none");
- rc = snprintf(page, count,
- "target name: %s\n"
- "pool ID: %d\n"
- "type: %s\n"
- "quota enabled: %s\n"
- "conn to master: %s\n",
- qsd->qsd_svname, qsd->qsd_pool_id,
- qsd->qsd_is_md ? "md" : "dt", enabled,
- qsd->qsd_exp_valid ? "setup" : "not setup yet");
+ rc = seq_printf(m, "target name: %s\n"
+ "pool ID: %d\n"
+ "type: %s\n"
+ "quota enabled: %s\n"
+ "conn to master: %s\n",
+ qsd->qsd_svname, qsd->qsd_pool_id,
+ qsd->qsd_is_md ? "md" : "dt", enabled,
+ qsd->qsd_exp_valid ? "setup" : "not setup yet");
if (qsd->qsd_prepared) {
memset(enabled, 0, sizeof(enabled));
strcat(enabled, "g");
if (strlen(enabled) == 0)
strcat(enabled, "none");
- rc += snprintf(page + rc, count - rc,
- "space acct: %s\n"
+ rc += seq_printf(m, "space acct: %s\n"
"user uptodate: glb[%d],slv[%d],reint[%d]\n"
"group uptodate: glb[%d],slv[%d],reint[%d]\n",
enabled,
}
return rc;
}
+LPROC_SEQ_FOPS_RO(qsd_state);
-static int lprocfs_qsd_rd_enabled(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int qsd_enabled_seq_show(struct seq_file *m, void *data)
{
- struct qsd_instance *qsd = (struct qsd_instance *)data;
+ struct qsd_instance *qsd = m->private;
char enabled[5];
LASSERT(qsd != NULL);
if (strlen(enabled) == 0)
strcat(enabled, "none");
- return snprintf(page, count, "%s\n", enabled);
+ return seq_printf(m, "%s\n", enabled);
}
+LPROC_SEQ_FOPS_RO(qsd_enabled);
/* force reintegration procedure to be executed.
* Used for test/debugging purpose */
-static int lprocfs_qsd_wr_force_reint(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static ssize_t
+lprocfs_force_reint_seq_write(struct file *file, const char *buffer,
+ size_t count, loff_t *off)
{
- struct qsd_instance *qsd = (struct qsd_instance *)data;
- int rc = 0, qtype;
+ struct qsd_instance *qsd = ((struct seq_file *)file->private_data)->private;
+ int rc = 0, qtype;
LASSERT(qsd != NULL);
}
return rc == 0 ? count : rc;
}
+LPROC_SEQ_FOPS_WO_TYPE(qsd, force_reint);
-static int lprocfs_qsd_rd_timeout(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int qsd_timeout_seq_show(struct seq_file *m, void *data)
{
- struct qsd_instance *qsd = (struct qsd_instance *)data;
+ struct qsd_instance *qsd = m->private;
LASSERT(qsd != NULL);
- return snprintf(page, count, "%d\n", qsd_wait_timeout(qsd));
+ return seq_printf(m, "%d\n", qsd_wait_timeout(qsd));
}
-static int lprocfs_qsd_wr_timeout(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static ssize_t
+qsd_timeout_seq_write(struct file *file, const char *buffer,
+ size_t count, loff_t *off)
{
- struct qsd_instance *qsd = (struct qsd_instance *)data;
- int timeout, rc;
+ struct qsd_instance *qsd = ((struct seq_file *)file->private_data)->private;
+ int timeout, rc;
LASSERT(qsd != NULL);
rc = lprocfs_write_helper(buffer, count, &timeout);
qsd->qsd_timeout = timeout;
return count;
}
-
-static struct lprocfs_vars lprocfs_quota_qsd_vars[] = {
- { "info", lprocfs_qsd_rd_state, 0, 0},
- { "enabled", lprocfs_qsd_rd_enabled, 0, 0},
- { "force_reint", 0, lprocfs_qsd_wr_force_reint, 0},
- { "timeout", lprocfs_qsd_rd_timeout, lprocfs_qsd_wr_timeout, 0},
+LPROC_SEQ_FOPS(qsd_timeout);
+
+static struct lprocfs_seq_vars lprocfs_quota_qsd_vars[] = {
+ { .name = "info",
+ .fops = &qsd_state_fops },
+ { .name = "enabled",
+ .fops = &qsd_enabled_fops },
+ { .name = "force_reint",
+ .fops = &qsd_force_reint_fops },
+ { .name = "timeout",
+ .fops = &qsd_timeout_fops },
{ NULL }
};
/* qsd_exp should now be valid */
LASSERT(qsd->qsd_exp);
- /* grab reference on namespace */
- ldlm_namespace_get(class_exp2obd(qsd->qsd_exp)->obd_namespace);
qsd->qsd_ns = class_exp2obd(qsd->qsd_exp)->obd_namespace;
write_lock(&qsd->qsd_lock);
* step 3) will have to wait for qsd_start() to be called */
for (type = USRQUOTA; type < MAXQUOTAS; type++) {
struct qsd_qtype_info *qqi = qsd->qsd_type_array[type];
- cfs_waitq_signal(&qqi->qqi_reint_thread.t_ctl_waitq);
+ wake_up(&qqi->qqi_reint_thread.t_ctl_waitq);
}
RETURN(0);
int qtype)
{
struct qsd_qtype_info *qqi;
+ int repeat = 0;
ENTRY;
if (qsd->qsd_type_array[qtype] == NULL)
qsd->qsd_type_array[qtype] = NULL;
/* all deferred work lists should be empty */
- LASSERT(cfs_list_empty(&qqi->qqi_deferred_glb));
- LASSERT(cfs_list_empty(&qqi->qqi_deferred_slv));
+ LASSERT(list_empty(&qqi->qqi_deferred_glb));
+ LASSERT(list_empty(&qqi->qqi_deferred_slv));
/* shutdown lquota site */
if (qqi->qqi_site != NULL && !IS_ERR(qqi->qqi_site)) {
qqi->qqi_site = NULL;
}
+ /* The qqi may still be holding by global locks which are being
+ * canceled asynchronously (LU-4365), see the following steps:
+ *
+ * - On server umount, we try to clear all quota locks first by
+ * disconnecting LWP (which will invalidate import and cleanup
+ * all locks on it), however, if quota reint process is holding
+ * the global lock for reintegration at that time, global lock
+ * will fail to be cleared on LWP disconnection.
+ *
+ * - Umount process goes on and stops reint process, the global
+ * lock will be dropped on reint process exit, however, the lock
+ * cancel in done in asynchronous way, so the
+ * qsd_glb_blocking_ast() might haven't been called yet when we
+ * get here.
+ */
+ while (atomic_read(&qqi->qqi_ref) > 1) {
+ CDEBUG(D_QUOTA, "qqi reference count %u, repeat: %d\n",
+ atomic_read(&qqi->qqi_ref), repeat);
+ repeat++;
+ schedule_timeout_and_set_state(TASK_INTERRUPTIBLE,
+ cfs_time_seconds(1));
+ }
+
/* by now, all qqi users should have gone away */
- LASSERT(cfs_atomic_read(&qqi->qqi_ref) == 1);
+ LASSERT(atomic_read(&qqi->qqi_ref) == 1);
lu_ref_fini(&qqi->qqi_reference);
/* release accounting object */
if (qqi == NULL)
RETURN(-ENOMEM);
qsd->qsd_type_array[qtype] = qqi;
- cfs_atomic_set(&qqi->qqi_ref, 1); /* referenced from qsd */
+ atomic_set(&qqi->qqi_ref, 1); /* referenced from qsd */
/* set backpointer and other parameters */
qqi->qqi_qsd = qsd;
qqi->qqi_glb_uptodate = false;
qqi->qqi_slv_uptodate = false;
qqi->qqi_reint = false;
- cfs_waitq_init(&qqi->qqi_reint_thread.t_ctl_waitq);
+ init_waitqueue_head(&qqi->qqi_reint_thread.t_ctl_waitq);
thread_set_flags(&qqi->qqi_reint_thread, SVC_STOPPED);
- CFS_INIT_LIST_HEAD(&qqi->qqi_deferred_glb);
- CFS_INIT_LIST_HEAD(&qqi->qqi_deferred_slv);
+ INIT_LIST_HEAD(&qqi->qqi_deferred_glb);
+ INIT_LIST_HEAD(&qqi->qqi_deferred_slv);
/* open accounting object */
LASSERT(qqi->qqi_acct_obj == NULL);
qqi->qqi_acct_obj = acct_obj_lookup(env, qsd->qsd_dev, qtype);
if (IS_ERR(qqi->qqi_acct_obj)) {
- LCONSOLE_WARN("%s: No %s space accounting support. Please "
- "consider running tunefs.lustre --quota on an "
- "unmounted filesystem to enable quota accounting."
- "\n", qsd->qsd_svname,
- QTYPE_NAME(qtype));
+ CDEBUG(D_QUOTA, "%s: no %s space accounting support rc:%ld\n",
+ qsd->qsd_svname, QTYPE_NAME(qtype),
+ PTR_ERR(qqi->qqi_acct_obj));
qqi->qqi_acct_obj = NULL;
qsd->qsd_acct_failed = true;
}
qsd_stop_reint_thread(qsd->qsd_type_array[qtype]);
}
- /* release reference on namespace */
if (qsd->qsd_ns != NULL) {
- ldlm_namespace_put(qsd->qsd_ns);
qsd->qsd_ns = NULL;
}
/* deregister connection to the quota master */
qsd->qsd_exp_valid = false;
- lustre_deregister_osp_item(&qsd->qsd_exp);
+ lustre_deregister_lwp_item(&qsd->qsd_exp);
/* release per-filesystem information */
if (qsd->qsd_fsinfo != NULL) {
- down(&qsd->qsd_fsinfo->qfs_sem);
+ mutex_lock(&qsd->qsd_fsinfo->qfs_mutex);
/* remove from the list of fsinfo */
- cfs_list_del_init(&qsd->qsd_link);
- up(&qsd->qsd_fsinfo->qfs_sem);
+ list_del_init(&qsd->qsd_link);
+ mutex_unlock(&qsd->qsd_fsinfo->qfs_mutex);
qsd_put_fsinfo(qsd->qsd_fsinfo);
qsd->qsd_fsinfo = NULL;
}
*/
struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
struct dt_device *dev,
- cfs_proc_dir_entry_t *osd_proc)
+ struct proc_dir_entry *osd_proc)
{
struct qsd_thread_info *qti = qsd_info(env);
struct qsd_instance *qsd;
/* generic initializations */
rwlock_init(&qsd->qsd_lock);
- CFS_INIT_LIST_HEAD(&qsd->qsd_link);
+ INIT_LIST_HEAD(&qsd->qsd_link);
thread_set_flags(&qsd->qsd_upd_thread, SVC_STOPPED);
- cfs_waitq_init(&qsd->qsd_upd_thread.t_ctl_waitq);
- CFS_INIT_LIST_HEAD(&qsd->qsd_upd_list);
+ init_waitqueue_head(&qsd->qsd_upd_thread.t_ctl_waitq);
+ INIT_LIST_HEAD(&qsd->qsd_upd_list);
spin_lock_init(&qsd->qsd_adjust_lock);
- CFS_INIT_LIST_HEAD(&qsd->qsd_adjust_list);
+ INIT_LIST_HEAD(&qsd->qsd_adjust_list);
qsd->qsd_prepared = false;
qsd->qsd_started = false;
/* copy service name */
- strncpy(qsd->qsd_svname, svname, MAX_OBD_NAME);
+ if (strlcpy(qsd->qsd_svname, svname, sizeof(qsd->qsd_svname))
+ >= sizeof(qsd->qsd_svname))
+ GOTO(out, rc = -E2BIG);
/* grab reference on osd device */
lu_device_get(&dev->dd_lu_dev);
}
/* add in the list of lquota_fsinfo */
- down(&qsd->qsd_fsinfo->qfs_sem);
+ mutex_lock(&qsd->qsd_fsinfo->qfs_mutex);
list_add_tail(&qsd->qsd_link, &qsd->qsd_fsinfo->qfs_qsd_list);
- up(&qsd->qsd_fsinfo->qfs_sem);
+ mutex_unlock(&qsd->qsd_fsinfo->qfs_mutex);
/* register procfs directory */
- qsd->qsd_proc = lprocfs_register(QSD_DIR, osd_proc,
- lprocfs_quota_qsd_vars, qsd);
+ qsd->qsd_proc = lprocfs_seq_register(QSD_DIR, osd_proc,
+ lprocfs_quota_qsd_vars, qsd);
if (IS_ERR(qsd->qsd_proc)) {
rc = PTR_ERR(qsd->qsd_proc);
qsd->qsd_proc = NULL;
}
/* generate osp name */
- rc = tgt_name2ospname((char *)qsd->qsd_svname, qti->qti_buf);
+ rc = tgt_name2lwp_name(qsd->qsd_svname, qti->qti_buf,
+ MTI_NAME_MAXLEN, 0);
if (rc) {
CERROR("%s: failed to generate ospname (%d)\n",
qsd->qsd_svname, rc);
/* the connection callback will start the reintegration
* procedure if quota is enabled */
- rc = lustre_register_osp_item(qti->qti_buf, &qsd->qsd_exp,
+ rc = lustre_register_lwp_item(qti->qti_buf, &qsd->qsd_exp,
qsd_conn_callback, (void *)qsd);
if (rc) {
CERROR("%s: fail to get connection to master (%d)\n",
* up to usage; If usage < granted, release down to usage. */
for (type = USRQUOTA; type < MAXQUOTAS; type++) {
struct qsd_qtype_info *qqi = qsd->qsd_type_array[type];
- cfs_waitq_signal(&qqi->qqi_reint_thread.t_ctl_waitq);
+ wake_up(&qqi->qqi_reint_thread.t_ctl_waitq);
}
RETURN(rc);