GNU Linux-libre 4.9-gnu1
[releases.git] / drivers / staging / lustre / 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  * GPL HEADER END
17  */
18 /*
19  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
20  *
21  * Copyright (c) 2011, 2015, Intel Corporation.
22  *
23  * Code originally extracted from quota directory
24  */
25
26 #include "../include/obd_class.h"
27 #include "osc_internal.h"
28
29 static inline struct osc_quota_info *osc_oqi_alloc(u32 id)
30 {
31         struct osc_quota_info *oqi;
32
33         oqi = kmem_cache_zalloc(osc_quota_kmem, GFP_NOFS);
34         if (oqi)
35                 oqi->oqi_id = id;
36
37         return oqi;
38 }
39
40 int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
41 {
42         int type;
43
44         for (type = 0; type < MAXQUOTAS; type++) {
45                 struct osc_quota_info *oqi;
46
47                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
48                 if (oqi) {
49                         /* do not try to access oqi here, it could have been
50                          * freed by osc_quota_setdq()
51                          */
52
53                         /* the slot is busy, the user is about to run out of
54                          * quota space on this OST
55                          */
56                         CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
57                                type == USRQUOTA ? "user" : "grout", qid[type]);
58                         return NO_QUOTA;
59                 }
60         }
61
62         return QUOTA_OK;
63 }
64
65 #define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
66                                                 : OBD_MD_FLGRPQUOTA)
67 #define FL_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_FL_NO_USRQUOTA \
68                                                 : OBD_FL_NO_GRPQUOTA)
69
70 int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[],
71                     u32 valid, u32 flags)
72 {
73         int type;
74         int rc = 0;
75
76         if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0)
77                 return 0;
78
79         for (type = 0; type < MAXQUOTAS; type++) {
80                 struct osc_quota_info *oqi;
81
82                 if ((valid & MD_QUOTA_FLAG(type)) == 0)
83                         continue;
84
85                 /* lookup the ID in the per-type hash table */
86                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
87                 if ((flags & FL_QUOTA_FLAG(type)) != 0) {
88                         /* This ID is getting close to its quota limit, let's
89                          * switch to sync I/O
90                          */
91                         if (oqi)
92                                 continue;
93
94                         oqi = osc_oqi_alloc(qid[type]);
95                         if (!oqi) {
96                                 rc = -ENOMEM;
97                                 break;
98                         }
99
100                         rc = cfs_hash_add_unique(cli->cl_quota_hash[type],
101                                                  &qid[type], &oqi->oqi_hash);
102                         /* race with others? */
103                         if (rc == -EALREADY) {
104                                 rc = 0;
105                                 kmem_cache_free(osc_quota_kmem, oqi);
106                         }
107
108                         CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n",
109                                cli->cl_import->imp_obd->obd_name,
110                                type == USRQUOTA ? "user" : "group",
111                                qid[type], rc);
112                 } else {
113                         /* This ID is now off the hook, let's remove it from
114                          * the hash table
115                          */
116                         if (!oqi)
117                                 continue;
118
119                         oqi = cfs_hash_del_key(cli->cl_quota_hash[type],
120                                                &qid[type]);
121                         if (oqi)
122                                 kmem_cache_free(osc_quota_kmem, oqi);
123
124                         CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n",
125                                cli->cl_import->imp_obd->obd_name,
126                                type == USRQUOTA ? "user" : "group",
127                                qid[type], oqi);
128                 }
129         }
130
131         return rc;
132 }
133
134 /*
135  * Hash operations for uid/gid <-> osc_quota_info
136  */
137 static unsigned
138 oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
139 {
140         return cfs_hash_u32_hash(*((__u32 *)key), mask);
141 }
142
143 static int
144 oqi_keycmp(const void *key, struct hlist_node *hnode)
145 {
146         struct osc_quota_info *oqi;
147         u32 uid;
148
149         LASSERT(key);
150         uid = *((u32 *)key);
151         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
152
153         return uid == oqi->oqi_id;
154 }
155
156 static void *
157 oqi_key(struct hlist_node *hnode)
158 {
159         struct osc_quota_info *oqi;
160
161         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
162         return &oqi->oqi_id;
163 }
164
165 static void *
166 oqi_object(struct hlist_node *hnode)
167 {
168         return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
169 }
170
171 static void
172 oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
173 {
174 }
175
176 static void
177 oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
178 {
179 }
180
181 static void
182 oqi_exit(struct cfs_hash *hs, struct hlist_node *hnode)
183 {
184         struct osc_quota_info *oqi;
185
186         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
187
188         kmem_cache_free(osc_quota_kmem, oqi);
189 }
190
191 #define HASH_QUOTA_BKT_BITS 5
192 #define HASH_QUOTA_CUR_BITS 5
193 #define HASH_QUOTA_MAX_BITS 15
194
195 static struct cfs_hash_ops quota_hash_ops = {
196         .hs_hash        = oqi_hashfn,
197         .hs_keycmp      = oqi_keycmp,
198         .hs_key         = oqi_key,
199         .hs_object      = oqi_object,
200         .hs_get         = oqi_get,
201         .hs_put_locked  = oqi_put_locked,
202         .hs_exit        = oqi_exit,
203 };
204
205 int osc_quota_setup(struct obd_device *obd)
206 {
207         struct client_obd *cli = &obd->u.cli;
208         int i, type;
209
210         for (type = 0; type < MAXQUOTAS; type++) {
211                 cli->cl_quota_hash[type] = cfs_hash_create("QUOTA_HASH",
212                                                            HASH_QUOTA_CUR_BITS,
213                                                            HASH_QUOTA_MAX_BITS,
214                                                            HASH_QUOTA_BKT_BITS,
215                                                            0,
216                                                            CFS_HASH_MIN_THETA,
217                                                            CFS_HASH_MAX_THETA,
218                                                            &quota_hash_ops,
219                                                            CFS_HASH_DEFAULT);
220                 if (!cli->cl_quota_hash[type])
221                         break;
222         }
223
224         if (type == MAXQUOTAS)
225                 return 0;
226
227         for (i = 0; i < type; i++)
228                 cfs_hash_putref(cli->cl_quota_hash[i]);
229
230         return -ENOMEM;
231 }
232
233 int osc_quota_cleanup(struct obd_device *obd)
234 {
235         struct client_obd *cli = &obd->u.cli;
236         int type;
237
238         for (type = 0; type < MAXQUOTAS; type++)
239                 cfs_hash_putref(cli->cl_quota_hash[type]);
240
241         return 0;
242 }
243
244 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
245                  struct obd_quotactl *oqctl)
246 {
247         struct ptlrpc_request *req;
248         struct obd_quotactl *oqc;
249         int rc;
250
251         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
252                                         &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
253                                         OST_QUOTACTL);
254         if (!req)
255                 return -ENOMEM;
256
257         oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
258         *oqc = *oqctl;
259
260         ptlrpc_request_set_replen(req);
261         ptlrpc_at_set_req_timeout(req);
262         req->rq_no_resend = 1;
263
264         rc = ptlrpc_queue_wait(req);
265         if (rc)
266                 CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
267
268         if (req->rq_repmsg) {
269                 oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
270                 if (oqc) {
271                         *oqctl = *oqc;
272                 } else if (!rc) {
273                         CERROR("Can't unpack obd_quotactl\n");
274                         rc = -EPROTO;
275                 }
276         } else if (!rc) {
277                 CERROR("Can't unpack obd_quotactl\n");
278                 rc = -EPROTO;
279         }
280         ptlrpc_req_finished(req);
281
282         return rc;
283 }
284
285 int osc_quotacheck(struct obd_device *unused, struct obd_export *exp,
286                    struct obd_quotactl *oqctl)
287 {
288         struct client_obd *cli = &exp->exp_obd->u.cli;
289         struct ptlrpc_request *req;
290         struct obd_quotactl *body;
291         int rc;
292
293         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
294                                         &RQF_OST_QUOTACHECK, LUSTRE_OST_VERSION,
295                                         OST_QUOTACHECK);
296         if (!req)
297                 return -ENOMEM;
298
299         body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
300         *body = *oqctl;
301
302         ptlrpc_request_set_replen(req);
303
304         /* the next poll will find -ENODATA, that means quotacheck is going on
305          */
306         cli->cl_qchk_stat = -ENODATA;
307         rc = ptlrpc_queue_wait(req);
308         if (rc)
309                 cli->cl_qchk_stat = rc;
310         ptlrpc_req_finished(req);
311         return rc;
312 }
313
314 int osc_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
315 {
316         struct client_obd *cli = &exp->exp_obd->u.cli;
317         int rc;
318
319         qchk->obd_uuid = cli->cl_target_uuid;
320         memcpy(qchk->obd_type, LUSTRE_OST_NAME, strlen(LUSTRE_OST_NAME));
321
322         rc = cli->cl_qchk_stat;
323         /* the client is not the previous one */
324         if (rc == CL_NOT_QUOTACHECKED)
325                 rc = -EINTR;
326         return rc;
327 }