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