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