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 	OBD_SLAB_ALLOC_PTR(oqi, osc_quota_kmem);
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 				OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
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 				OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
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 	oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
162 	return &oqi->oqi_id;
163 }
164 
165 static void *
oqi_object(struct hlist_node * hnode)166 oqi_object(struct hlist_node *hnode)
167 {
168 	return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
169 }
170 
171 static void
oqi_get(struct cfs_hash * hs,struct hlist_node * hnode)172 oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
173 {
174 }
175 
176 static void
oqi_put_locked(struct cfs_hash * hs,struct hlist_node * hnode)177 oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
178 {
179 }
180 
181 static void
oqi_exit(struct cfs_hash * hs,struct hlist_node * hnode)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 	OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
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 cfs_hash_ops_t 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 
osc_quota_setup(struct obd_device * obd)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] == NULL)
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 
osc_quota_cleanup(struct obd_device * obd)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 
osc_quotactl(struct obd_device * unused,struct obd_export * exp,struct obd_quotactl * oqctl)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 == NULL)
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 
osc_quotacheck(struct obd_device * unused,struct obd_export * exp,struct obd_quotactl * oqctl)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 == NULL)
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
305 	 * going on */
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 
osc_quota_poll_check(struct obd_export * exp,struct if_quotacheck * qchk)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 }
328