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