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