Whamcloud - gitweb
e165ae713960f890048ac21a89308997f10c8140
[fs/lustre-release.git] / lustre / quota / qmt_dev.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 /*
32  * Management of the device associated with a Quota Master Target (QMT).
33  *
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.
44  *
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.
49  *
50  * To bring up a QMT device, the following steps must be completed:
51  *
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.
55  *
56  * - the MDT can then connect to the QMT instance via legacy obd_connect path.
57  *
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.
60  *
61  * To shutdown a QMT device, the MDT just has to disconnect from the QMT.
62  *
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.
67  */
68
69 #ifndef EXPORT_SYMTAB
70 # define EXPORT_SYMTAB
71 #endif
72
73 #define DEBUG_SUBSYSTEM S_LQUOTA
74
75 #include <obd_class.h>
76 #include <lprocfs_status.h>
77 #include <lustre_disk.h>
78 #include "qmt_internal.h"
79
80 static const struct lu_device_operations qmt_lu_ops;
81
82 /*
83  * Release quota master target and all data structure associated with this
84  * target.
85  * Called on MDT0 cleanup.
86  *
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
89  *
90  * \retval - NULL on success (backend OSD device is managed by the main stack),
91  *           appropriate error on failure
92  */
93 static struct lu_device *qmt_device_fini(const struct lu_env *env,
94                                          struct lu_device *ld)
95 {
96         struct qmt_device       *qmt = lu2qmt_dev(ld);
97         ENTRY;
98
99         LASSERT(qmt != NULL);
100
101         CDEBUG(D_QUOTA, "%s: initiating QMT shutdown\n", qmt->qmt_svname);
102
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;
108         }
109
110         RETURN(NULL);
111 }
112
113 /*
114  * Connect a quota master to the backend OSD device.
115  *
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.
120  *
121  * \retval - 0 on success, appropriate error on failure
122  */
123 static int qmt_connect_to_osd(const struct lu_env *env, struct qmt_device *qmt,
124                               struct lustre_cfg *cfg)
125 {
126         struct obd_connect_data *data = NULL;
127         struct obd_device       *obd;
128         struct lu_device        *ld = qmt2lu_dev(qmt);
129         int                      rc;
130         ENTRY;
131
132         LASSERT(qmt->qmt_child_exp == NULL);
133
134         OBD_ALLOC_PTR(data);
135         if (data == NULL)
136                 GOTO(out, rc = -ENOMEM);
137
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));
141         if (obd == NULL) {
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);
145         }
146
147         data->ocd_connect_flags = OBD_CONNECT_VERSION;
148         data->ocd_version = LUSTRE_VERSION_CODE;
149
150         /* connect to OSD device */
151         rc = obd_connect(NULL, &qmt->qmt_child_exp, obd, &obd->obd_uuid, data,
152                          NULL);
153         if (rc) {
154                 CERROR("%s: cannot connect to osd dev %s (%d)\n",
155                        qmt->qmt_svname, obd->obd_name, rc);
156                 GOTO(out, rc);
157         }
158
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;
163         EXIT;
164 out:
165         if (data)
166                 OBD_FREE_PTR(data);
167         return rc;
168 }
169
170 /*
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).
176  *
177  * This function is called on MDT0 setup.
178  *
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
183  *
184  * \retval - 0 on success, appropriate error on failure
185  */
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)
188 {
189         struct lu_device        *ld = qmt2lu_dev(qmt);
190         struct obd_device       *obd;
191         int                      rc;
192         ENTRY;
193
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);
197
198         /* look-up the obd_device associated with the qmt */
199         obd = class_name2obd(qmt->qmt_svname);
200         if (obd == NULL)
201                 RETURN(-ENOENT);
202
203         /* reference each other */
204         obd->obd_lu_dev = ld;
205         ld->ld_obd      = obd;
206
207         /* connect to backend osd device */
208         rc = qmt_connect_to_osd(env, qmt, cfg);
209         if (rc)
210                 GOTO(out, rc);
211
212         EXIT;
213 out:
214         if (rc)
215                 qmt_device_fini(env, ld);
216         return rc;
217 }
218
219 /*
220  * Free quota master target device. Companion of qmt_device_alloc()
221  *
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
224  *
225  * \retval - NULL on success (backend OSD device is managed by the main stack),
226  *           appropriate error on failure
227  */
228 static struct lu_device *qmt_device_free(const struct lu_env *env,
229                                          struct lu_device *ld)
230 {
231         struct qmt_device       *qmt = lu2qmt_dev(ld);
232         ENTRY;
233
234         LASSERT(qmt != NULL);
235
236         lu_device_fini(ld);
237         OBD_FREE_PTR(qmt);
238         RETURN(NULL);
239 }
240
241 /*
242  * Allocate quota master target and initialize it.
243  *
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
247  *
248  * \retval - lu_device structure associated with the qmt on success,
249  *           appropriate error on failure
250  */
251 static struct lu_device *qmt_device_alloc(const struct lu_env *env,
252                                           struct lu_device_type *ldt,
253                                           struct lustre_cfg *cfg)
254 {
255         struct qmt_device       *qmt;
256         struct lu_device        *ld;
257         int                      rc;
258         ENTRY;
259
260         /* allocate qmt device */
261         OBD_ALLOC_PTR(qmt);
262         if (qmt == NULL)
263                 RETURN(ERR_PTR(-ENOMEM));
264
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;
269
270         /* initialize qmt device */
271         rc = qmt_device_init0(env, qmt, ldt, cfg);
272         if (rc != 0) {
273                 qmt_device_free(env, ld);
274                 RETURN(ERR_PTR(rc));
275         }
276
277         RETURN(ld);
278 }
279
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);
283
284 /*
285  * lu device type operations associated with the master target.
286  */
287 static struct lu_device_type_operations qmt_device_type_ops = {
288         .ldto_init              = qmt_type_init,
289         .ldto_fini              = qmt_type_fini,
290
291         .ldto_start             = qmt_type_start,
292         .ldto_stop              = qmt_type_stop,
293
294         .ldto_device_alloc      = qmt_device_alloc,
295         .ldto_device_free       = qmt_device_free,
296
297         .ldto_device_fini       = qmt_device_fini,
298 };
299
300 /*
301  * lu device type structure associated with the master target.
302  * MDT0 uses this structure to configure the qmt.
303  */
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,
309 };
310
311 /*
312  * obd_connect handler used by the MDT to connect to the master target.
313  */
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,
319                                   void *localdata)
320 {
321         struct lustre_handle    conn;
322         int                     rc;
323         ENTRY;
324
325         rc = class_connect(&conn, obd, cluuid);
326         if (rc)
327                 RETURN(rc);
328
329         *exp = class_conn2export(&conn);
330         RETURN(0);
331 }
332
333 /*
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
336  * shutdown.
337  */
338 static int qmt_device_obd_disconnect(struct obd_export *exp)
339 {
340         struct obd_device       *obd = exp->exp_obd;
341         int                      rc;
342         ENTRY;
343
344         rc = class_disconnect(exp);
345         if (rc)
346                 RETURN(rc);
347
348         rc = class_manual_cleanup(obd);
349         RETURN(0);
350 }
351
352 /*
353  * obd device operations associated with the master target.
354  */
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,
359 };
360
361 /*
362  * Called when the MDS is fully configured. We use it to set up local objects
363  * associated with the quota master target.
364  *
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
368  *
369  * \retval    - 0 on success, appropriate error on failure
370  */
371 static int qmt_device_prepare(const struct lu_env *env,
372                               struct lu_device *parent,
373                               struct lu_device *ld)
374 {
375         return 0;
376 }
377
378 /*
379  * lu device operations for the quota master target
380  */
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
384                                          * configuration */
385 };
386
387 /* global variable initialization called when the lquota module is loaded */
388 int qmt_glb_init(void)
389 {
390         int rc;
391         ENTRY;
392
393         rc = class_register_type(&qmt_obd_ops, NULL, NULL, LUSTRE_QMT_NAME,
394                                  &qmt_device_type);
395         RETURN(rc);
396 }
397
398 /* called when the lquota module is about to be unloaded */
399 void qmt_glb_fini(void)
400 {
401         class_unregister_type(LUSTRE_QMT_NAME);
402 }