]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/lustre/lustre/osc/osc_quota.c
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[karo-tx-linux.git] / drivers / staging / lustre / 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) 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
34 static 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
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                         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
76 int 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  */
141 static unsigned
142 oqi_hashfn(cfs_hash_t *hs, const void *key, unsigned mask)
143 {
144         return cfs_hash_u32_hash(*((__u32*)key), mask);
145 }
146
147 static int
148 oqi_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
160 static void *
161 oqi_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
168 static void *
169 oqi_object(struct hlist_node *hnode)
170 {
171         return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
172 }
173
174 static void
175 oqi_get(cfs_hash_t *hs, struct hlist_node *hnode)
176 {
177 }
178
179 static void
180 oqi_put_locked(cfs_hash_t *hs, struct hlist_node *hnode)
181 {
182 }
183
184 static void
185 oqi_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
198 static 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
208 int 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
236 int 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
247 int 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
283 int 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
312 int 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 }