[go: nahoru, domu]

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
34static 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
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			/* 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
73int 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 */
138static unsigned
139oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
140{
141	return cfs_hash_u32_hash(*((__u32 *)key), mask);
142}
143
144static int
145oqi_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
157static void *
158oqi_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
165static void *
166oqi_object(struct hlist_node *hnode)
167{
168	return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
169}
170
171static void
172oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
173{
174}
175
176static void
177oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
178{
179}
180
181static void
182oqi_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
195static 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
205int 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
233int 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
244int 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
285int 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
314int 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