Whamcloud - gitweb
c1d45904b951a80b90b7e62f14f09c3bd4ff7b34
[fs/lustre-release.git] / lustre / quota / lquota_lib.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 #ifndef EXPORT_SYMTAB
32 # define EXPORT_SYMTAB
33 #endif
34
35 #define DEBUG_SUBSYSTEM S_LQUOTA
36
37 #include <linux/version.h>
38 #include <linux/module.h>
39 #include <linux/init.h>
40
41 #include "lquota_internal.h"
42
43 cfs_mem_cache_t *lqe_kmem;
44
45 struct lu_kmem_descr lquota_caches[] = {
46         {
47                 .ckd_cache = &lqe_kmem,
48                 .ckd_name  = "lqe_kmem",
49                 .ckd_size  = sizeof(struct lquota_entry)
50         },
51         {
52                 .ckd_cache = NULL
53         }
54 };
55
56 /* register lquota key */
57 LU_KEY_INIT_FINI(lquota, struct lquota_thread_info);
58 LU_CONTEXT_KEY_DEFINE(lquota, LCT_MD_THREAD | LCT_DT_THREAD | LCT_LOCAL);
59 LU_KEY_INIT_GENERIC(lquota);
60
61 /**
62  * Look-up accounting object to collect space usage information for user
63  * or group.
64  *
65  * \param env  - is the environment passed by the caller
66  * \param dev  - is the dt_device storing the accounting object
67  * \param type - is the quota type, either USRQUOTA or GRPQUOTA
68  */
69 struct dt_object *acct_obj_lookup(const struct lu_env *env,
70                                   struct dt_device *dev, int type)
71 {
72         struct lquota_thread_info       *qti = lquota_info(env);
73         struct dt_object                *obj = NULL;
74         ENTRY;
75
76         lu_local_obj_fid(&qti->qti_fid,
77                          type == USRQUOTA ? ACCT_USER_OID : ACCT_GROUP_OID);
78
79         /* lookup the accounting object */
80         obj = dt_locate(env, dev, &qti->qti_fid);
81         if (IS_ERR(obj))
82                 RETURN(obj);
83
84         if (!dt_object_exists(obj)) {
85                 lu_object_put(env, &obj->do_lu);
86                 RETURN(ERR_PTR(-ENOENT));
87         }
88
89         if (obj->do_index_ops == NULL) {
90                 int rc;
91
92                 /* set up indexing operations */
93                 rc = obj->do_ops->do_index_try(env, obj, &dt_acct_features);
94                 if (rc) {
95                         CERROR("%s: failed to set up indexing operations for %s"
96                                " acct object rc:%d\n",
97                                dev->dd_lu_dev.ld_obd->obd_name,
98                                QTYPE_NAME(type), rc);
99                         lu_object_put(env, &obj->do_lu);
100                         RETURN(ERR_PTR(rc));
101                 }
102         }
103         RETURN(obj);
104 }
105
106 /**
107  * Initialize slave index object to collect local quota limit for user or group.
108  *
109  * \param env - is the environment passed by the caller
110  * \param dev - is the dt_device storing the slave index object
111  * \param type - is the quota type, either USRQUOTA or GRPQUOTA
112  */
113 static struct dt_object *quota_obj_lookup(const struct lu_env *env,
114                                           struct dt_device *dev, int type)
115 {
116         struct lquota_thread_info       *qti = lquota_info(env);
117         struct dt_object                *obj = NULL;
118         ENTRY;
119
120         qti->qti_fid.f_seq = FID_SEQ_QUOTA;
121         qti->qti_fid.f_oid = type == USRQUOTA ? LQUOTA_USR_OID : LQUOTA_GRP_OID;
122         qti->qti_fid.f_ver = 0;
123
124         /* lookup the quota object */
125         obj = dt_locate(env, dev, &qti->qti_fid);
126         if (IS_ERR(obj))
127                 RETURN(obj);
128
129         if (!dt_object_exists(obj)) {
130                 lu_object_put(env, &obj->do_lu);
131                 RETURN(ERR_PTR(-ENOENT));
132         }
133
134         if (obj->do_index_ops == NULL) {
135                 int rc;
136
137                 /* set up indexing operations */
138                 rc = obj->do_ops->do_index_try(env, obj,
139                                                &dt_quota_slv_features);
140                 if (rc) {
141                         CERROR("%s: failed to set up indexing operations for %s"
142                                " slave index object rc:%d\n",
143                                dev->dd_lu_dev.ld_obd->obd_name,
144                                QTYPE_NAME(type), rc);
145                         lu_object_put(env, &obj->do_lu);
146                         RETURN(ERR_PTR(rc));
147                 }
148         }
149         RETURN(obj);
150 }
151
152 /*
153  * Helper routine to retrieve slave information.
154  * This function converts a quotactl request into quota/accounting object
155  * operations. It is independant of the slave stack which is only accessible
156  * from the OSD layer.
157  *
158  * \param env   - is the environment passed by the caller
159  * \param dev   - is the dt_device this quotactl is executed on
160  * \param oqctl - is the quotactl request
161  */
162 int lquotactl_slv(const struct lu_env *env, struct dt_device *dev,
163                   struct obd_quotactl *oqctl)
164 {
165         struct lquota_thread_info       *qti = lquota_info(env);
166         __u64                            key;
167         struct dt_object                *obj;
168         struct obd_dqblk                *dqblk = &oqctl->qc_dqblk;
169         int                              rc;
170         ENTRY;
171
172         if (oqctl->qc_cmd != Q_GETOQUOTA) {
173                 /* as in many other places, dev->dd_lu_dev.ld_obd->obd_name
174                  * point to an invalid obd_name, to be fixed in LU-1574 */
175                 CERROR("%s: Unsupported quotactl command: %x\n",
176                        dev->dd_lu_dev.ld_obd->obd_name, oqctl->qc_cmd);
177                 RETURN(-EOPNOTSUPP);
178         }
179
180         if (oqctl->qc_type != USRQUOTA && oqctl->qc_type != GRPQUOTA)
181                 /* no support for directory quota yet */
182                 RETURN(-EOPNOTSUPP);
183
184         /* qc_id is a 32-bit field while a key has 64 bits */
185         key = oqctl->qc_id;
186
187         /* Step 1: collect accounting information */
188
189         obj = acct_obj_lookup(env, dev, oqctl->qc_type);
190         if (IS_ERR(obj))
191                 RETURN(-EOPNOTSUPP);
192         if (obj->do_index_ops == NULL)
193                 GOTO(out, rc = -EINVAL);
194
195         /* lookup record storing space accounting information for this ID */
196         rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_acct_rec,
197                        (struct dt_key *)&key, BYPASS_CAPA);
198         if (rc < 0)
199                 GOTO(out, rc);
200
201         memset(&oqctl->qc_dqblk, 0, sizeof(struct obd_dqblk));
202         dqblk->dqb_curspace     = qti->qti_acct_rec.bspace;
203         dqblk->dqb_curinodes    = qti->qti_acct_rec.ispace;
204         dqblk->dqb_valid        = QIF_USAGE;
205
206         lu_object_put(env, &obj->do_lu);
207
208         /* Step 2: collect enforcement information */
209
210         obj = quota_obj_lookup(env, dev, oqctl->qc_type);
211         if (IS_ERR(obj))
212                 RETURN(0);
213         if (obj->do_index_ops == NULL)
214                 GOTO(out, rc = 0);
215
216         memset(&qti->qti_slv_rec, 0, sizeof(qti->qti_slv_rec));
217         /* lookup record storing enforcement information for this ID */
218         rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_slv_rec,
219                        (struct dt_key *)&key, BYPASS_CAPA);
220         if (rc < 0 && rc != -ENOENT)
221                 GOTO(out, rc = 0);
222
223         if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev)) {
224                 dqblk->dqb_ihardlimit = qti->qti_slv_rec.qsr_granted;
225                 dqblk->dqb_bhardlimit = 0;
226         } else {
227                 dqblk->dqb_ihardlimit = 0;
228                 dqblk->dqb_bhardlimit = qti->qti_slv_rec.qsr_granted;
229         }
230         dqblk->dqb_valid |= QIF_LIMITS;
231
232         GOTO(out, rc = 0);
233 out:
234         lu_object_put(env, &obj->do_lu);
235         return rc;
236 }
237 EXPORT_SYMBOL(lquotactl_slv);
238
239 /**
240  * Helper routine returning the FID associated with the global index storing
241  * quota settings for the storage pool \pool_id, resource type \pool_type and
242  * the quota type \quota_type.
243  */
244 void lquota_generate_fid(struct lu_fid *fid, int pool_id, int pool_type,
245                          int quota_type)
246 {
247         __u8     qtype;
248
249         qtype = (quota_type == USRQUOTA) ? LQUOTA_TYPE_USR : LQUOTA_TYPE_GRP;
250
251         fid->f_seq = FID_SEQ_QUOTA_GLB;
252         fid->f_oid = (qtype << 24) | (pool_type << 16) | (__u16)pool_id;
253         fid->f_ver = 0;
254 }
255
256 /**
257  * Helper routine used to extract pool ID, pool type and quota type from a
258  * given FID.
259  */
260 int lquota_extract_fid(const struct lu_fid *fid, int *pool_id, int *pool_type,
261                        int *quota_type)
262 {
263         unsigned int     tmp;
264         ENTRY;
265
266         if (fid->f_seq != FID_SEQ_QUOTA_GLB)
267                 RETURN(-EINVAL);
268
269         if (pool_id != NULL) {
270                 tmp = fid->f_oid & 0xffffU;
271                 if (tmp != 0)
272                         /* we only support pool ID 0 for the time being */
273                         RETURN(-ENOTSUPP);
274                 *pool_id = tmp;
275         }
276
277         if (pool_type != NULL) {
278                 tmp = (fid->f_oid >> 16) & 0xffU;
279                 if (tmp >= LQUOTA_LAST_RES)
280                         RETURN(-ENOTSUPP);
281
282                 *pool_type = tmp;
283         }
284
285         if (quota_type != NULL) {
286                 tmp = fid->f_oid >> 24;
287                 if (tmp >= LQUOTA_TYPE_MAX)
288                         RETURN(-ENOTSUPP);
289
290                 *quota_type = (tmp == LQUOTA_TYPE_USR) ? USRQUOTA : GRPQUOTA;
291         }
292
293         RETURN(0);
294 }
295
296 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0)
297 /* Index features supported by the global index objects.
298  * We actually use one dt_index_features structure for each quota combination
299  * of quota type x [inode, block] to allow the ldiskfs OSD to recognize those
300  * objects and to handle the conversion from the old administrative quota file
301  * format */
302 struct dt_index_features dt_quota_iusr_features;
303 EXPORT_SYMBOL(dt_quota_iusr_features);
304 struct dt_index_features dt_quota_busr_features;
305 EXPORT_SYMBOL(dt_quota_busr_features);
306 struct dt_index_features dt_quota_igrp_features;
307 EXPORT_SYMBOL(dt_quota_igrp_features);
308 struct dt_index_features dt_quota_bgrp_features;
309 EXPORT_SYMBOL(dt_quota_bgrp_features);
310
311 /**
312  * Helper routine returning the right index feature structure to be used
313  * depending on the FID of the global index.
314  */
315 const struct dt_index_features *glb_idx_feature(struct lu_fid *fid)
316 {
317         int     res_type, quota_type, rc;
318
319         rc = lquota_extract_fid(fid, NULL, &res_type, &quota_type);
320         if (rc)
321                 return ERR_PTR(rc);
322
323         if (quota_type == USRQUOTA) {
324                 if (res_type == LQUOTA_RES_MD)
325                         return &dt_quota_iusr_features;
326                 else
327                         return &dt_quota_busr_features;
328         } else {
329                 if (res_type == LQUOTA_RES_MD)
330                         return &dt_quota_igrp_features;
331                 else
332                         return &dt_quota_bgrp_features;
333         }
334 }
335 #else
336 #warning "remove old quota compatibility code"
337 #endif
338
339 static int __init init_lquota(void)
340 {
341         int     rc;
342         ENTRY;
343
344         lquota_key_init_generic(&lquota_thread_key, NULL);
345         lu_context_key_register(&lquota_thread_key);
346
347 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2,7,50,0)
348         dt_quota_iusr_features = dt_quota_busr_features = dt_quota_glb_features;
349         dt_quota_igrp_features = dt_quota_bgrp_features = dt_quota_glb_features;
350 #else
351 #warning "remove old quota compatibility code"
352 #endif
353
354         rc = lu_kmem_init(lquota_caches);
355         if (rc)
356                 GOTO(out_key, rc);
357
358         rc = qmt_glb_init();
359         if (rc)
360                 GOTO(out_caches, rc);
361
362         rc = qsd_glb_init();
363         if (rc)
364                 GOTO(out_qmt, rc);
365
366         RETURN(0);
367
368 out_qmt:
369         qmt_glb_fini();
370 out_caches:
371         lu_kmem_fini(lquota_caches);
372 out_key:
373         lu_context_key_degister(&lquota_thread_key);
374         return rc;
375 }
376
377 static void exit_lquota(void)
378 {
379         qsd_glb_fini();
380         qmt_glb_fini();
381         lu_kmem_fini(lquota_caches);
382         lu_context_key_degister(&lquota_thread_key);
383 }
384
385 MODULE_AUTHOR("Intel, Inc. <http://www.intel.com/>");
386 MODULE_DESCRIPTION("Lustre Quota");
387 MODULE_LICENSE("GPL");
388
389 cfs_module(lquota, "2.4.0", init_lquota, exit_lquota);