Whamcloud - gitweb
LU-16518 misc: use fixed hash code
[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.h>
32 #include <lustre_osc.h>
33
34 #include "osc_internal.h"
35
36 static inline struct osc_quota_info *osc_oqi_alloc(u32 id)
37 {
38         struct osc_quota_info *oqi;
39
40         OBD_SLAB_ALLOC_PTR(oqi, osc_quota_kmem);
41         if (oqi != NULL)
42                 oqi->oqi_id = id;
43
44         return oqi;
45 }
46
47 int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
48 {
49         int type;
50         ENTRY;
51
52         for (type = 0; type < LL_MAXQUOTAS; type++) {
53                 struct osc_quota_info *oqi;
54
55                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
56                 if (oqi) {
57                         /* do not try to access oqi here, it could have been
58                          * freed by osc_quota_setdq() */
59
60                         /* the slot is busy, the user is about to run out of
61                          * quota space on this OST */
62                         CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
63                                type == USRQUOTA ? "user" : "grout", qid[type]);
64                         RETURN(-EDQUOT);
65                 }
66         }
67
68         RETURN(0);
69 }
70
71 static inline u32 md_quota_flag(int qtype)
72 {
73         switch (qtype) {
74         case USRQUOTA:
75                 return OBD_MD_FLUSRQUOTA;
76         case GRPQUOTA:
77                 return OBD_MD_FLGRPQUOTA;
78         case PRJQUOTA:
79                 return OBD_MD_FLPRJQUOTA;
80         default:
81                 return 0;
82         }
83 }
84
85 static inline u32 fl_quota_flag(int qtype)
86 {
87         switch (qtype) {
88         case USRQUOTA:
89                 return OBD_FL_NO_USRQUOTA;
90         case GRPQUOTA:
91                 return OBD_FL_NO_GRPQUOTA;
92         case PRJQUOTA:
93                 return OBD_FL_NO_PRJQUOTA;
94         default:
95                 return 0;
96         }
97 }
98
99 int osc_quota_setdq(struct client_obd *cli, __u64 xid, const unsigned int qid[],
100                     u64 valid, u32 flags)
101 {
102         int type;
103         int rc = 0;
104
105         ENTRY;
106
107         if ((valid & (OBD_MD_FLALLQUOTA)) == 0)
108                 RETURN(0);
109
110         mutex_lock(&cli->cl_quota_mutex);
111         cli->cl_root_squash = !!(flags & OBD_FL_ROOT_SQUASH);
112         cli->cl_root_prjquota = !!(flags & OBD_FL_ROOT_PRJQUOTA);
113         /* still mark the quots is running out for the old request, because it
114          * could be processed after the new request at OST, the side effect is
115          * the following request will be processed synchronously, but it will
116          * not break the quota enforcement. */
117         if (cli->cl_quota_last_xid > xid && !(flags & OBD_FL_NO_QUOTA_ALL))
118                 GOTO(out_unlock, rc);
119
120         if (cli->cl_quota_last_xid < xid)
121                 cli->cl_quota_last_xid = xid;
122
123         for (type = 0; type < LL_MAXQUOTAS; type++) {
124                 struct osc_quota_info *oqi;
125
126                 if ((valid & md_quota_flag(type)) == 0)
127                         continue;
128
129                 /* lookup the ID in the per-type hash table */
130                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
131                 if ((flags & fl_quota_flag(type)) != 0) {
132                         /* This ID is getting close to its quota limit, let's
133                          * switch to sync I/O */
134                         if (oqi != NULL)
135                                 continue;
136
137                         oqi = osc_oqi_alloc(qid[type]);
138                         if (oqi == NULL) {
139                                 rc = -ENOMEM;
140                                 break;
141                         }
142
143                         rc = cfs_hash_add_unique(cli->cl_quota_hash[type],
144                                                  &qid[type], &oqi->oqi_hash);
145                         /* race with others? */
146                         if (rc == -EALREADY) {
147                                 rc = 0;
148                                 OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
149                         }
150
151                         CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n",
152                                cli_name(cli), qtype_name(type), qid[type], rc);
153                 } else {
154                         /* This ID is now off the hook, let's remove it from
155                          * the hash table */
156                         if (oqi == NULL)
157                                 continue;
158
159                         oqi = cfs_hash_del_key(cli->cl_quota_hash[type],
160                                                &qid[type]);
161                         if (oqi)
162                                 OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
163
164                         CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n",
165                                cli_name(cli), qtype_name(type), qid[type], oqi);
166                 }
167         }
168
169 out_unlock:
170         mutex_unlock(&cli->cl_quota_mutex);
171         RETURN(rc);
172 }
173
174 /*
175  * Hash operations for uid/gid <-> osc_quota_info
176  */
177 static unsigned
178 oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
179 {
180         return cfs_hash_32(*((__u32 *)key), 0) & mask;
181 }
182
183 static int
184 oqi_keycmp(const void *key, struct hlist_node *hnode)
185 {
186         struct osc_quota_info *oqi;
187         u32 uid;
188
189         LASSERT(key != NULL);
190         uid = *((u32 *)key);
191         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
192
193         return uid == oqi->oqi_id;
194 }
195
196 static void *
197 oqi_key(struct hlist_node *hnode)
198 {
199         struct osc_quota_info *oqi;
200         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
201         return &oqi->oqi_id;
202 }
203
204 static void *
205 oqi_object(struct hlist_node *hnode)
206 {
207         return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
208 }
209
210 static void
211 oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
212 {
213 }
214
215 static void
216 oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
217 {
218 }
219
220 static void
221 oqi_exit(struct cfs_hash *hs, struct hlist_node *hnode)
222 {
223         struct osc_quota_info *oqi;
224
225         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
226
227         OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
228 }
229
230 #define HASH_QUOTA_BKT_BITS 5
231 #define HASH_QUOTA_CUR_BITS 5
232 #define HASH_QUOTA_MAX_BITS 15
233
234 static struct cfs_hash_ops quota_hash_ops = {
235         .hs_hash        = oqi_hashfn,
236         .hs_keycmp      = oqi_keycmp,
237         .hs_key         = oqi_key,
238         .hs_object      = oqi_object,
239         .hs_get         = oqi_get,
240         .hs_put_locked  = oqi_put_locked,
241         .hs_exit        = oqi_exit,
242 };
243
244 int osc_quota_setup(struct obd_device *obd)
245 {
246         struct client_obd *cli = &obd->u.cli;
247         int i, type;
248         ENTRY;
249
250         mutex_init(&cli->cl_quota_mutex);
251
252         for (type = 0; type < LL_MAXQUOTAS; type++) {
253                 cli->cl_quota_hash[type] = cfs_hash_create("QUOTA_HASH",
254                                                            HASH_QUOTA_CUR_BITS,
255                                                            HASH_QUOTA_MAX_BITS,
256                                                            HASH_QUOTA_BKT_BITS,
257                                                            0,
258                                                            CFS_HASH_MIN_THETA,
259                                                            CFS_HASH_MAX_THETA,
260                                                            &quota_hash_ops,
261                                                            CFS_HASH_DEFAULT);
262                 if (cli->cl_quota_hash[type] == NULL)
263                         break;
264         }
265
266         if (type == LL_MAXQUOTAS)
267                 RETURN(0);
268
269         for (i = 0; i < type; i++)
270                 cfs_hash_putref(cli->cl_quota_hash[i]);
271
272         RETURN(-ENOMEM);
273 }
274
275 int osc_quota_cleanup(struct obd_device *obd)
276 {
277         struct client_obd     *cli = &obd->u.cli;
278         int type;
279         ENTRY;
280
281         for (type = 0; type < LL_MAXQUOTAS; type++)
282                 cfs_hash_putref(cli->cl_quota_hash[type]);
283
284         RETURN(0);
285 }
286
287 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
288                  struct obd_quotactl *oqctl)
289 {
290         struct ptlrpc_request *req;
291         struct obd_quotactl   *oqc;
292         int                    rc;
293         ENTRY;
294
295         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
296                                         &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
297                                         OST_QUOTACTL);
298         if (req == NULL)
299                 RETURN(-ENOMEM);
300
301         oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
302         *oqc = *oqctl;
303
304         ptlrpc_request_set_replen(req);
305         ptlrpc_at_set_req_timeout(req);
306         req->rq_no_resend = 1;
307
308         rc = ptlrpc_queue_wait(req);
309         if (rc)
310                 CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
311
312         if (req->rq_repmsg &&
313             (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
314                 *oqctl = *oqc;
315         } else if (!rc) {
316                 CERROR ("Can't unpack obd_quotactl\n");
317                 rc = -EPROTO;
318         }
319         ptlrpc_req_finished(req);
320
321         RETURN(rc);
322 }