Whamcloud - gitweb
Branch b1_6
[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  *  lustre/quota/quota_adjust_qunit.c
5  *
6  *  Copyright (c) 2005 Cluster File Systems, Inc.
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
11  *
12  */
13 #ifndef EXPORT_SYMTAB
14 # define EXPORT_SYMTAB
15 #endif
16 #define DEBUG_SUBSYSTEM S_MDS
17
18 #ifdef __KERNEL__
19 # include <linux/version.h>
20 # include <linux/module.h>
21 # include <linux/init.h>
22 # include <linux/fs.h>
23 # include <linux/jbd.h>
24 # include <linux/ext3_fs.h>
25 # include <linux/quota.h>
26 # if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
27 #  include <linux/smp_lock.h>
28 #  include <linux/buffer_head.h>
29 #  include <linux/workqueue.h>
30 #  include <linux/mount.h>
31 # else
32 #  include <linux/locks.h>
33 # endif
34 #else /* __KERNEL__ */
35 # include <liblustre.h>
36 #endif
37
38 #include <obd_class.h>
39 #include <lustre_mds.h>
40 #include <lustre_dlm.h>
41 #include <lustre_cfg.h>
42 #include <obd_ost.h>
43 #include <lustre_fsfilt.h>
44 #include <linux/lustre_quota.h>
45 #include <class_hash.h>
46 #include "quota_internal.h"
47
48 #ifdef __KERNEL__
49 /* this function is charge of recording lqs_ino_rec and
50  * lqs_blk_rec. when a lquota slave checks a quota
51  * request(check_cur_qunit) and finishes a quota
52  * request(dqacq_completion), it will be called.
53  * is_chk: whether it is checking quota; otherwise, it is finishing
54  * is_acq: whether it is acquiring; otherwise, it is releasing
55  */
56 void quota_compute_lqs(struct qunit_data *qdata, struct lustre_qunit_size *lqs,
57                       int is_chk, int is_acq)
58 {
59         int is_blk;
60
61         LASSERT(qdata && lqs);
62         LASSERT_SPIN_LOCKED(&lqs->lqs_lock);
63         is_blk = QDATA_IS_BLK(qdata);
64
65         if (is_chk) {
66                 if (is_acq) {
67                         if (is_blk)
68                                 lqs->lqs_blk_rec += qdata->qd_count;
69                         else
70                                 lqs->lqs_ino_rec += qdata->qd_count;
71                 } else {
72                         if (is_blk)
73                                 lqs->lqs_blk_rec -= qdata->qd_count;
74                         else
75                                 lqs->lqs_ino_rec -= qdata->qd_count;
76                 }
77         } else {
78                 if (is_acq) {
79                         if (is_blk)
80                                 lqs->lqs_blk_rec -= qdata->qd_count;
81                         else
82                                 lqs->lqs_ino_rec -= qdata->qd_count;
83                 } else {
84                         if (is_blk)
85                                 lqs->lqs_blk_rec += qdata->qd_count;
86                         else
87                                 lqs->lqs_ino_rec += qdata->qd_count;
88                 }
89         }
90 }
91
92 void qdata_to_oqaq(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq)
93 {
94         LASSERT(qdata);
95         LASSERT(oqaq);
96
97         oqaq->qaq_flags = qdata->qd_flags;
98         oqaq->qaq_id    = qdata->qd_id;
99         if (QDATA_IS_ADJBLK(qdata))
100                 oqaq->qaq_bunit_sz = qdata->qd_qunit;
101         if (QDATA_IS_ADJINO(qdata))
102                 oqaq->qaq_iunit_sz = qdata->qd_qunit;
103 }
104
105 int quota_search_lqs(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq,
106                      struct lustre_quota_ctxt *qctxt,
107                      struct lustre_qunit_size **lqs_return)
108 {
109         struct quota_adjust_qunit *oqaq_tmp = NULL;
110         ENTRY;
111
112         LASSERT(*lqs_return == NULL);
113         LASSERT(oqaq || qdata);
114
115         if (!oqaq) {
116                 OBD_ALLOC_PTR(oqaq_tmp);
117                 if (!oqaq_tmp)
118                         RETURN(-ENOMEM);
119                 qdata_to_oqaq(qdata, oqaq_tmp);
120         } else {
121                 oqaq_tmp = oqaq;
122         }
123
124         *lqs_return = lustre_hash_get_object_by_key(LQC_HASH_BODY(qctxt),
125                                                     oqaq_tmp);
126         if (*lqs_return)
127                 LQS_DEBUG((*lqs_return), "show lqs\n");
128
129         if (!oqaq)
130                 OBD_FREE_PTR(oqaq_tmp);
131         RETURN(0);
132 }
133
134 int quota_create_lqs(struct qunit_data *qdata, struct quota_adjust_qunit *oqaq,
135                      struct lustre_quota_ctxt *qctxt,
136                      struct lustre_qunit_size **lqs_return)
137 {
138         int rc = 0;
139         struct quota_adjust_qunit *oqaq_tmp = NULL;
140         struct lustre_qunit_size *lqs = NULL;
141         ENTRY;
142
143         LASSERT(*lqs_return == NULL);
144         LASSERT(oqaq || qdata);
145
146         if (!oqaq) {
147                 OBD_ALLOC_PTR(oqaq_tmp);
148                 if (!oqaq_tmp)
149                         RETURN(-ENOMEM);
150                 qdata_to_oqaq(qdata, oqaq_tmp);
151         } else {
152                 oqaq_tmp = oqaq;
153         }
154
155         OBD_ALLOC_PTR(lqs);
156         if (!lqs)
157                 GOTO(out, rc = -ENOMEM);
158
159         spin_lock_init(&lqs->lqs_lock);
160         lqs->lqs_bwrite_pending = 0;
161         lqs->lqs_iwrite_pending = 0;
162         lqs->lqs_ino_rec = 0;
163         lqs->lqs_blk_rec = 0;
164         lqs->lqs_id = oqaq_tmp->qaq_id;
165         lqs->lqs_flags = QAQ_IS_GRP(oqaq_tmp);
166         lqs->lqs_bunit_sz = qctxt->lqc_bunit_sz;
167         lqs->lqs_iunit_sz = qctxt->lqc_iunit_sz;
168         lqs->lqs_btune_sz = qctxt->lqc_btune_sz;
169         lqs->lqs_itune_sz = qctxt->lqc_itune_sz;
170         if (qctxt->lqc_handler) {
171                 lqs->lqs_last_bshrink  = 0;
172                 lqs->lqs_last_ishrink  = 0;
173         }
174         lqs_initref(lqs);
175         rc = lustre_hash_additem_unique(LQC_HASH_BODY(qctxt),
176                                         oqaq_tmp, &lqs->lqs_hash);
177         LQS_DEBUG(lqs, "create lqs\n");
178         if (!rc) {
179                 lqs_getref(lqs);
180                 *lqs_return = lqs;
181         }
182  out:
183         if (rc && lqs)
184                 OBD_FREE_PTR(lqs);
185         if (!oqaq)
186                 OBD_FREE_PTR(oqaq_tmp);
187         RETURN(rc);
188 }
189
190 int quota_adjust_slave_lqs(struct quota_adjust_qunit *oqaq,
191                            struct lustre_quota_ctxt *qctxt)
192 {
193         struct lustre_qunit_size *lqs = NULL;
194         unsigned long *lbunit, *liunit, *lbtune, *litune;
195         signed long b_tmp = 0, i_tmp = 0;
196         cfs_time_t time_limit = 0;
197         int rc = 0;
198         ENTRY;
199
200         if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS))
201                 RETURN(0);
202
203         LASSERT(qctxt);
204 search_lqs:
205         rc = quota_search_lqs(NULL, oqaq, qctxt, &lqs);
206
207         /* deleting the lqs, because a user sets lfs quota 0 0 0 0  */
208         if (!oqaq->qaq_bunit_sz && !oqaq->qaq_iunit_sz && QAQ_IS_ADJBLK(oqaq) &&
209             QAQ_IS_ADJINO(oqaq)) {
210                 if (lqs) {
211                         LQS_DEBUG(lqs, "release lqs\n");
212                         /* this is for quota_search_lqs */
213                         lqs_putref(lqs);
214                         /* this is for deleting this lqs */
215                         lqs_putref(lqs);
216                 }
217                 RETURN(rc);
218         }
219
220         if (!lqs) {
221                 rc = quota_create_lqs(NULL, oqaq, qctxt, &lqs);
222                 if (rc == -EALREADY)
223                         goto search_lqs;
224                 if (rc < 0)
225                         RETURN(rc);
226         }
227
228         lbunit = &lqs->lqs_bunit_sz;
229         liunit = &lqs->lqs_iunit_sz;
230         lbtune = &lqs->lqs_btune_sz;
231         litune = &lqs->lqs_itune_sz;
232
233         spin_lock(&lqs->lqs_lock);
234         CDEBUG(D_QUOTA, "before: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
235         /* adjust the slave's block qunit size */
236         if (QAQ_IS_ADJBLK(oqaq)) {
237                 cfs_duration_t sec = cfs_time_seconds(qctxt->lqc_switch_seconds);
238
239                 b_tmp = *lbunit - oqaq->qaq_bunit_sz;
240
241                 if (qctxt->lqc_handler && b_tmp > 0)
242                         lqs->lqs_last_bshrink = cfs_time_current();
243
244                 if (qctxt->lqc_handler && b_tmp < 0) {
245                         time_limit = cfs_time_add(lqs->lqs_last_bshrink, sec);
246                         if (!lqs->lqs_last_bshrink ||
247                             cfs_time_after(cfs_time_current(), time_limit)) {
248                                 *lbunit = oqaq->qaq_bunit_sz;
249                                 *lbtune = (*lbunit) / 2;
250                         } else {
251                                 b_tmp = 0;
252                         }
253                 } else {
254                         *lbunit = oqaq->qaq_bunit_sz;
255                         *lbtune = (*lbunit) / 2;
256                 }
257         }
258
259         /* adjust the slave's file qunit size */
260         if (QAQ_IS_ADJINO(oqaq)) {
261                 i_tmp = *liunit - oqaq->qaq_iunit_sz;
262
263                 if (qctxt->lqc_handler && i_tmp > 0)
264                         lqs->lqs_last_ishrink  = cfs_time_current();
265
266                 if (qctxt->lqc_handler && i_tmp < 0) {
267                         time_limit = cfs_time_add(lqs->lqs_last_ishrink,
268                                                   cfs_time_seconds(qctxt->
269                                                   lqc_switch_seconds));
270                         if (!lqs->lqs_last_ishrink ||
271                             cfs_time_after(cfs_time_current(), time_limit)) {
272                                 *liunit = oqaq->qaq_iunit_sz;
273                                 *litune = (*liunit) / 2;
274                         } else {
275                                 i_tmp = 0;
276                         }
277                 } else {
278                         *liunit = oqaq->qaq_iunit_sz;
279                         *litune = (*liunit) / 2;
280                 }
281         }
282         CDEBUG(D_QUOTA, "after: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
283         spin_unlock(&lqs->lqs_lock);
284
285         lqs_putref(lqs);
286
287         if (b_tmp > 0)
288                 rc |= LQS_BLK_DECREASE;
289         else if (b_tmp < 0)
290                 rc |= LQS_BLK_INCREASE;
291
292         if (i_tmp > 0)
293                 rc |= LQS_INO_DECREASE;
294         else if (i_tmp < 0)
295                 rc |= LQS_INO_INCREASE;
296
297         RETURN(rc);
298 }
299
300 int filter_quota_adjust_qunit(struct obd_export *exp,
301                               struct quota_adjust_qunit *oqaq)
302 {
303         struct obd_device *obd = exp->exp_obd;
304         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
305         unsigned int uid = 0, gid = 0;
306         int rc = 0;
307         ENTRY;
308
309         LASSERT(oqaq);
310         LASSERT(QAQ_IS_ADJBLK(oqaq));
311         rc = quota_adjust_slave_lqs(oqaq, qctxt);
312         if (rc < 0) {
313                 CERROR("adjust mds slave's qunit size failed!(rc:%d)\n", rc);
314                 RETURN(rc);
315         }
316         if (QAQ_IS_GRP(oqaq))
317                 gid = oqaq->qaq_id;
318         else
319                 uid = oqaq->qaq_id;
320
321         if (rc > 0) {
322                 rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 0);
323                 if (rc == -EDQUOT || rc == -EBUSY) {
324                         CDEBUG(D_QUOTA, "rc: %d.\n", rc);
325                         rc = 0;
326                 }
327                 if (rc)
328                         CERROR("slave adjust block quota failed!(rc:%d)\n", rc);
329         }
330         RETURN(rc);
331 }
332 #endif /* __KERNEL__ */
333
334 int client_quota_adjust_qunit(struct obd_export *exp,
335                               struct quota_adjust_qunit *oqaq)
336 {
337         struct ptlrpc_request *req;
338         struct quota_adjust_qunit *oqa;
339         int size[2] = { sizeof(struct ptlrpc_body), sizeof(*oqaq) };
340         int rc = 0;
341         ENTRY;
342
343         /* client don't support this kind of operation, abort it */
344         if (!(exp->exp_connect_flags & OBD_CONNECT_CHANGE_QS)||
345             OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS)) {
346                 CDEBUG(D_QUOTA, "osc: %s don't support change qunit size\n",
347                        exp->exp_obd->obd_name);
348                 RETURN(rc);
349         }
350         if (strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
351                 RETURN(-EINVAL);
352
353         req = ptlrpc_prep_req(class_exp2cliimp(exp), LUSTRE_OST_VERSION,
354                               OST_QUOTA_ADJUST_QUNIT, 2, size, NULL);
355         if (!req)
356                 GOTO(out, rc = -ENOMEM);
357
358         oqa = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF, sizeof(*oqaq));
359         *oqa = *oqaq;
360
361         ptlrpc_req_set_repsize(req, 2, size);
362
363         rc = ptlrpc_queue_wait(req);
364         if (rc) {
365                 CERROR("%s: %s failed: rc = %d\n", exp->exp_obd->obd_name,
366                        __FUNCTION__, rc);
367                 GOTO(out, rc);
368         }
369         ptlrpc_req_finished(req);
370 out:
371         RETURN (rc);
372 }
373
374 int lov_quota_adjust_qunit(struct obd_export *exp,
375                            struct quota_adjust_qunit *oqaq)
376 {
377         struct obd_device *obd = class_exp2obd(exp);
378         struct lov_obd *lov = &obd->u.lov;
379         int i, rc = 0;
380         ENTRY;
381
382         if (!QAQ_IS_ADJBLK(oqaq)) {
383                 CERROR("bad qaq_flags %x for lov obd.\n", oqaq->qaq_flags);
384                 RETURN(-EFAULT);
385         }
386
387         for (i = 0; i < lov->desc.ld_tgt_count; i++) {
388                 int err;
389
390                 if (!lov->lov_tgts[i]->ltd_active) {
391                         CDEBUG(D_HA, "ost %d is inactive\n", i);
392                         continue;
393                 }
394
395                 err = obd_quota_adjust_qunit(lov->lov_tgts[i]->ltd_exp, oqaq);
396                 if (err) {
397                         if (lov->lov_tgts[i]->ltd_active && !rc)
398                                 rc = err;
399                         continue;
400                 }
401         }
402         RETURN(rc);
403 }