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 Intel, Inc.
25 * Use is subject to license terms.
27 * Author: Johann Lombardi <johann.lombardi@intel.com>
28 * Author: Niu Yawei <yawei.niu@intel.com>
32 * Management of the device associated with a Quota Master Target (QMT).
34 * The QMT holds the cluster wide quota limits. It stores the quota settings
35 * ({hard,soft} limit & grace time) in a global index file and is in charge
36 * of allocating quota space to slaves while guaranteeing that the overall
37 * limits aren't exceeded. The QMT also maintains one index per slave (in fact,
38 * one per slave per quota type) used to track how much space is allocated
39 * to a given slave. Now that the QMT is aware of the quota space distribution
40 * among slaves, it can afford to rebalance efficiently quota space from one
41 * slave to another. Slaves are asked to release quota space via glimpse
42 * callbacks sent on DLM locks which are granted to slaves when those latters
43 * acquire quota space.
45 * The QMT device is currently set up by the MDT and should probably be moved
46 * to a separate target in the future. Meanwhile, the MDT forwards all quota
47 * requests to the QMT via a list of request handlers (see struct qmt_handlers
48 * in lquota.h). The QMT also borrows the LDLM namespace from the MDT.
50 * To bring up a QMT device, the following steps must be completed:
52 * - call ->ldto_device_alloc to allocate the QMT device and perform basic
53 * initialization like connecting to the backend OSD device or setting up the
54 * default pools and the QMT procfs directory.
56 * - the MDT can then connect to the QMT instance via legacy obd_connect path.
58 * - once the MDT stack has been fully configured, ->ldto_prepare must be called
59 * to configure on-disk objects associated with this master target.
61 * To shutdown a QMT device, the MDT just has to disconnect from the QMT.
63 * The qmt_device_type structure is registered when the lquota module is
64 * loaded and all the steps described above are automatically done when the MDT
65 * set up the Quota Master Target via calls to class_attach/class_setup, see
66 * mdt_quota_init() for more details.
70 # define EXPORT_SYMTAB
73 #define DEBUG_SUBSYSTEM S_LQUOTA
75 #include <obd_class.h>
76 #include <lprocfs_status.h>
77 #include <lustre_disk.h>
78 #include "qmt_internal.h"
80 static const struct lu_device_operations qmt_lu_ops;
83 * Release quota master target and all data structure associated with this
85 * Called on MDT0 cleanup.
87 * \param env - is the environment passed by the caller
88 * \param ld - is the lu_device associated with the qmt device to be released
90 * \retval - NULL on success (backend OSD device is managed by the main stack),
91 * appropriate error on failure
93 static struct lu_device *qmt_device_fini(const struct lu_env *env,
96 struct qmt_device *qmt = lu2qmt_dev(ld);
101 CDEBUG(D_QUOTA, "%s: initiating QMT shutdown\n", qmt->qmt_svname);
103 /* disconnect from OSD */
104 if (qmt->qmt_child_exp != NULL) {
105 obd_disconnect(qmt->qmt_child_exp);
106 qmt->qmt_child_exp = NULL;
107 qmt->qmt_child = NULL;
114 * Connect a quota master to the backend OSD device.
116 * \param env - is the environment passed by the caller
117 * \param qmt - is the quota master target to be connected
118 * \param cfg - is the configuration log record from which we need to extract
119 * the service name of the backend OSD device to connect to.
121 * \retval - 0 on success, appropriate error on failure
123 static int qmt_connect_to_osd(const struct lu_env *env, struct qmt_device *qmt,
124 struct lustre_cfg *cfg)
126 struct obd_connect_data *data = NULL;
127 struct obd_device *obd;
128 struct lu_device *ld = qmt2lu_dev(qmt);
132 LASSERT(qmt->qmt_child_exp == NULL);
136 GOTO(out, rc = -ENOMEM);
138 /* look-up OBD device associated with the backend OSD device.
139 * The MDT is kind enough to pass the OBD name in QMT configuration */
140 obd = class_name2obd(lustre_cfg_string(cfg, 3));
142 CERROR("%s: can't locate backend osd device: %s\n",
143 qmt->qmt_svname, lustre_cfg_string(cfg, 3));
144 GOTO(out, rc = -ENOTCONN);
147 data->ocd_connect_flags = OBD_CONNECT_VERSION;
148 data->ocd_version = LUSTRE_VERSION_CODE;
150 /* connect to OSD device */
151 rc = obd_connect(NULL, &qmt->qmt_child_exp, obd, &obd->obd_uuid, data,
154 CERROR("%s: cannot connect to osd dev %s (%d)\n",
155 qmt->qmt_svname, obd->obd_name, rc);
159 /* initialize site (although it isn't used anywhere) and lu_device
160 * pointer to next device */
161 qmt->qmt_child = lu2dt_dev(qmt->qmt_child_exp->exp_obd->obd_lu_dev);
162 ld->ld_site = qmt->qmt_child_exp->exp_obd->obd_lu_dev->ld_site;
171 * Initialize quota master target device. This includers connecting to
172 * the backend OSD device, initializing the pool configuration and creating the
173 * root procfs directory dedicated to this quota target.
174 * The rest of the initialization is done when the stack is fully configured
175 * (i.e. when ->ldo_start is called across the stack).
177 * This function is called on MDT0 setup.
179 * \param env - is the environment passed by the caller
180 * \param qmt - is the quota master target to be initialized
181 * \param ldt - is the device type structure associated with the qmt device
182 * \param cfg - is the configuration record used to configure the qmt device
184 * \retval - 0 on success, appropriate error on failure
186 static int qmt_device_init0(const struct lu_env *env, struct qmt_device *qmt,
187 struct lu_device_type *ldt, struct lustre_cfg *cfg)
189 struct lu_device *ld = qmt2lu_dev(qmt);
190 struct obd_device *obd;
194 /* record who i am, it might be useful ... */
195 strncpy(qmt->qmt_svname, lustre_cfg_string(cfg, 0),
196 sizeof(qmt->qmt_svname) - 1);
198 /* look-up the obd_device associated with the qmt */
199 obd = class_name2obd(qmt->qmt_svname);
203 /* reference each other */
204 obd->obd_lu_dev = ld;
207 /* connect to backend osd device */
208 rc = qmt_connect_to_osd(env, qmt, cfg);
215 qmt_device_fini(env, ld);
220 * Free quota master target device. Companion of qmt_device_alloc()
222 * \param env - is the environment passed by the caller
223 * \param ld - is the lu_device associated with the qmt dev to be freed
225 * \retval - NULL on success (backend OSD device is managed by the main stack),
226 * appropriate error on failure
228 static struct lu_device *qmt_device_free(const struct lu_env *env,
229 struct lu_device *ld)
231 struct qmt_device *qmt = lu2qmt_dev(ld);
234 LASSERT(qmt != NULL);
242 * Allocate quota master target and initialize it.
244 * \param env - is the environment passed by the caller
245 * \param ldt - is the device type structure associated with the qmt
246 * \param cfg - is the configuration record used to configure the qmt
248 * \retval - lu_device structure associated with the qmt on success,
249 * appropriate error on failure
251 static struct lu_device *qmt_device_alloc(const struct lu_env *env,
252 struct lu_device_type *ldt,
253 struct lustre_cfg *cfg)
255 struct qmt_device *qmt;
256 struct lu_device *ld;
260 /* allocate qmt device */
263 RETURN(ERR_PTR(-ENOMEM));
265 /* configure lu/dt_device */
266 ld = qmt2lu_dev(qmt);
267 dt_device_init(&qmt->qmt_dt_dev, ldt);
268 ld->ld_ops = &qmt_lu_ops;
270 /* initialize qmt device */
271 rc = qmt_device_init0(env, qmt, ldt, cfg);
273 qmt_device_free(env, ld);
280 LU_KEY_INIT_FINI(qmt, struct qmt_thread_info);
281 LU_TYPE_INIT_FINI(qmt, &qmt_thread_key);
282 LU_CONTEXT_KEY_DEFINE(qmt, LCT_MD_THREAD);
285 * lu device type operations associated with the master target.
287 static struct lu_device_type_operations qmt_device_type_ops = {
288 .ldto_init = qmt_type_init,
289 .ldto_fini = qmt_type_fini,
291 .ldto_start = qmt_type_start,
292 .ldto_stop = qmt_type_stop,
294 .ldto_device_alloc = qmt_device_alloc,
295 .ldto_device_free = qmt_device_free,
297 .ldto_device_fini = qmt_device_fini,
301 * lu device type structure associated with the master target.
302 * MDT0 uses this structure to configure the qmt.
304 static struct lu_device_type qmt_device_type = {
305 .ldt_tags = LU_DEVICE_DT,
306 .ldt_name = LUSTRE_QMT_NAME,
307 .ldt_ops = &qmt_device_type_ops,
308 .ldt_ctx_tags = LCT_MD_THREAD,
312 * obd_connect handler used by the MDT to connect to the master target.
314 static int qmt_device_obd_connect(const struct lu_env *env,
315 struct obd_export **exp,
316 struct obd_device *obd,
317 struct obd_uuid *cluuid,
318 struct obd_connect_data *data,
321 struct lustre_handle conn;
325 rc = class_connect(&conn, obd, cluuid);
329 *exp = class_conn2export(&conn);
334 * obd_disconnect handler used by the MDT to disconnect from the master target.
335 * We trigger cleanup on disconnect since it means that the MDT is about to
338 static int qmt_device_obd_disconnect(struct obd_export *exp)
340 struct obd_device *obd = exp->exp_obd;
344 rc = class_disconnect(exp);
348 rc = class_manual_cleanup(obd);
353 * obd device operations associated with the master target.
355 struct obd_ops qmt_obd_ops = {
356 .o_owner = THIS_MODULE,
357 .o_connect = qmt_device_obd_connect,
358 .o_disconnect = qmt_device_obd_disconnect,
362 * Called when the MDS is fully configured. We use it to set up local objects
363 * associated with the quota master target.
365 * \param env - is the environment passed by the caller
366 * \param parent - is the lu_device of the parent, that's to say the mdt
367 * \param ld - is the lu_device associated with the master target
369 * \retval - 0 on success, appropriate error on failure
371 static int qmt_device_prepare(const struct lu_env *env,
372 struct lu_device *parent,
373 struct lu_device *ld)
379 * lu device operations for the quota master target
381 static const struct lu_device_operations qmt_lu_ops = {
382 .ldo_prepare = qmt_device_prepare,
383 .ldo_process_config = NULL, /* to be defined for dynamic pool
387 /* global variable initialization called when the lquota module is loaded */
388 int qmt_glb_init(void)
393 rc = class_register_type(&qmt_obd_ops, NULL, NULL, LUSTRE_QMT_NAME,
398 /* called when the lquota module is about to be unloaded */
399 void qmt_glb_fini(void)
401 class_unregister_type(LUSTRE_QMT_NAME);