Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[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 Intel, Inc.
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 #ifndef EXPORT_SYMTAB
32 # define EXPORT_SYMTAB
33 #endif
34
35 #define DEBUG_SUBSYSTEM S_LQUOTA
36
37 #include <obd_class.h>
38 #include <lustre_param.h>
39
40 #include "qsd_internal.h"
41
42 static CFS_LIST_HEAD(qfs_list);
43 /* protect the qfs_list */
44 static DEFINE_SPINLOCK(qfs_list_lock);
45
46 /*
47  * Put reference of qsd_fsinfo.
48  *
49  * \param  qfs    - the qsd_fsinfo to be put
50  */
51 void qsd_put_fsinfo(struct qsd_fsinfo *qfs)
52 {
53         ENTRY;
54         LASSERT(qfs != NULL);
55
56         spin_lock(&qfs_list_lock);
57         LASSERT(qfs->qfs_ref > 0);
58         qfs->qfs_ref--;
59         if (qfs->qfs_ref == 0) {
60                 LASSERT(cfs_list_empty(&qfs->qfs_qsd_list));
61                 cfs_list_del(&qfs->qfs_link);
62                 OBD_FREE_PTR(qfs);
63         }
64         spin_unlock(&qfs_list_lock);
65         EXIT;
66 }
67
68 /*
69  * Find or create a qsd_fsinfo
70  *
71  * \param  name   - filesystem name
72  * \param  create - when @create is non-zero, create new one if fail to
73  *                  find existing qfs by @name
74  *
75  * \retval qsd_fsinfo - success
76  * \retval NULL          - failure
77  */
78 struct qsd_fsinfo *qsd_get_fsinfo(char *name, bool create)
79 {
80         struct qsd_fsinfo       *qfs, *new = NULL;
81         ENTRY;
82
83         if (name == NULL ||  strlen(name) >= MTI_NAME_MAXLEN)
84                 RETURN(NULL);
85
86         if (create) {
87                 /* pre-allocate a qsd_fsinfo in case there isn't one already.
88                  * we can afford the extra cost since qsd_get_fsinfo() isn't
89                  * called very often with create = true */
90
91                 OBD_ALLOC_PTR(new);
92                 if (new == NULL)
93                         RETURN(NULL);
94
95                 sema_init(&new->qfs_sem, 1);
96                 CFS_INIT_LIST_HEAD(&new->qfs_qsd_list);
97                 strcpy(new->qfs_name, name);
98                 new->qfs_ref = 1;
99         }
100
101         /* search in the fsinfo list */
102         spin_lock(&qfs_list_lock);
103         cfs_list_for_each_entry(qfs, &qfs_list, qfs_link) {
104                 if (!strcmp(qfs->qfs_name, name)) {
105                         qfs->qfs_ref++;
106                         goto out;
107                 }
108         }
109
110         qfs = NULL; /* not found */
111
112         if (new) {
113                 /* not found, but we were asked to create a new one */
114                 cfs_list_add_tail(&new->qfs_link, &qfs_list);
115                 qfs = new;
116                 new = NULL;
117         }
118 out:
119         spin_unlock(&qfs_list_lock);
120
121         if (new)
122                 OBD_FREE_PTR(new);
123         RETURN(qfs);
124 }
125
126 /*
127  * Quota configuration handlers in charge of processing all per-filesystem quota
128  * parameters set via conf_param.
129  *
130  * \param lcfg - quota configuration log to be processed
131  */
132 int qsd_process_config(struct lustre_cfg *lcfg)
133 {
134         struct qsd_fsinfo       *qfs;
135         char                    *fsname = lustre_cfg_string(lcfg, 0);
136         char                    *cfgstr = lustre_cfg_string(lcfg, 1);
137         char                    *keystr, *valstr;
138         int                      rc, pool, enabled = 0;
139         bool                     reint = false;
140         ENTRY;
141
142         CDEBUG(D_QUOTA, "processing quota parameter: fs:%s cfgstr:%s\n", fsname,
143                cfgstr);
144
145         if (class_match_param(cfgstr, PARAM_QUOTA, &keystr) != 0)
146                 RETURN(-EINVAL);
147
148         if (!class_match_param(keystr, QUOTA_METAPOOL_NAME, &valstr))
149                 pool = LQUOTA_RES_MD;
150         else if (!class_match_param(keystr, QUOTA_DATAPOOL_NAME, &valstr))
151                 pool = LQUOTA_RES_DT;
152         else
153                 RETURN(-EINVAL);
154
155         qfs = qsd_get_fsinfo(fsname, 0);
156         if (qfs == NULL) {
157                 CERROR("failed to find quota filesystem information for %s\n",
158                        fsname);
159                 RETURN(-ENOENT);
160         }
161
162         if (strchr(valstr, 'u'))
163                 enabled |= 1 << USRQUOTA;
164         if (strchr(valstr, 'g'))
165                 enabled |= 1 << GRPQUOTA;
166
167         down(&qfs->qfs_sem);
168         if (qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] == enabled)
169                 /* no change required */
170                 GOTO(out, rc = 0);
171
172         if ((qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] & enabled) != enabled)
173                 reint = true;
174
175         qfs->qfs_enabled[pool - LQUOTA_FIRST_RES] = enabled;
176
177         /* trigger reintegration for all qsd */
178         if (reint) {
179                 struct qsd_instance     *qsd;
180                 struct qsd_qtype_info   *qqi;
181
182                 cfs_list_for_each_entry(qsd, &qfs->qfs_qsd_list, qsd_link) {
183                         bool    skip = false;
184                         int     type;
185
186                         /* start reintegration only if qsd_prepare() was
187                          * successfully called */
188                         read_lock(&qsd->qsd_lock);
189                         if (!qsd->qsd_prepared)
190                                 skip = true;
191                         read_unlock(&qsd->qsd_lock);
192                         if (skip)
193                                 continue;
194
195                         for (type = USRQUOTA; type < MAXQUOTAS; type++) {
196                                 qqi = qsd->qsd_type_array[type];
197                                 qsd_start_reint_thread(qqi);
198                         }
199                 }
200         }
201 out:
202         up(&qfs->qfs_sem);
203         qsd_put_fsinfo(qfs);
204         RETURN(0);
205 }