4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
24 * Copyright (c) 2012 Whamcloud, Inc.
25 * Use is subject to license terms.
27 * Author: Johann Lombardi <johann@whamcloud.com>
28 * Author: Niu Yawei <niu@whamcloud.com>
32 * Quota Slave Driver (QSD) management.
36 # define EXPORT_SYMTAB
39 #define DEBUG_SUBSYSTEM S_LQUOTA
41 #include "qsd_internal.h"
43 /* define qsd thread key */
44 LU_KEY_INIT_FINI(qsd, struct qsd_thread_info);
45 LU_CONTEXT_KEY_DEFINE(qsd, LCT_MD_THREAD | LCT_DT_THREAD | LCT_LOCAL);
46 LU_KEY_INIT_GENERIC(qsd);
48 /* some procfs helpers */
49 static int lprocfs_qsd_rd_state(char *page, char **start, off_t off,
50 int count, int *eof, void *data)
52 struct qsd_instance *qsd = (struct qsd_instance *)data;
56 return snprintf(page, count,
60 "quota enabled: none\n",
61 qsd->qsd_svname, qsd->qsd_pool_id,
62 qsd->qsd_is_md ? "md" : "dt");
65 static struct lprocfs_vars lprocfs_quota_qsd_vars[] = {
66 { "info", lprocfs_qsd_rd_state, 0, 0},
71 * Release qsd_qtype_info structure which contains data associated with a
72 * given quota type. This releases the accounting objects.
73 * It's called on OSD cleanup when the qsd instance is released.
75 * \param env - is the environment passed by the caller
76 * \param qsd - is the qsd instance managing the qsd_qtype_info structure
78 * \param qtype - is the quota type to be shutdown
80 static void qsd_qtype_fini(const struct lu_env *env, struct qsd_instance *qsd,
83 struct qsd_qtype_info *qqi;
86 if (qsd->qsd_type_array[qtype] == NULL)
88 qqi = qsd->qsd_type_array[qtype];
89 qsd->qsd_type_array[qtype] = NULL;
91 /* release accounting object */
92 if (qqi->qqi_acct_obj != NULL && !IS_ERR(qqi->qqi_acct_obj)) {
93 lu_object_put(env, &qqi->qqi_acct_obj->do_lu);
94 qqi->qqi_acct_obj = NULL;
97 /* release slv index */
98 if (qqi->qqi_slv_obj != NULL && !IS_ERR(qqi->qqi_slv_obj)) {
99 lu_object_put(env, &qqi->qqi_slv_obj->do_lu);
100 qqi->qqi_slv_obj = NULL;
101 qqi->qqi_slv_ver = 0;
104 /* release global index */
105 if (qqi->qqi_glb_obj != NULL && !IS_ERR(qqi->qqi_glb_obj)) {
106 lu_object_put(env, &qqi->qqi_glb_obj->do_lu);
107 qqi->qqi_glb_obj = NULL;
108 qqi->qqi_glb_ver = 0;
116 * Allocate and initialize a qsd_qtype_info structure for quota type \qtype.
117 * This opens the accounting object and initializes the proc file.
118 * It's called on OSD start when the qsd instance is created.
120 * \param env - the environment passed by the caller
121 * \param qsd - is the qsd instance which will be in charge of the new
122 * qsd_qtype_info instance.
123 * \param qtype - is quota type to set up
125 * \retval - 0 on success and qsd->qsd_type_array[qtype] is allocated,
126 * appropriate error on failure
128 static int qsd_qtype_init(const struct lu_env *env, struct qsd_instance *qsd,
131 struct qsd_qtype_info *qqi;
133 struct obd_uuid uuid;
136 LASSERT(qsd->qsd_type_array[qtype] == NULL);
138 /* allocate structure for this quota type */
142 qsd->qsd_type_array[qtype] = qqi;
144 /* set backpointer and other parameters */
146 qqi->qqi_qtype = qtype;
147 lquota_generate_fid(&qqi->qqi_fid, qsd->qsd_pool_id, QSD_RES_TYPE(qsd),
150 /* open accounting object */
151 LASSERT(qqi->qqi_acct_obj == NULL);
152 qqi->qqi_acct_obj = acct_obj_lookup(env, qsd->qsd_dev,
153 qtype == USRQUOTA ? ACCT_USER_OID
155 /* don't print any error message on failure in order not to confuse
156 * non-OFD user (e.g. 2.3 MDT stack) */
157 if (IS_ERR(qqi->qqi_acct_obj))
158 qqi->qqi_acct_obj = NULL;
160 /* open global index copy */
161 LASSERT(qqi->qqi_glb_obj == NULL);
162 qqi->qqi_glb_obj = lquota_disk_glb_find_create(env, qsd->qsd_dev,
164 &qqi->qqi_fid, true);
165 if (IS_ERR(qqi->qqi_glb_obj)) {
166 CERROR("%s: can't open global index copy "DFID" %ld\n",
167 qsd->qsd_svname, PFID(&qqi->qqi_fid),
168 PTR_ERR(qqi->qqi_glb_obj));
169 GOTO(out, rc = PTR_ERR(qqi->qqi_glb_obj));
171 qqi->qqi_glb_ver = dt_version_get(env, qqi->qqi_glb_obj);
173 /* open slave index copy */
174 LASSERT(qqi->qqi_slv_obj == NULL);
175 obd_str2uuid(&uuid, qsd->qsd_svname);
176 qqi->qqi_slv_obj = lquota_disk_slv_find_create(env, qsd->qsd_dev,
178 &qqi->qqi_fid, &uuid,
180 if (IS_ERR(qqi->qqi_slv_obj)) {
181 CERROR("%s: can't open slave index copy "DFID" %ld\n",
182 qsd->qsd_svname, PFID(&qqi->qqi_fid),
183 PTR_ERR(qqi->qqi_slv_obj));
184 GOTO(out, rc = PTR_ERR(qqi->qqi_slv_obj));
186 qqi->qqi_slv_ver = dt_version_get(env, qqi->qqi_slv_obj);
188 /* register proc entry for accounting object */
189 rc = lprocfs_seq_create(qsd->qsd_proc,
190 qtype == USRQUOTA ? "acct_user" : "acct_group",
191 0444, &lprocfs_quota_seq_fops,
194 CWARN("%s: can't add procfs entry for accounting file %d\n",
195 qsd->qsd_svname, rc);
202 qsd_qtype_fini(env, qsd, qtype);
207 * Release a qsd_instance. Companion of qsd_init(). This releases all data
208 * structures associated with the quota slave.
209 * This function should be called when the OSD is shutting down.
211 * \param env - is the environment passed by the caller
212 * \param qsd - is the qsd instance to shutdown
214 void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd)
219 CDEBUG(D_QUOTA, "%s: initiating QSD shutdown\n", qsd->qsd_svname);
220 qsd->qsd_stopping = true;
222 /* remove qsd proc entry */
223 if (qsd->qsd_proc != NULL && !IS_ERR(qsd->qsd_proc)) {
224 lprocfs_remove(&qsd->qsd_proc);
225 qsd->qsd_proc = NULL;
228 /* free per-quota type data */
229 for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++)
230 qsd_qtype_fini(env, qsd, qtype);
232 /* release quota root directory */
233 if (qsd->qsd_root != NULL && !IS_ERR(qsd->qsd_root)) {
234 lu_object_put(env, &qsd->qsd_root->do_lu);
235 qsd->qsd_root = NULL;
238 /* release reference on dt_device */
239 if (qsd->qsd_dev != NULL) {
240 lu_ref_del(&qsd->qsd_dev->dd_lu_dev.ld_reference, "qsd", qsd);
241 lu_device_put(&qsd->qsd_dev->dd_lu_dev);
248 EXPORT_SYMBOL(qsd_fini);
251 * Create a new qsd_instance to be associated with backend osd device
252 * identified by \dev. For now, this function just create procfs files which
253 * dumps the accounting information
255 * \param env - the environment passed by the caller
256 * \param svname - is the service name of the OSD device creating this instance
257 * \param dev - is the dt_device where to store quota index files
258 * \param osd_proc - is the procfs parent directory where to create procfs file
259 * related to this new qsd instance
261 * \retval - pointer to new qsd_instance associated with dev \dev on success,
262 * appropriate error on failure
264 struct qsd_instance *qsd_init(const struct lu_env *env, char *svname,
265 struct dt_device *dev,
266 cfs_proc_dir_entry_t *osd_proc)
268 struct qsd_instance *qsd;
272 /* allocate qsd instance */
275 RETURN(ERR_PTR(-ENOMEM));
277 /* copy service name */
278 strncpy(qsd->qsd_svname, svname, MAX_OBD_NAME);
280 /* grab reference on osd device */
281 lu_device_get(&dev->dd_lu_dev);
282 lu_ref_add(&dev->dd_lu_dev.ld_reference, "qsd", qsd);
285 /* we only support pool ID 0 (default data or metadata pool) for the
286 * time being. A different pool ID could be assigned to this target via
287 * the configuration log in the future */
288 qsd->qsd_pool_id = 0;
290 /* Record whether this qsd instance is managing quota enforcement for a
291 * MDT (i.e. inode quota) or OST (block quota) */
292 qsd->qsd_is_md = lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev);
294 /* look-up on-disk directory for the quota slave */
295 qsd->qsd_root = lquota_disk_dir_find_create(env, dev, NULL, QSD_DIR);
296 if (IS_ERR(qsd->qsd_root)) {
297 rc = PTR_ERR(qsd->qsd_root);
298 CERROR("%s: failed to create quota slave root dir (%d)\n",
303 /* register procfs directory */
304 qsd->qsd_proc = lprocfs_register(QSD_DIR, osd_proc,
305 lprocfs_quota_qsd_vars, qsd);
306 if (IS_ERR(qsd->qsd_proc)) {
307 rc = PTR_ERR(qsd->qsd_proc);
308 CERROR("%s: fail to create quota slave proc entry (%d)\n",
313 /* initialize per-quota type data */
314 for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++) {
315 rc = qsd_qtype_init(env, qsd, qtype);
326 EXPORT_SYMBOL(qsd_init);
329 * Global initialization performed at module load time
331 int qsd_glb_init(void)
333 qsd_key_init_generic(&qsd_thread_key, NULL);
334 lu_context_key_register(&qsd_thread_key);
339 * Companion of qsd_glb_init() called at module unload time
341 void qsd_glb_fini(void)
343 lu_context_key_degister(&qsd_thread_key);