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