Whamcloud - gitweb
LU-15785 tests: do not detect versions for RPC_MODE mode
[fs/lustre-release.git] / lustre / quota / qsd_config.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA
20  *
21  * GPL HEADER END
22  */
23 /*
24  * Copyright (c) 2012, 2014, Intel Corporation.
25  * Use is subject to license terms.
26  *
27  * Author: Johann Lombardi <johann.lombardi@intel.com>
28  * Author: Niu    Yawei    <yawei.niu@intel.com>
29  */
30
31 #define DEBUG_SUBSYSTEM S_LQUOTA
32
33 #include <obd_class.h>
34 #include <uapi/linux/lustre/lustre_param.h>
35
36 #include "qsd_internal.h"
37
38 static LIST_HEAD(qfs_list);
39 /* protect the qfs_list */
40 static DEFINE_SPINLOCK(qfs_list_lock);
41
42 /*
43  * Put reference of qsd_fsinfo.
44  *
45  * \param  qfs    - the qsd_fsinfo to be put
46  */
47 void qsd_put_fsinfo(struct qsd_fsinfo *qfs)
48 {
49         ENTRY;
50         LASSERT(qfs != NULL);
51
52         spin_lock(&qfs_list_lock);
53         LASSERT(qfs->qfs_ref > 0);
54         qfs->qfs_ref--;
55         if (qfs->qfs_ref == 0) {
56                 LASSERT(list_empty(&qfs->qfs_qsd_list));
57                 list_del(&qfs->qfs_link);
58                 OBD_FREE_PTR(qfs);
59         }
60         spin_unlock(&qfs_list_lock);
61         EXIT;
62 }
63
64 /*
65  * Find or create a qsd_fsinfo
66  *
67  * \param  name   - filesystem name
68  * \param  create - when @create is non-zero, create new one if fail to
69  *                  find existing qfs by @name
70  *
71  * \retval qsd_fsinfo - success
72  * \retval NULL          - failure
73  */
74 struct qsd_fsinfo *qsd_get_fsinfo(char *name, bool create)
75 {
76         struct qsd_fsinfo       *qfs, *new = NULL;
77         ENTRY;
78
79         if (name == NULL ||  strlen(name) >= MTI_NAME_MAXLEN)
80                 RETURN(NULL);
81
82         if (create) {
83                 /* pre-allocate a qsd_fsinfo in case there isn't one already.
84                  * we can afford the extra cost since qsd_get_fsinfo() isn't
85                  * called very often with create = true */
86
87                 OBD_ALLOC_PTR(new);
88                 if (new == NULL)
89                         RETURN(NULL);
90
91                 mutex_init(&new->qfs_mutex);
92                 INIT_LIST_HEAD(&new->qfs_qsd_list);
93                 strcpy(new->qfs_name, name);
94                 new->qfs_ref = 1;
95         }
96
97         /* search in the fsinfo list */
98         spin_lock(&qfs_list_lock);
99         list_for_each_entry(qfs, &qfs_list, qfs_link) {
100                 if (!strcmp(qfs->qfs_name, name)) {
101                         qfs->qfs_ref++;
102                         goto out;
103                 }
104         }
105
106         qfs = NULL; /* not found */
107
108         if (new) {
109                 /* not found, but we were asked to create a new one */
110                 list_add_tail(&new->qfs_link, &qfs_list);
111                 qfs = new;
112                 new = NULL;
113         }
114 out:
115         spin_unlock(&qfs_list_lock);
116
117         if (new)
118                 OBD_FREE_PTR(new);
119         RETURN(qfs);
120 }
121
122 int qsd_config(char *valstr, char *fsname, int pool)
123 {
124         struct qsd_fsinfo *qfs;
125         int rc, enabled = 0, old_enabled = 0;
126         bool reint = false;
127
128         ENTRY;
129         qfs = qsd_get_fsinfo(fsname, 0);
130         if (qfs == NULL) {
131                 CERROR("failed to find quota filesystem information for %s\n",
132                        fsname);
133                 RETURN(-ENOENT);
134         }
135
136         if (strchr(valstr, 'u'))
137                 enabled |= BIT(USRQUOTA);
138         if (strchr(valstr, 'g'))
139                 enabled |= BIT(GRPQUOTA);
140         if (strchr(valstr, 'p'))
141                 enabled |= BIT(PRJQUOTA);
142
143         mutex_lock(&qfs->qfs_mutex);
144         if (qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] == enabled)
145                 /* no change required */
146                 GOTO(out, rc = 0);
147
148         if ((qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] & enabled) != enabled)
149                 reint = true;
150
151         old_enabled = qfs->qfs_enabled[pool - LQUOTA_FIRST_RES];
152         qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] = enabled;
153
154         /* trigger reintegration for all qsd */
155         if (reint) {
156                 struct qsd_instance     *qsd;
157                 struct qsd_qtype_info   *qqi;
158
159                 list_for_each_entry(qsd, &qfs->qfs_qsd_list, qsd_link) {
160                         bool    skip = false;
161                         int     type;
162
163                         /* start reintegration only if qsd_prepare() was
164                          * successfully called */
165                         read_lock(&qsd->qsd_lock);
166                         if (!qsd->qsd_prepared)
167                                 skip = true;
168                         read_unlock(&qsd->qsd_lock);
169                         if (skip)
170                                 continue;
171
172                         for (type = USRQUOTA; type < LL_MAXQUOTAS; type++) {
173                                 qqi = qsd->qsd_type_array[type];
174                                 /* only trigger reintegration if this
175                                  * type of quota is not enabled before */
176                                 if ((old_enabled & BIT(type)) ||
177                                     !(enabled & BIT(type)))
178                                         continue;
179
180                                 if (qqi->qqi_acct_failed) {
181                                         LCONSOLE_ERROR("%s: can't enable quota "
182                                                        "enforcement since space "
183                                                        "accounting isn't functional. "
184                                                        "Please run tunefs.lustre "
185                                                        "--quota on an unmounted "
186                                                        "filesystem if not done already"
187                                                        "\n", qsd->qsd_svname);
188                                         continue;
189                                 }
190                                 qsd_start_reint_thread(qqi);
191                         }
192                 }
193         }
194 out:
195         mutex_unlock(&qfs->qfs_mutex);
196         qsd_put_fsinfo(qfs);
197         RETURN(0);
198 }
199
200 /*
201  * Quota configuration handlers in charge of processing all per-filesystem quota
202  * parameters set via conf_param.
203  *
204  * \param lcfg - quota configuration log to be processed
205  */
206 int qsd_process_config(struct lustre_cfg *lcfg)
207 {
208         char *fsname = lustre_cfg_string(lcfg, 0);
209         char *cfgstr = lustre_cfg_string(lcfg, 1);
210         char *keystr, *valstr;
211         int pool;
212
213         ENTRY;
214         CDEBUG(D_QUOTA, "processing quota parameter: fs:%s cfgstr:%s\n", fsname,
215                cfgstr);
216
217         if (class_match_param(cfgstr, PARAM_QUOTA, &keystr) != 0)
218                 RETURN(-EINVAL);
219
220         if (!class_match_param(keystr, QUOTA_METAPOOL_NAME, &valstr))
221                 pool = LQUOTA_RES_MD;
222         else if (!class_match_param(keystr, QUOTA_DATAPOOL_NAME, &valstr))
223                 pool = LQUOTA_RES_DT;
224         else
225                 RETURN(-EINVAL);
226
227         return qsd_config(valstr, fsname, pool);
228 }