Whamcloud - gitweb
LU-3963 libcfs: convert ptlrpc,quota plus others to linux atomics
[fs/lustre-release.git] / lustre / quota / qmt_pool.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 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 /*
32  * A Quota Master Target has a hash table where it stores qmt_pool_info
33  * structures. There is one such structure for each pool managed by the QMT.
34  *
35  * Each pool can have different quota types enforced (typically user & group
36  * quota). A pool is in charge of managing lquota_entry structures for each
37  * quota type. This is done by creating one lquota_entry site per quota
38  * type. A site stores entries in a hash table and read quota settings from disk
39  * when a given ID isn't present in the hash.
40  *
41  * The pool API exported here is the following:
42  * - qmt_pool_init(): initializes the general QMT structures used to manage
43  *                    pools.
44  * - qmt_pool_fini(): frees the structures allocated by qmt_pool_fini().
45  * - qmt_pool_prepare(): sets up the on-disk indexes associated with each pool.
46  * - qmt_pool_new_conn(): is used to create a new slave index file.
47  * - qmt_pool_lqe_lookup(): returns an up-to-date lquota entry associated with
48  *                          a given ID.
49  */
50
51 #define DEBUG_SUBSYSTEM S_LQUOTA
52
53 #include <obd_class.h>
54 #include <lprocfs_status.h>
55 #include "qmt_internal.h"
56
57 static void qmt_pool_free(const struct lu_env *, struct qmt_pool_info *);
58
59 /*
60  * Static helper functions not used outside the scope of this file
61  */
62
63 /*
64  * Reference counter management for qmt_pool_info structures
65  */
66 static inline void qpi_getref(struct qmt_pool_info *pool)
67 {
68         atomic_inc(&pool->qpi_ref);
69 }
70
71 static inline void qpi_putref(const struct lu_env *env,
72                               struct qmt_pool_info *pool)
73 {
74         LASSERT(atomic_read(&pool->qpi_ref) > 0);
75         if (atomic_dec_and_test(&pool->qpi_ref))
76                 qmt_pool_free(env, pool);
77 }
78
79 static inline void qpi_putref_locked(struct qmt_pool_info *pool)
80 {
81         LASSERT(atomic_read(&pool->qpi_ref) > 1);
82         atomic_dec(&pool->qpi_ref);
83 }
84
85 /*
86  * Hash functions for qmt_pool_info management
87  */
88
89 static unsigned qpi_hash_hash(cfs_hash_t *hs, const void *key, unsigned mask)
90 {
91         return cfs_hash_u32_hash(*((__u32 *)key), mask);
92 }
93
94 static void *qpi_hash_key(cfs_hlist_node_t *hnode)
95 {
96         struct qmt_pool_info *pool;
97         pool = cfs_hlist_entry(hnode, struct qmt_pool_info, qpi_hash);
98         return &pool->qpi_key;
99 }
100
101 static int qpi_hash_keycmp(const void *key, cfs_hlist_node_t *hnode)
102 {
103         struct qmt_pool_info *pool;
104         pool = cfs_hlist_entry(hnode, struct qmt_pool_info, qpi_hash);
105         return pool->qpi_key == *((__u32 *)key);
106 }
107
108 static void *qpi_hash_object(cfs_hlist_node_t *hnode)
109 {
110         return cfs_hlist_entry(hnode, struct qmt_pool_info, qpi_hash);
111 }
112
113 static void qpi_hash_get(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
114 {
115         struct qmt_pool_info *pool;
116         pool = cfs_hlist_entry(hnode, struct qmt_pool_info, qpi_hash);
117         qpi_getref(pool);
118 }
119
120 static void qpi_hash_put_locked(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
121 {
122         struct qmt_pool_info *pool;
123         pool = cfs_hlist_entry(hnode, struct qmt_pool_info, qpi_hash);
124         qpi_putref_locked(pool);
125 }
126
127 static void qpi_hash_exit(cfs_hash_t *hs, cfs_hlist_node_t *hnode)
128 {
129         CERROR("Should not have any item left!\n");
130 }
131
132 /* vector of hash operations */
133 static cfs_hash_ops_t qpi_hash_ops = {
134         .hs_hash        = qpi_hash_hash,
135         .hs_key         = qpi_hash_key,
136         .hs_keycmp      = qpi_hash_keycmp,
137         .hs_object      = qpi_hash_object,
138         .hs_get         = qpi_hash_get,
139         .hs_put_locked  = qpi_hash_put_locked,
140         .hs_exit        = qpi_hash_exit
141 };
142
143 /* some procfs helpers */
144 static int qpi_state_seq_show(struct seq_file *m, void *data)
145 {
146         struct qmt_pool_info    *pool = m->private;
147         int                      type;
148
149         LASSERT(pool != NULL);
150
151         seq_printf(m, "pool:\n"
152                    "    id: %u\n"
153                    "    type: %s\n"
154                    "    ref: %d\n"
155                    "    least qunit: %lu\n",
156                    pool->qpi_key & 0x0000ffff,
157                    RES_NAME(pool->qpi_key >> 16),
158                    atomic_read(&pool->qpi_ref),
159                    pool->qpi_least_qunit);
160
161         for (type = 0; type < MAXQUOTAS; type++)
162                 seq_printf(m, "    %s:\n"
163                            "        #slv: %d\n"
164                            "        #lqe: %d\n",
165                            QTYPE_NAME(type),
166                            pool->qpi_slv_nr[type],
167                     atomic_read(&pool->qpi_site[type]->lqs_hash->hs_count));
168
169         return 0;
170 }
171 LPROC_SEQ_FOPS_RO(qpi_state);
172
173 static struct lprocfs_seq_vars lprocfs_quota_qpi_vars[] = {
174         { .name =       "info",
175           .fops =       &qpi_state_fops },
176         { NULL }
177 };
178
179 /*
180  * Allocate a new qmt_pool_info structure and add it to the pool hash table
181  * of the qmt.
182  *
183  * \param env       - is the environment passed by the caller
184  * \param qmt       - is the quota master target
185  * \param pool_id   - is the 16-bit pool identifier of the new pool to add
186  * \param pool_type - is the resource type of this pool instance, either
187  *                    LQUOTA_RES_MD or LQUOTA_RES_DT.
188  *
189  * \retval - 0 on success, appropriate error on failure
190  */
191 static int qmt_pool_alloc(const struct lu_env *env, struct qmt_device *qmt,
192                           int pool_id, int pool_type)
193 {
194         struct qmt_thread_info  *qti = qmt_info(env);
195         struct qmt_pool_info    *pool;
196         int                      rc = 0;
197         ENTRY;
198
199         OBD_ALLOC_PTR(pool);
200         if (pool == NULL)
201                 RETURN(-ENOMEM);
202         CFS_INIT_LIST_HEAD(&pool->qpi_linkage);
203
204         /* assign key used by hash functions */
205         pool->qpi_key = pool_id + (pool_type << 16);
206
207         /* initialize refcount to 1, hash table will then grab an additional
208          * reference */
209         atomic_set(&pool->qpi_ref, 1);
210
211         /* set up least qunit size to use for this pool */
212         pool->qpi_least_qunit = LQUOTA_LEAST_QUNIT(pool_type);
213
214         /* create pool proc directory */
215         sprintf(qti->qti_buf, "%s-0x%x", RES_NAME(pool_type), pool_id);
216         pool->qpi_proc = lprocfs_seq_register(qti->qti_buf, qmt->qmt_proc,
217                                                 lprocfs_quota_qpi_vars, pool);
218         if (IS_ERR(pool->qpi_proc)) {
219                 rc = PTR_ERR(pool->qpi_proc);
220                 CERROR("%s: failed to create proc entry for pool %s (%d)\n",
221                        qmt->qmt_svname, qti->qti_buf, rc);
222                 pool->qpi_proc = NULL;
223                 GOTO(out, rc);
224         }
225
226         /* grab reference on master target that this pool belongs to */
227         lu_device_get(qmt2lu_dev(qmt));
228         lu_ref_add(&qmt2lu_dev(qmt)->ld_reference, "pool", pool);
229         pool->qpi_qmt = qmt;
230
231         /* add to qmt hash table */
232         rc = cfs_hash_add_unique(qmt->qmt_pool_hash, &pool->qpi_key,
233                                  &pool->qpi_hash);
234         if (rc) {
235                 CERROR("%s: failed to add pool %s to qmt hash (%d)\n",
236                        qmt->qmt_svname, qti->qti_buf, rc);
237                 GOTO(out, rc);
238         }
239
240         /* add to qmt pool list */
241         cfs_list_add_tail(&pool->qpi_linkage, &qmt->qmt_pool_list);
242         EXIT;
243 out:
244         if (rc)
245                 /* this frees the pool structure since refcount is equal to 1 */
246                 qpi_putref(env, pool);
247         return rc;
248 }
249
250 /*
251  * Delete a qmt_pool_info instance and all structures associated.
252  *
253  * \param env  - is the environment passed by the caller
254  * \param pool - is the qmt_pool_info structure to free
255  */
256 static void qmt_pool_free(const struct lu_env *env, struct qmt_pool_info *pool)
257 {
258         int     qtype;
259         ENTRY;
260
261         /* release proc entry */
262         if (pool->qpi_proc) {
263                 lprocfs_remove(&pool->qpi_proc);
264                 pool->qpi_proc = NULL;
265         }
266
267         /* release per-quota type site used to manage quota entries as well as
268          * references to global index files */
269         for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
270                 /* release lqe storing grace time */
271                 if (pool->qpi_grace_lqe[qtype] != NULL)
272                         lqe_putref(pool->qpi_grace_lqe[qtype]);
273
274                 /* release site */
275                 if (pool->qpi_site[qtype] != NULL &&
276                     !IS_ERR(pool->qpi_site[qtype]))
277                         lquota_site_free(env, pool->qpi_site[qtype]);
278                 /* release reference to global index */
279                 if (pool->qpi_glb_obj[qtype] != NULL &&
280                     !IS_ERR(pool->qpi_glb_obj[qtype]))
281                         lu_object_put(env, &pool->qpi_glb_obj[qtype]->do_lu);
282         }
283
284         /* release reference on pool directory */
285         if (pool->qpi_root != NULL && !IS_ERR(pool->qpi_root))
286                 lu_object_put(env, &pool->qpi_root->do_lu);
287
288         /* release reference on the master target */
289         if (pool->qpi_qmt != NULL) {
290                 struct lu_device *ld = qmt2lu_dev(pool->qpi_qmt);
291
292                 lu_device_put(ld);
293                 lu_ref_del(&ld->ld_reference, "pool", pool);
294                 pool->qpi_qmt = NULL;
295         }
296
297         LASSERT(cfs_list_empty(&pool->qpi_linkage));
298         OBD_FREE_PTR(pool);
299 }
300
301 /*
302  * Look-up a pool in the hash table based on the pool ID and type.
303  *
304  * \param env     - is the environment passed by the caller
305  * \param qmt     - is the quota master target
306  * \param pool_id   - is the 16-bit identifier of the pool to look up
307  * \param pool_type - is the type of this pool, either LQUOTA_RES_MD or
308  *                    LQUOTA_RES_DT.
309  */
310 static struct qmt_pool_info *qmt_pool_lookup(const struct lu_env *env,
311                                              struct qmt_device *qmt,
312                                              int pool_id, int pool_type)
313 {
314         struct qmt_pool_info    *pool;
315         __u32                    key;
316         ENTRY;
317
318         LASSERT(qmt->qmt_pool_hash != NULL);
319
320         /* look-up pool in hash table */
321         key = pool_id + (pool_type << 16);
322         pool = cfs_hash_lookup(qmt->qmt_pool_hash, (void *)&key);
323         if (pool == NULL) {
324                 /* this qmt isn't managing this pool! */
325                 CERROR("%s: looking up quota entry for a pool (0x%x/%d) which "
326                        "isn't managed by this quota master target\n",
327                        qmt->qmt_svname, pool_id, pool_type);
328                 RETURN(ERR_PTR(-ENOENT));
329         }
330         RETURN(pool);
331 }
332
333 /*
334  * Functions implementing the pool API, used by the qmt handlers
335  */
336
337 /*
338  * Destroy all pools which are still in the hash table and free the pool
339  * hash table.
340  *
341  * \param env - is the environment passed by the caller
342  * \param qmt - is the quota master target
343  *
344  */
345 void qmt_pool_fini(const struct lu_env *env, struct qmt_device *qmt)
346 {
347         struct qmt_pool_info    *pool;
348         cfs_list_t              *pos, *n;
349         ENTRY;
350
351         if (qmt->qmt_pool_hash == NULL)
352                 RETURN_EXIT;
353
354         /* parse list of pool and destroy each element */
355         cfs_list_for_each_safe(pos, n, &qmt->qmt_pool_list) {
356                 pool = cfs_list_entry(pos, struct qmt_pool_info,
357                                       qpi_linkage);
358                 /* remove from hash */
359                 cfs_hash_del(qmt->qmt_pool_hash, &pool->qpi_key,
360                              &pool->qpi_hash);
361
362                 /* remove from list */
363                 cfs_list_del_init(&pool->qpi_linkage);
364
365                 /* release extra reference taken in qmt_pool_alloc */
366                 qpi_putref(env, pool);
367         }
368         LASSERT(cfs_list_empty(&qmt->qmt_pool_list));
369
370         cfs_hash_putref(qmt->qmt_pool_hash);
371         qmt->qmt_pool_hash = NULL;
372         EXIT;
373 }
374
375 /*
376  * Initialize pool configure for the quota master target. For now, we only
377  * support the default data (i.e. all OSTs) and metadata (i.e. all the MDTs)
378  * pool which are instantiated in this function.
379  *
380  * \param env - is the environment passed by the caller
381  * \param qmt - is the quota master target for which we have to initializa the
382  *              pool configuration
383  *
384  * \retval - 0 on success, appropriate error on failure
385  */
386 int qmt_pool_init(const struct lu_env *env, struct qmt_device *qmt)
387 {
388         int     res, rc = 0;
389         ENTRY;
390
391         /* initialize pool hash table */
392         qmt->qmt_pool_hash = cfs_hash_create("POOL_HASH",
393                                              HASH_POOLS_CUR_BITS,
394                                              HASH_POOLS_MAX_BITS,
395                                              HASH_POOLS_BKT_BITS, 0,
396                                              CFS_HASH_MIN_THETA,
397                                              CFS_HASH_MAX_THETA,
398                                              &qpi_hash_ops,
399                                              CFS_HASH_DEFAULT);
400         if (qmt->qmt_pool_hash == NULL) {
401                 CERROR("%s: failed to create pool hash table\n",
402                        qmt->qmt_svname);
403                 RETURN(-ENOMEM);
404         }
405
406         /* initialize pool list */
407         CFS_INIT_LIST_HEAD(&qmt->qmt_pool_list);
408
409         /* Instantiate pool master for the default data and metadata pool (both
410          * have pool ID equals to 0).
411          * This code will have to be revisited once we support quota on
412          * non-default pools */
413         for (res = LQUOTA_FIRST_RES; res < LQUOTA_LAST_RES; res++) {
414                 rc = qmt_pool_alloc(env, qmt, 0, res);
415                 if (rc)
416                         break;
417         }
418
419         if (rc)
420                 qmt_pool_fini(env, qmt);
421
422         RETURN(rc);
423 }
424
425 static int qmt_slv_cnt(const struct lu_env *env, struct lu_fid *glb_fid,
426                        char *slv_name, struct lu_fid *slv_fid, void *arg)
427 {
428         int *nr = arg;
429
430         /* one more slave */
431         (*nr)++;
432
433         return 0;
434 }
435
436 /*
437  * Set up on-disk index files associated with each pool.
438  *
439  * \param env - is the environment passed by the caller
440  * \param qmt - is the quota master target for which we have to initializa the
441  *              pool configuration
442  * \param qmt_root - is the on-disk directory created for the QMT.
443  *
444  * \retval - 0 on success, appropriate error on failure
445  */
446 int qmt_pool_prepare(const struct lu_env *env, struct qmt_device *qmt,
447                      struct dt_object *qmt_root)
448 {
449         struct qmt_thread_info  *qti = qmt_info(env);
450         struct lquota_glb_rec   *rec = &qti->qti_glb_rec;
451         struct qmt_pool_info    *pool;
452         struct dt_device        *dev = NULL;
453         dt_obj_version_t         version;
454         cfs_list_t              *pos;
455         int                      rc = 0, qtype;
456         ENTRY;
457
458         LASSERT(qmt->qmt_pool_hash != NULL);
459
460         /* iterate over each pool in the hash and allocate a quota site for each
461          * one. This involves creating a global index file on disk */
462         cfs_list_for_each(pos, &qmt->qmt_pool_list) {
463                 struct dt_object        *obj;
464                 int                      pool_type, pool_id;
465                 struct lquota_entry     *lqe;
466
467                 pool = cfs_list_entry(pos, struct qmt_pool_info,
468                                       qpi_linkage);
469
470                 pool_id   = pool->qpi_key & 0x0000ffff;
471                 pool_type = pool->qpi_key >> 16;
472                 if (dev == NULL)
473                         dev = pool->qpi_qmt->qmt_child;
474
475                 /* allocate directory for this pool */
476                 sprintf(qti->qti_buf, "%s-0x%x", RES_NAME(pool_type), pool_id);
477                 obj = lquota_disk_dir_find_create(env, qmt->qmt_child, qmt_root,
478                                                   qti->qti_buf);
479                 if (IS_ERR(obj))
480                         RETURN(PTR_ERR(obj));
481                 pool->qpi_root = obj;
482
483                 for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
484                         /* Generating FID of global index in charge of storing
485                          * settings for this quota type */
486                         lquota_generate_fid(&qti->qti_fid, pool_id, pool_type,
487                                             qtype);
488
489                         /* open/create the global index file for this quota
490                          * type */
491                         obj = lquota_disk_glb_find_create(env, dev,
492                                                           pool->qpi_root,
493                                                           &qti->qti_fid, false);
494                         if (IS_ERR(obj)) {
495                                 rc = PTR_ERR(obj);
496                                 CERROR("%s: failed to create glb index copy for"
497                                        " %s type (%d)\n", qmt->qmt_svname,
498                                        QTYPE_NAME(qtype), rc);
499                                 RETURN(rc);
500                         }
501
502                         pool->qpi_glb_obj[qtype] = obj;
503
504                         version = dt_version_get(env, obj);
505                         /* set default grace time for newly created index */
506                         if (version == 0) {
507                                 rec->qbr_hardlimit = 0;
508                                 rec->qbr_softlimit = 0;
509                                 rec->qbr_granted = 0;
510                                 rec->qbr_time = pool_type == LQUOTA_RES_MD ?
511                                         MAX_IQ_TIME : MAX_DQ_TIME;
512
513                                 rc = lquota_disk_write_glb(env, obj, 0, rec);
514                                 if (rc) {
515                                         CERROR("%s: failed to set default "
516                                                "grace time for %s type (%d)\n",
517                                                qmt->qmt_svname,
518                                                QTYPE_NAME(qtype), rc);
519                                         RETURN(rc);
520                                 }
521
522                                 rc = lquota_disk_update_ver(env, dev, obj, 1);
523                                 if (rc) {
524                                         CERROR("%s: failed to set initial "
525                                                "version for %s type (%d)\n",
526                                                qmt->qmt_svname,
527                                                QTYPE_NAME(qtype), rc);
528                                         RETURN(rc);
529                                 }
530                         }
531
532                         /* create quota entry site for this quota type */
533                         pool->qpi_site[qtype] = lquota_site_alloc(env, pool,
534                                                                   true, qtype,
535                                                                   &qmt_lqe_ops);
536                         if (IS_ERR(pool->qpi_site[qtype])) {
537                                 rc = PTR_ERR(pool->qpi_site[qtype]);
538                                 CERROR("%s: failed to create site for %s type "
539                                        "(%d)\n", qmt->qmt_svname,
540                                        QTYPE_NAME(qtype), rc);
541                                 RETURN(rc);
542                         }
543
544                         /* count number of slaves which already connected to
545                          * the master in the past */
546                         pool->qpi_slv_nr[qtype] = 0;
547                         rc = lquota_disk_for_each_slv(env, pool->qpi_root,
548                                                       &qti->qti_fid,
549                                                       qmt_slv_cnt,
550                                                       &pool->qpi_slv_nr[qtype]);
551                         if (rc) {
552                                 CERROR("%s: failed to scan & count slave "
553                                        "indexes for %s type (%d)\n",
554                                        qmt->qmt_svname, QTYPE_NAME(qtype), rc);
555                                 RETURN(rc);
556                         }
557
558                         /* Global grace time is stored in quota settings of
559                          * ID 0. */
560                         qti->qti_id.qid_uid = 0;
561
562                         /* look-up quota entry storing grace time */
563                         lqe = lqe_locate(env, pool->qpi_site[qtype],
564                                          &qti->qti_id);
565                         if (IS_ERR(lqe))
566                                 RETURN(PTR_ERR(lqe));
567                         pool->qpi_grace_lqe[qtype] = lqe;
568 #ifdef LPROCFS
569                         /* add procfs file to dump the global index, mostly for
570                          * debugging purpose */
571                         sprintf(qti->qti_buf, "glb-%s", QTYPE_NAME(qtype));
572                         rc = lprocfs_seq_create(pool->qpi_proc, qti->qti_buf,
573                                                 0444, &lprocfs_quota_seq_fops,
574                                                 obj);
575                         if (rc)
576                                 CWARN("%s: Error adding procfs file for global"
577                                       "quota index "DFID", rc:%d\n",
578                                       qmt->qmt_svname, PFID(&qti->qti_fid), rc);
579 #endif
580                 }
581         }
582
583         RETURN(0);
584 }
585
586 /*
587  * Handle new slave connection. Called when a slave enqueues the global quota
588  * lock at the beginning of the reintegration procedure.
589  *
590  * \param env - is the environment passed by the caller
591  * \parap qmt - is the quota master target handling this request
592  * \param glb_fid - is the fid of the global index file
593  * \param slv_fid - is the fid of the newly created slave index file
594  * \param slv_ver - is the current version of the slave index file
595  * \param uuid    - is the uuid of slave which is (re)connecting to the master
596  *                  target
597  *
598  * \retval - 0 on success, appropriate error on failure
599  */
600 int qmt_pool_new_conn(const struct lu_env *env, struct qmt_device *qmt,
601                       struct lu_fid *glb_fid, struct lu_fid *slv_fid,
602                       __u64 *slv_ver, struct obd_uuid *uuid)
603 {
604         struct qmt_pool_info    *pool;
605         struct dt_object        *slv_obj;
606         int                      pool_id, pool_type, qtype;
607         bool                     created = false;
608         int                      rc = 0;
609
610         /* extract pool info from global index FID */
611         rc = lquota_extract_fid(glb_fid, &pool_id, &pool_type, &qtype);
612         if (rc)
613                 RETURN(rc);
614
615         /* look-up pool in charge of this global index FID */
616         pool = qmt_pool_lookup(env, qmt, pool_id, pool_type);
617         if (IS_ERR(pool))
618                 RETURN(PTR_ERR(pool));
619
620         /* look-up slave index file */
621         slv_obj = lquota_disk_slv_find(env, qmt->qmt_child, pool->qpi_root,
622                                        glb_fid, uuid);
623         if (IS_ERR(slv_obj) && PTR_ERR(slv_obj) == -ENOENT) {
624                 /* create slave index file */
625                 slv_obj = lquota_disk_slv_find_create(env, qmt->qmt_child,
626                                                       pool->qpi_root, glb_fid,
627                                                       uuid, false);
628                 created = true;
629         }
630         if (IS_ERR(slv_obj)) {
631                 rc = PTR_ERR(slv_obj);
632                 CERROR("%s: failed to create quota slave index file for %s (%d)"
633                        "\n", qmt->qmt_svname, obd_uuid2str(uuid), rc);
634                 GOTO(out, rc);
635         }
636
637         /* retrieve slave fid & current object version */
638         memcpy(slv_fid, lu_object_fid(&slv_obj->do_lu), sizeof(*slv_fid));
639         *slv_ver = dt_version_get(env, slv_obj);
640         lu_object_put(env, &slv_obj->do_lu);
641         if (created)
642                 pool->qpi_slv_nr[qtype]++;
643 out:
644         qpi_putref(env, pool);
645         RETURN(rc);
646 }
647
648 /*
649  * Look-up a lquota_entry in the pool hash and allocate it if not found.
650  *
651  * \param env - is the environment passed by the caller
652  * \param qmt - is the quota master target for which we have to initializa the
653  *              pool configuration
654  * \param pool_id   - is the 16-bit identifier of the pool
655  * \param pool_type - is the pool type, either LQUOTA_RES_MD or LQUOTA_RES_DT.
656  * \param qtype     - is the quota type, either user or group.
657  * \param qid       - is the quota ID to look-up
658  *
659  * \retval - valid pointer to lquota entry on success, appropriate error on
660  *           failure
661  */
662 struct lquota_entry *qmt_pool_lqe_lookup(const struct lu_env *env,
663                                          struct qmt_device *qmt,
664                                          int pool_id, int pool_type,
665                                          int qtype, union lquota_id *qid)
666 {
667         struct qmt_pool_info    *pool;
668         struct lquota_entry     *lqe;
669         ENTRY;
670
671         /* look-up pool responsible for this global index FID */
672         pool = qmt_pool_lookup(env, qmt, pool_id, pool_type);
673         if (IS_ERR(pool))
674                 RETURN((void *)pool);
675
676         if (qid->qid_uid == 0) {
677                 /* caller wants to access grace time, no need to look up the
678                  * entry since we keep a reference on ID 0 all the time */
679                 lqe = pool->qpi_grace_lqe[qtype];
680                 lqe_getref(lqe);
681                 GOTO(out, lqe);
682         }
683
684         /* now that we have the pool, let's look-up the quota entry in the
685          * right quota site */
686         lqe = lqe_locate(env, pool->qpi_site[qtype], qid);
687 out:
688         qpi_putref(env, pool);
689         RETURN(lqe);
690 }