Whamcloud - gitweb
LU-14027 tests: Fix test_135 of replay-single
[fs/lustre-release.git] / lustre / osc / osc_quota.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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
25  *
26  * Copyright (c) 2012, 2017, Intel Corporation.
27  *
28  * Code originally extracted from quota directory
29  */
30
31 #include <obd_class.h>
32 #include <lustre_osc.h>
33
34 #include "osc_internal.h"
35
36 int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
37 {
38         int type;
39
40         ENTRY;
41         for (type = 0; type < LL_MAXQUOTAS; type++) {
42                 u8 *qtype;
43
44                 qtype = xa_load(&cli->cl_quota_exceeded_ids, qid[type]);
45                 if (qtype && (xa_to_value(qtype) & BIT(type))) {
46                         /* the slot is busy, the user is about to run out of
47                          * quota space on this OST
48                          */
49                         CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
50                                qtype_name(type), qid[type]);
51                         RETURN(-EDQUOT);
52                 }
53         }
54
55         RETURN(0);
56 }
57
58 static inline u32 md_quota_flag(int qtype)
59 {
60         switch (qtype) {
61         case USRQUOTA:
62                 return OBD_MD_FLUSRQUOTA;
63         case GRPQUOTA:
64                 return OBD_MD_FLGRPQUOTA;
65         case PRJQUOTA:
66                 return OBD_MD_FLPRJQUOTA;
67         default:
68                 return 0;
69         }
70 }
71
72 static inline u32 fl_quota_flag(int qtype)
73 {
74         switch (qtype) {
75         case USRQUOTA:
76                 return OBD_FL_NO_USRQUOTA;
77         case GRPQUOTA:
78                 return OBD_FL_NO_GRPQUOTA;
79         case PRJQUOTA:
80                 return OBD_FL_NO_PRJQUOTA;
81         default:
82                 return 0;
83         }
84 }
85
86 int osc_quota_setdq(struct client_obd *cli, u64 xid, const unsigned int qid[],
87                     u64 valid, u32 flags)
88 {
89         int type;
90         int rc = 0;
91
92         ENTRY;
93         if ((valid & (OBD_MD_FLALLQUOTA)) == 0)
94                 RETURN(0);
95
96         mutex_lock(&cli->cl_quota_mutex);
97         cli->cl_root_squash = !!(flags & OBD_FL_ROOT_SQUASH);
98         cli->cl_root_prjquota = !!(flags & OBD_FL_ROOT_PRJQUOTA);
99         /* still mark the quots is running out for the old request, because it
100          * could be processed after the new request at OST, the side effect is
101          * the following request will be processed synchronously, but it will
102          * not break the quota enforcement. */
103         if (cli->cl_quota_last_xid > xid && !(flags & OBD_FL_NO_QUOTA_ALL))
104                 GOTO(out_unlock, rc);
105
106         if (cli->cl_quota_last_xid < xid)
107                 cli->cl_quota_last_xid = xid;
108
109         for (type = 0; type < LL_MAXQUOTAS; type++) {
110                 unsigned long bits = 0;
111                 u8 *qtypes;
112
113                 if ((valid & md_quota_flag(type)) == 0)
114                         continue;
115
116                 /* lookup the quota IDs in the ID xarray */
117                 qtypes = xa_load(&cli->cl_quota_exceeded_ids, qid[type]);
118                 if ((flags & fl_quota_flag(type)) != 0) {
119                         /* This ID is getting close to its quota limit, let's
120                          * switch to sync I/O
121                          */
122                         if (qtypes) {
123                                 bits = xa_to_value(qtypes);
124                                 /* test if already set */
125                                 if (bits & BIT(type))
126                                         continue;
127                         }
128
129                         bits |= BIT(type);
130                         rc = xa_insert(&cli->cl_quota_exceeded_ids, qid[type],
131                                        xa_mk_value(bits), GFP_KERNEL);
132                         if (rc)
133                                 break;
134
135                         CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d: rc = %d\n",
136                                cli_name(cli), qtype_name(type), qid[type], rc);
137                 } else {
138                         /* This ID is now off the hook, let's remove it from
139                          * the xarray
140                          */
141                         if (!qtypes)
142                                 continue;
143
144                         bits = xa_to_value(qtypes);
145                         if (!(bits & BIT(type)))
146                                 continue;
147
148                         bits &= ~BIT(type);
149                         if (bits) {
150                                 if (xa_cmpxchg(&cli->cl_quota_exceeded_ids,
151                                                qid[type], qtypes,
152                                                xa_mk_value(bits),
153                                                GFP_KERNEL) != qtypes)
154                                         GOTO(out_unlock, rc = -ENOENT);
155                         } else {
156                                 xa_erase(&cli->cl_quota_exceeded_ids, qid[type]);
157                         }
158
159                         CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d\n",
160                                cli_name(cli), qtype_name(type), qid[type]);
161                 }
162         }
163
164 out_unlock:
165         mutex_unlock(&cli->cl_quota_mutex);
166         RETURN(rc);
167 }
168
169 int osc_quota_setup(struct obd_device *obd)
170 {
171         struct client_obd *cli = &obd->u.cli;
172
173         mutex_init(&cli->cl_quota_mutex);
174
175         xa_init(&cli->cl_quota_exceeded_ids);
176
177         return 0;
178 }
179
180 void osc_quota_cleanup(struct obd_device *obd)
181 {
182         struct client_obd *cli = &obd->u.cli;
183
184         xa_destroy(&cli->cl_quota_exceeded_ids);
185 }
186
187 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
188                  struct obd_quotactl *oqctl)
189 {
190         struct ptlrpc_request *req;
191         struct obd_quotactl   *oqc;
192         int                    rc;
193         ENTRY;
194
195         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
196                                         &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
197                                         OST_QUOTACTL);
198         if (req == NULL)
199                 RETURN(-ENOMEM);
200
201         oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
202         *oqc = *oqctl;
203
204         ptlrpc_request_set_replen(req);
205         ptlrpc_at_set_req_timeout(req);
206         req->rq_no_resend = 1;
207
208         rc = ptlrpc_queue_wait(req);
209         if (rc)
210                 CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
211
212         if (req->rq_repmsg &&
213             (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
214                 *oqctl = *oqc;
215         } else if (!rc) {
216                 CERROR ("Can't unpack obd_quotactl\n");
217                 rc = -EPROTO;
218         }
219         ptlrpc_req_finished(req);
220
221         RETURN(rc);
222 }