Whamcloud - gitweb
LU-8191 liblustre: add missing functions to header
[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) { /* ID already cached */
123                                 bits = xa_to_value(qtypes);
124                                 /* test if ID type already set */
125                                 if (!(bits & BIT(type))) {
126                                         bits |= BIT(type);
127                                         rc = xa_err(xa_store(&cli->cl_quota_exceeded_ids,
128                                                              qid[type],
129                                                              xa_mk_value(bits),
130                                                              GFP_KERNEL));
131                                         if (rc < 0)
132                                                 GOTO(out_unlock, rc);
133                                 }
134                                 continue;
135                         }
136
137                         /* Only insert if we see the this ID for the
138                          * very first time.
139                          */
140                         bits |= BIT(type);
141                         rc = ll_xa_insert(&cli->cl_quota_exceeded_ids,
142                                           qid[type], xa_mk_value(bits),
143                                           GFP_KERNEL);
144                         if (rc == -ENOMEM)
145                                 break;
146
147                         CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d: rc = %d\n",
148                                cli_name(cli), qtype_name(type), qid[type], rc);
149                 } else {
150                         /* This ID is now off the hook, let's remove it from
151                          * the xarray
152                          */
153                         if (!qtypes)
154                                 continue;
155
156                         bits = xa_to_value(qtypes);
157                         if (!(bits & BIT(type)))
158                                 continue;
159
160                         bits &= ~BIT(type);
161                         if (bits) {
162                                 rc = xa_err(xa_store(&cli->cl_quota_exceeded_ids,
163                                                      qid[type],
164                                                      xa_mk_value(bits),
165                                                      GFP_KERNEL));
166                                 if (rc < 0)
167                                         GOTO(out_unlock, rc);
168                         } else {
169                                 xa_erase(&cli->cl_quota_exceeded_ids, qid[type]);
170                         }
171
172                         CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d\n",
173                                cli_name(cli), qtype_name(type), qid[type]);
174                 }
175         }
176
177 out_unlock:
178         mutex_unlock(&cli->cl_quota_mutex);
179         RETURN(rc);
180 }
181
182 int osc_quota_setup(struct obd_device *obd)
183 {
184         struct client_obd *cli = &obd->u.cli;
185
186         mutex_init(&cli->cl_quota_mutex);
187
188         xa_init(&cli->cl_quota_exceeded_ids);
189
190         return 0;
191 }
192
193 void osc_quota_cleanup(struct obd_device *obd)
194 {
195         struct client_obd *cli = &obd->u.cli;
196
197         xa_destroy(&cli->cl_quota_exceeded_ids);
198 }
199
200 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
201                  struct obd_quotactl *oqctl)
202 {
203         struct ptlrpc_request *req;
204         struct obd_quotactl   *oqc;
205         int                    rc;
206         ENTRY;
207
208         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
209                                         &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
210                                         OST_QUOTACTL);
211         if (req == NULL)
212                 RETURN(-ENOMEM);
213
214         oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
215         *oqc = *oqctl;
216
217         ptlrpc_request_set_replen(req);
218         ptlrpc_at_set_req_timeout(req);
219         req->rq_no_resend = 1;
220
221         rc = ptlrpc_queue_wait(req);
222         if (rc)
223                 CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
224
225         if (req->rq_repmsg &&
226             (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
227                 *oqctl = *oqc;
228         } else if (!rc) {
229                 CERROR ("Can't unpack obd_quotactl\n");
230                 rc = -EPROTO;
231         }
232         ptlrpc_req_finished(req);
233
234         RETURN(rc);
235 }