Whamcloud - gitweb
1c20d86b8d40c0eb769d594346ccf3980a0b37c9
[fs/lustre-release.git] / lustre / quota / quota_adjust_qunit.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 #ifndef EXPORT_SYMTAB
37 # define EXPORT_SYMTAB
38 #endif
39 #define DEBUG_SUBSYSTEM S_LQUOTA
40
41 #ifdef __KERNEL__
42 # include <linux/version.h>
43 # include <linux/module.h>
44 # include <linux/init.h>
45 # include <linux/fs.h>
46 # include <linux/jbd.h>
47 # include <linux/quota.h>
48 # include <linux/smp_lock.h>
49 # include <linux/buffer_head.h>
50 # include <linux/workqueue.h>
51 # include <linux/mount.h>
52 #else /* __KERNEL__ */
53 # include <liblustre.h>
54 #endif
55
56 #include <obd_class.h>
57 #include <lustre_mds.h>
58 #include <lustre_dlm.h>
59 #include <lustre_cfg.h>
60 #include <obd_ost.h>
61 #include <lustre_fsfilt.h>
62 #include <linux/lustre_quota.h>
63 #include <class_hash.h>
64 #include "quota_internal.h"
65
66 #ifdef HAVE_QUOTA_SUPPORT
67
68 #ifdef __KERNEL__
69 /**
70  * This function is charge of recording lqs_ino_rec and
71  * lqs_blk_rec. when a lquota slave checks a quota
72  * request(check_cur_qunit) and finishes a quota
73  * request(dqacq_completion), it will be called.
74  * is_chk: whether it is checking quota; otherwise, it is finishing
75  * is_acq: whether it is acquiring; otherwise, it is releasing
76  */
77 void quota_compute_lqs(struct qunit_data *qdata, struct lustre_qunit_size *lqs,
78                       int is_chk, int is_acq)
79 {
80         int is_blk;
81
82         LASSERT(qdata && lqs);
83         LASSERT_SPIN_LOCKED(&lqs->lqs_lock);
84         is_blk = QDATA_IS_BLK(qdata);
85
86         if (is_chk) {
87                 if (is_acq) {
88                         if (is_blk)
89                                 lqs->lqs_blk_rec += qdata->qd_count;
90                         else
91                                 lqs->lqs_ino_rec += qdata->qd_count;
92                 } else {
93                         if (is_blk)
94                                 lqs->lqs_blk_rec -= qdata->qd_count;
95                         else
96                                 lqs->lqs_ino_rec -= qdata->qd_count;
97                 }
98         } else {
99                 if (is_acq) {
100                         if (is_blk)
101                                 lqs->lqs_blk_rec -= qdata->qd_count;
102                         else
103                                 lqs->lqs_ino_rec -= qdata->qd_count;
104                 } else {
105                         if (is_blk)
106                                 lqs->lqs_blk_rec += qdata->qd_count;
107                         else
108                                 lqs->lqs_ino_rec += qdata->qd_count;
109                 }
110         }
111 }
112
113 void qdata_to_oqaq(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq)
114 {
115         LASSERT(qdata);
116         LASSERT(oqaq);
117
118         oqaq->qaq_flags = qdata->qd_flags;
119         oqaq->qaq_id    = qdata->qd_id;
120         if (QDATA_IS_ADJBLK(qdata))
121                 oqaq->qaq_bunit_sz = qdata->qd_qunit;
122         if (QDATA_IS_ADJINO(qdata))
123                 oqaq->qaq_iunit_sz = qdata->qd_qunit;
124 }
125
126 int quota_search_lqs(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq,
127                      struct lustre_quota_ctxt *qctxt,
128                      struct lustre_qunit_size **lqs_return)
129 {
130         struct quota_adjust_qunit *oqaq_tmp = NULL;
131         ENTRY;
132
133         LASSERT(*lqs_return == NULL);
134         LASSERT(oqaq || qdata);
135
136         if (!oqaq) {
137                 OBD_ALLOC_PTR(oqaq_tmp);
138                 if (!oqaq_tmp)
139                         RETURN(-ENOMEM);
140                 qdata_to_oqaq(qdata, oqaq_tmp);
141         } else {
142                 oqaq_tmp = oqaq;
143         }
144
145         *lqs_return = lustre_hash_lookup(qctxt->lqc_lqs_hash, oqaq_tmp);
146         if (*lqs_return)
147                 LQS_DEBUG((*lqs_return), "show lqs\n");
148
149         if (!oqaq)
150                 OBD_FREE_PTR(oqaq_tmp);
151         RETURN(0);
152 }
153
154 int quota_create_lqs(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq,
155                      struct lustre_quota_ctxt *qctxt,
156                      struct lustre_qunit_size **lqs_return)
157 {
158         struct lustre_qunit_size *lqs = NULL;
159         int rc = 0;
160         ENTRY;
161
162         LASSERT(*lqs_return == NULL);
163         LASSERT(oqaq || qdata);
164
165         OBD_ALLOC_PTR(lqs);
166         if (!lqs)
167                 GOTO(out, rc = -ENOMEM);
168
169         if (!oqaq)
170                 qdata_to_oqaq(qdata, &lqs->lqs_key);
171         else
172                 lqs->lqs_key = *oqaq;
173
174         spin_lock_init(&lqs->lqs_lock);
175         lqs->lqs_bwrite_pending = 0;
176         lqs->lqs_iwrite_pending = 0;
177         lqs->lqs_ino_rec = 0;
178         lqs->lqs_blk_rec = 0;
179         lqs->lqs_id = lqs->lqs_key.qaq_id;
180         lqs->lqs_flags = QAQ_IS_GRP(&lqs->lqs_key);
181         lqs->lqs_bunit_sz = qctxt->lqc_bunit_sz;
182         lqs->lqs_iunit_sz = qctxt->lqc_iunit_sz;
183         lqs->lqs_btune_sz = qctxt->lqc_btune_sz;
184         lqs->lqs_itune_sz = qctxt->lqc_itune_sz;
185         lqs->lqs_ctxt = qctxt;
186         if (qctxt->lqc_handler) {
187                 lqs->lqs_last_bshrink  = 0;
188                 lqs->lqs_last_ishrink  = 0;
189         }
190         lqs_initref(lqs);
191         rc = lustre_hash_add_unique(qctxt->lqc_lqs_hash,
192                                     &lqs->lqs_key, &lqs->lqs_hash);
193         LQS_DEBUG(lqs, "create lqs\n");
194         if (!rc) {
195                 lqs_getref(lqs);
196                 *lqs_return = lqs;
197         }
198 out:
199         if (rc && lqs)
200                 OBD_FREE_PTR(lqs);
201         RETURN(rc);
202 }
203
204 int quota_adjust_slave_lqs(struct quota_adjust_qunit *oqaq,
205                            struct lustre_quota_ctxt *qctxt)
206 {
207         struct lustre_qunit_size *lqs = NULL;
208         unsigned long *lbunit, *liunit, *lbtune, *litune;
209         signed long b_tmp = 0, i_tmp = 0;
210         cfs_time_t time_limit = 0;
211         int rc = 0;
212         ENTRY;
213
214         LASSERT(qctxt);
215 search_lqs:
216         rc = quota_search_lqs(NULL, oqaq, qctxt, &lqs);
217
218         /* deleting the lqs, because a user sets lfs quota 0 0 0 0  */
219         if (!oqaq->qaq_bunit_sz && !oqaq->qaq_iunit_sz && QAQ_IS_ADJBLK(oqaq) &&
220             QAQ_IS_ADJINO(oqaq)) {
221                 if (lqs) {
222                         LQS_DEBUG(lqs, "release lqs\n");
223                         /* this is for quota_search_lqs */
224                         lqs_putref(lqs);
225                         /* kill lqs */
226                         lqs_putref(lqs);
227                 }
228                 RETURN(rc);
229         }
230
231         if (!lqs) {
232                 rc = quota_create_lqs(NULL, oqaq, qctxt, &lqs);
233                 if (rc == -EALREADY)
234                         goto search_lqs;
235                 if (rc < 0)
236                         RETURN(rc);
237         }
238
239         lbunit = &lqs->lqs_bunit_sz;
240         liunit = &lqs->lqs_iunit_sz;
241         lbtune = &lqs->lqs_btune_sz;
242         litune = &lqs->lqs_itune_sz;
243
244         CDEBUG(D_QUOTA, "before: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
245         spin_lock(&lqs->lqs_lock);
246         /* adjust the slave's block qunit size */
247         if (QAQ_IS_ADJBLK(oqaq)) {
248                 cfs_duration_t sec = cfs_time_seconds(qctxt->lqc_switch_seconds);
249
250                 b_tmp = *lbunit - oqaq->qaq_bunit_sz;
251
252                 if (qctxt->lqc_handler && b_tmp > 0)
253                         lqs->lqs_last_bshrink = cfs_time_current();
254
255                 if (qctxt->lqc_handler && b_tmp < 0) {
256                         time_limit = cfs_time_add(lqs->lqs_last_bshrink, sec);
257                         if (!lqs->lqs_last_bshrink ||
258                             cfs_time_after(cfs_time_current(), time_limit)) {
259                                 *lbunit = oqaq->qaq_bunit_sz;
260                                 *lbtune = (*lbunit) / 2;
261                         } else {
262                                 b_tmp = 0;
263                         }
264                 } else {
265                         *lbunit = oqaq->qaq_bunit_sz;
266                         *lbtune = (*lbunit) / 2;
267                 }
268         }
269
270         /* adjust the slave's file qunit size */
271         if (QAQ_IS_ADJINO(oqaq)) {
272                 i_tmp = *liunit - oqaq->qaq_iunit_sz;
273
274                 if (qctxt->lqc_handler && i_tmp > 0)
275                         lqs->lqs_last_ishrink  = cfs_time_current();
276
277                 if (qctxt->lqc_handler && i_tmp < 0) {
278                         time_limit = cfs_time_add(lqs->lqs_last_ishrink,
279                                                   cfs_time_seconds(qctxt->
280                                                   lqc_switch_seconds));
281                         if (!lqs->lqs_last_ishrink ||
282                             cfs_time_after(cfs_time_current(), time_limit)) {
283                                 *liunit = oqaq->qaq_iunit_sz;
284                                 *litune = (*liunit) / 2;
285                         } else {
286                                 i_tmp = 0;
287                         }
288                 } else {
289                         *liunit = oqaq->qaq_iunit_sz;
290                         *litune = (*liunit) / 2;
291                 }
292         }
293         spin_unlock(&lqs->lqs_lock);
294         CDEBUG(D_QUOTA, "after: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
295
296         lqs_putref(lqs);
297
298         if (b_tmp > 0)
299                 rc |= LQS_BLK_DECREASE;
300         else if (b_tmp < 0)
301                 rc |= LQS_BLK_INCREASE;
302
303         if (i_tmp > 0)
304                 rc |= LQS_INO_DECREASE;
305         else if (i_tmp < 0)
306                 rc |= LQS_INO_INCREASE;
307
308         RETURN(rc);
309 }
310
311 int filter_quota_adjust_qunit(struct obd_export *exp,
312                               struct quota_adjust_qunit *oqaq,
313                               struct lustre_quota_ctxt *qctxt)
314 {
315         struct obd_device *obd = exp->exp_obd;
316         unsigned int id[MAXQUOTAS] = { 0, 0 };
317         int rc = 0;
318         ENTRY;
319
320         LASSERT(oqaq);
321         LASSERT(QAQ_IS_ADJBLK(oqaq));
322         rc = quota_adjust_slave_lqs(oqaq, qctxt);
323         if (rc < 0) {
324                 CERROR("adjust mds slave's qunit size failed!(rc:%d)\n", rc);
325                 RETURN(rc);
326         }
327         if (QAQ_IS_GRP(oqaq))
328                 id[GRPQUOTA] = oqaq->qaq_id;
329         else
330                 id[USRQUOTA] = oqaq->qaq_id;
331
332         if (rc > 0) {
333                 rc = qctxt_adjust_qunit(obd, qctxt, id, 1, 0, NULL);
334                 if (rc == -EDQUOT || rc == -EBUSY ||
335                     rc == QUOTA_REQ_RETURNED || rc == -EAGAIN) {
336                         CDEBUG(D_QUOTA, "rc: %d.\n", rc);
337                         rc = 0;
338                 }
339                 if (rc)
340                         CERROR("slave adjust block quota failed!(rc:%d)\n", rc);
341         }
342         RETURN(rc);
343 }
344 #endif /* __KERNEL__ */
345 #endif
346
347 int client_quota_adjust_qunit(struct obd_export *exp,
348                               struct quota_adjust_qunit *oqaq,
349                               struct lustre_quota_ctxt *qctxt)
350 {
351         struct ptlrpc_request *req;
352         struct quota_adjust_qunit *oqa;
353         int rc = 0;
354         ENTRY;
355
356         /* client don't support this kind of operation, abort it */
357         if (!(exp->exp_connect_flags & OBD_CONNECT_CHANGE_QS)) {
358                 CDEBUG(D_QUOTA, "osc: %s don't support change qunit size\n",
359                        exp->exp_obd->obd_name);
360                 RETURN(rc);
361         }
362         if (strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
363                 RETURN(-EINVAL);
364
365         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
366                                         &RQF_OST_QUOTA_ADJUST_QUNIT,
367                                         LUSTRE_OST_VERSION,
368                                         OST_QUOTA_ADJUST_QUNIT);
369         if (req == NULL)
370                 RETURN(-ENOMEM);
371
372         oqa = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_ADJUST_QUNIT);
373         *oqa = *oqaq;
374
375         ptlrpc_request_set_replen(req);
376
377         rc = ptlrpc_queue_wait(req);
378         if (rc)
379                 CERROR("%s: %s failed: rc = %d\n", exp->exp_obd->obd_name,
380                        __FUNCTION__, rc);
381         ptlrpc_req_finished(req);
382         RETURN (rc);
383 }
384
385 int lov_quota_adjust_qunit(struct obd_export *exp,
386                            struct quota_adjust_qunit *oqaq,
387                            struct lustre_quota_ctxt *qctxt)
388 {
389         struct obd_device *obd = class_exp2obd(exp);
390         struct lov_obd *lov = &obd->u.lov;
391         int i, rc = 0;
392         ENTRY;
393
394         if (!QAQ_IS_ADJBLK(oqaq)) {
395                 CERROR("bad qaq_flags %x for lov obd.\n", oqaq->qaq_flags);
396                 RETURN(-EFAULT);
397         }
398
399         for (i = 0; i < lov->desc.ld_tgt_count; i++) {
400                 int err;
401
402                 if (!lov->lov_tgts[i]->ltd_active) {
403                         CDEBUG(D_HA, "ost %d is inactive\n", i);
404                         continue;
405                 }
406
407                 err = obd_quota_adjust_qunit(lov->lov_tgts[i]->ltd_exp, oqaq,
408                                              NULL);
409                 if (err) {
410                         if (lov->lov_tgts[i]->ltd_active && !rc)
411                                 rc = err;
412                         continue;
413                 }
414         }
415         RETURN(rc);
416 }