Whamcloud - gitweb
LU-13039 quota: Ensure local buffer is null terminated
[fs/lustre-release.git] / lustre / quota / qsd_lib.c
index 7ab8648..c535f90 100644 (file)
@@ -21,7 +21,7 @@
  * GPL HEADER END
  */
 /*
- * Copyright (c) 2012, 2016, Intel Corporation.
+ * Copyright (c) 2012, 2017, Intel Corporation.
  * Use is subject to license terms.
  *
  * Author: Johann Lombardi <johann.lombardi@intel.com>
@@ -85,15 +85,19 @@ static int qsd_state_seq_show(struct seq_file *m, void *data)
                strcat(enabled, "u");
        if (qsd_type_enabled(qsd, GRPQUOTA))
                strcat(enabled, "g");
+       if (qsd_type_enabled(qsd, PRJQUOTA))
+               strncat(enabled, "p", 1);
        if (strlen(enabled) == 0)
                strcat(enabled, "none");
 
+       /* TODO: further pool ID should be removed or
+        * replaced with pool Name */
        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_svname, 0,
                   qsd->qsd_is_md ? "md" : "dt", enabled,
                   qsd->qsd_exp_valid ? "setup" : "not setup yet");
 
@@ -103,18 +107,24 @@ static int qsd_state_seq_show(struct seq_file *m, void *data)
                        strcat(enabled, "u");
                if (qsd->qsd_type_array[GRPQUOTA]->qqi_acct_obj != NULL)
                        strcat(enabled, "g");
+               if (qsd->qsd_type_array[PRJQUOTA]->qqi_acct_obj != NULL)
+                       strncat(enabled, "p", 1);
                if (strlen(enabled) == 0)
                        strcat(enabled, "none");
                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",
+                          "group uptodate: glb[%d],slv[%d],reint[%d]\n"
+                          "project uptodate: glb[%d],slv[%d],reint[%d]\n",
                           enabled,
                           qsd->qsd_type_array[USRQUOTA]->qqi_glb_uptodate,
                           qsd->qsd_type_array[USRQUOTA]->qqi_slv_uptodate,
                           qsd->qsd_type_array[USRQUOTA]->qqi_reint,
                           qsd->qsd_type_array[GRPQUOTA]->qqi_glb_uptodate,
                           qsd->qsd_type_array[GRPQUOTA]->qqi_slv_uptodate,
-                          qsd->qsd_type_array[GRPQUOTA]->qqi_reint);
+                          qsd->qsd_type_array[GRPQUOTA]->qqi_reint,
+                          qsd->qsd_type_array[PRJQUOTA]->qqi_glb_uptodate,
+                          qsd->qsd_type_array[PRJQUOTA]->qqi_slv_uptodate,
+                          qsd->qsd_type_array[PRJQUOTA]->qqi_reint);
        }
        return 0;
 }
@@ -129,16 +139,61 @@ static int qsd_enabled_seq_show(struct seq_file *m, void *data)
 
        memset(enabled, 0, sizeof(enabled));
        if (qsd_type_enabled(qsd, USRQUOTA))
-               strcat(enabled, "u");
+               strncat(enabled, "u", sizeof(enabled) - strlen(enabled));
        if (qsd_type_enabled(qsd, GRPQUOTA))
-               strcat(enabled, "g");
+               strncat(enabled, "g", sizeof(enabled) - strlen(enabled));
+       if (qsd_type_enabled(qsd, PRJQUOTA))
+               strncat(enabled, "p", sizeof(enabled) - strlen(enabled));
        if (strlen(enabled) == 0)
-               strcat(enabled, "none");
+               strncat(enabled, "none", sizeof(enabled) - strlen(enabled));
 
        seq_printf(m, "%s\n", enabled);
        return 0;
 }
-LPROC_SEQ_FOPS_RO(qsd_enabled);
+
+static ssize_t qsd_enabled_seq_write(struct file *file,
+                                    const char __user *buffer,
+                                    size_t count, loff_t *off)
+{
+       struct seq_file *m = file->private_data;
+       struct qsd_instance *qsd = m->private;
+       char fsname[LUSTRE_MAXFSNAME + 1];
+       int enabled = 0;
+       char valstr[5];
+       int pool, rc;
+
+       if (count > 4)
+               return -E2BIG;
+
+       if (copy_from_user(valstr, buffer, count))
+               GOTO(out, count = -EFAULT);
+
+       valstr[sizeof(valstr) - 1] = 0;
+       if (strchr(valstr, 'u'))
+               enabled |= BIT(USRQUOTA);
+       if (strchr(valstr, 'g'))
+               enabled |= BIT(GRPQUOTA);
+       if (strchr(valstr, 'p'))
+               enabled |= BIT(PRJQUOTA);
+
+       if (enabled == 0 && strcmp(valstr, "none"))
+               GOTO(out, count = -EINVAL);
+
+       if (qsd->qsd_is_md)
+               pool = LQUOTA_RES_MD;
+       else
+               pool = LQUOTA_RES_DT;
+
+       if (server_name2fsname(qsd->qsd_svname, fsname, NULL))
+               GOTO(out, count = -EINVAL);
+
+       rc = qsd_config(valstr, fsname, pool);
+       if (rc)
+               count = rc;
+out:
+       return count;
+}
+LPROC_SEQ_FOPS(qsd_enabled);
 
 /* force reintegration procedure to be executed.
  * Used for test/debugging purpose */
@@ -178,7 +233,7 @@ lprocfs_force_reint_seq_write(struct file *file, const char __user *buffer,
        }
        return rc == 0 ? count : rc;
 }
-LPROC_SEQ_FOPS_WO_TYPE(qsd, force_reint);
+LPROC_SEQ_FOPS_WR_ONLY(qsd, force_reint);
 
 static int qsd_timeout_seq_show(struct seq_file *m, void *data)
 {
@@ -194,14 +249,15 @@ qsd_timeout_seq_write(struct file *file, const char __user *buffer,
                        size_t count, loff_t *off)
 {
        struct qsd_instance *qsd = ((struct seq_file *)file->private_data)->private;
+       time64_t timeout;
        int rc;
-       __s64 timeout;
-       LASSERT(qsd != NULL);
 
-       rc = lprocfs_str_to_s64(buffer, count, &timeout);
+       LASSERT(qsd != NULL);
+       rc = kstrtoll_from_user(buffer, count, 0, &timeout);
        if (rc)
                return rc;
-       if (timeout < 0 || timeout > INT_MAX)
+
+       if (timeout < 0)
                return -EINVAL;
 
        qsd->qsd_timeout = timeout;
@@ -345,6 +401,8 @@ static void qsd_qtype_fini(const struct lu_env *env, struct qsd_instance *qsd,
 
 static const char *qtype2acct_name(int qtype)
 {
+       static char unknown[24];
+
        switch (qtype) {
        case USRQUOTA:
                return "acct_user";
@@ -354,12 +412,14 @@ static const char *qtype2acct_name(int qtype)
                return "acct_project";
        }
 
-       LASSERTF(0, "invalid quota type: %d", qtype);
-       return NULL;
+       snprintf(unknown, sizeof(unknown), "acct_unknown_%u", qtype);
+       return unknown;
 }
 
 static const char *qtype2glb_name(int qtype)
 {
+       static char unknown[24];
+
        switch (qtype) {
        case USRQUOTA:
                return "limit_user";
@@ -369,8 +429,8 @@ static const char *qtype2glb_name(int qtype)
                return "limit_project";
        }
 
-       LASSERTF(0, "invalid quota type: %d", qtype);
-       return NULL;
+       snprintf(unknown, sizeof(unknown), "acct_unknown_%u", qtype);
+       return unknown;
 }
 
 /*
@@ -415,8 +475,7 @@ static int qsd_qtype_init(const struct lu_env *env, struct qsd_instance *qsd,
        thread_set_flags(&qqi->qqi_reint_thread, SVC_STOPPED);
        INIT_LIST_HEAD(&qqi->qqi_deferred_glb);
        INIT_LIST_HEAD(&qqi->qqi_deferred_slv);
-       lquota_generate_fid(&qqi->qqi_fid, qsd->qsd_pool_id,
-                           QSD_RES_TYPE(qsd), qtype);
+       lquota_generate_fid(&qqi->qqi_fid, QSD_RES_TYPE(qsd), qtype);
 
        /* open accounting object */
        LASSERT(qqi->qqi_acct_obj == NULL);
@@ -532,16 +591,6 @@ void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd)
                qsd->qsd_ns = NULL;
        }
 
-       /* free per-quota type data */
-       for (qtype = USRQUOTA; qtype < LL_MAXQUOTAS; qtype++)
-               qsd_qtype_fini(env, qsd, qtype);
-
-       if (qsd->qsd_exp) {
-               /* deregister connection to the quota master */
-               qsd->qsd_exp_valid = false;
-               lustre_deregister_lwp_item(&qsd->qsd_exp);
-       }
-
        /* release per-filesystem information */
        if (qsd->qsd_fsinfo != NULL) {
                mutex_lock(&qsd->qsd_fsinfo->qfs_mutex);
@@ -552,6 +601,14 @@ void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd)
                qsd->qsd_fsinfo = NULL;
        }
 
+       /* free per-quota type data */
+       for (qtype = USRQUOTA; qtype < LL_MAXQUOTAS; qtype++)
+               qsd_qtype_fini(env, qsd, qtype);
+
+       /* deregister connection to the quota master */
+       qsd->qsd_exp_valid = false;
+       lustre_deregister_lwp_item(&qsd->qsd_exp);
+
        /* release quota root directory */
        if (qsd->qsd_root != NULL) {
                dt_object_put(env, qsd->qsd_root);
@@ -586,7 +643,7 @@ EXPORT_SYMBOL(qsd_fini);
  */
 struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
                              struct dt_device *dev,
-                             struct proc_dir_entry *osd_proc)
+                             struct proc_dir_entry *osd_proc, bool is_md)
 {
        struct qsd_thread_info  *qti = qsd_info(env);
        struct qsd_instance     *qsd;
@@ -613,6 +670,7 @@ struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
        INIT_LIST_HEAD(&qsd->qsd_adjust_list);
        qsd->qsd_prepared = false;
        qsd->qsd_started = false;
+       qsd->qsd_is_md = is_md;
 
        /* copy service name */
        if (strlcpy(qsd->qsd_svname, svname, sizeof(qsd->qsd_svname))
@@ -624,11 +682,6 @@ struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
        lu_ref_add(&dev->dd_lu_dev.ld_reference, "qsd", qsd);
        qsd->qsd_dev = dev;
 
-       /* we only support pool ID 0 (default data or metadata pool) for the
-        * time being. A different pool ID could be assigned to this target via
-        * the configuration log in the future */
-       qsd->qsd_pool_id  = 0;
-
        /* get fsname from svname */
        rc = server_name2fsname(svname, qti->qti_buf, NULL);
        if (rc) {
@@ -649,8 +702,18 @@ struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
        mutex_unlock(&qsd->qsd_fsinfo->qfs_mutex);
 
        /* register procfs directory */
-       qsd->qsd_proc = lprocfs_register(QSD_DIR, osd_proc,
-                                        lprocfs_quota_qsd_vars, qsd);
+       if (qsd->qsd_is_md)
+               qsd->qsd_proc = lprocfs_register(QSD_DIR_MD, osd_proc,
+                                                lprocfs_quota_qsd_vars, qsd);
+       else
+               qsd->qsd_proc = lprocfs_register(QSD_DIR_DT, osd_proc,
+                                                lprocfs_quota_qsd_vars, qsd);
+
+       if (type == LDD_F_SV_TYPE_MDT && qsd->qsd_is_md)
+               lprocfs_add_symlink(QSD_DIR, osd_proc, "./%s", QSD_DIR_MD);
+       else if (type == LDD_F_SV_TYPE_OST && !qsd->qsd_is_md)
+               lprocfs_add_symlink(QSD_DIR, osd_proc, "./%s", QSD_DIR_DT);
+
        if (IS_ERR(qsd->qsd_proc)) {
                rc = PTR_ERR(qsd->qsd_proc);
                qsd->qsd_proc = NULL;
@@ -703,12 +766,10 @@ int qsd_prepare(const struct lu_env *env, struct qsd_instance *qsd)
 
        /* Record whether this qsd instance is managing quota enforcement for a
         * MDT (i.e. inode quota) or OST (block quota) */
-       if (lu_device_is_md(qsd->qsd_dev->dd_lu_dev.ld_site->ls_top_dev)) {
-               qsd->qsd_is_md = true;
+       if (qsd->qsd_is_md)
                qsd->qsd_sync_threshold = LQUOTA_LEAST_QUNIT(LQUOTA_RES_MD);
-       } else {
+       else
                qsd->qsd_sync_threshold = LQUOTA_LEAST_QUNIT(LQUOTA_RES_DT);
-       }
 
        /* look-up on-disk directory for the quota slave */
        qsd->qsd_root = lquota_disk_dir_find_create(env, qsd->qsd_dev, NULL,
@@ -747,7 +808,7 @@ int qsd_prepare(const struct lu_env *env, struct qsd_instance *qsd)
                                       ". Please run tunefs.lustre --quota on "
                                       "an unmounted filesystem if not done "
                                       "already\n", qsd->qsd_svname);
-                       break;
+                       continue;
                }
 
                rc = qsd_start_reint_thread(qqi);