Whamcloud - gitweb
f259f493188ace40eb32e9ef9699fc0c1aeba377
[fs/lustre-release.git] / 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) 2012, 2015, Intel Corporation.
27  *
28  * Code originally extracted from quota directory
29  */
30
31 #include <obd.h>
32 #include "osc_internal.h"
33
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
45 int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
46 {
47         int type;
48         ENTRY;
49
50         for (type = 0; type < LL_MAXQUOTAS; type++) {
51                 struct osc_quota_info *oqi;
52
53                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
54                 if (oqi) {
55                         /* do not try to access oqi here, it could have been
56                          * freed by osc_quota_setdq() */
57
58                         /* the slot is busy, the user is about to run out of
59                          * quota space on this OST */
60                         CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
61                                type == USRQUOTA ? "user" : "grout", qid[type]);
62                         RETURN(NO_QUOTA);
63                 }
64         }
65
66         RETURN(QUOTA_OK);
67 }
68
69 #define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
70                                                 : OBD_MD_FLGRPQUOTA)
71 #define FL_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_FL_NO_USRQUOTA \
72                                                 : OBD_FL_NO_GRPQUOTA)
73
74 int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[],
75                     u64 valid, u32 flags)
76 {
77         int type;
78         int rc = 0;
79         ENTRY;
80
81         if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0)
82                 RETURN(0);
83
84         for (type = 0; type < LL_MAXQUOTAS; type++) {
85                 struct osc_quota_info *oqi;
86
87                 if ((valid & MD_QUOTA_FLAG(type)) == 0)
88                         continue;
89
90                 /* lookup the ID in the per-type hash table */
91                 oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
92                 if ((flags & FL_QUOTA_FLAG(type)) != 0) {
93                         /* This ID is getting close to its quota limit, let's
94                          * switch to sync I/O */
95                         if (oqi != NULL)
96                                 continue;
97
98                         oqi = osc_oqi_alloc(qid[type]);
99                         if (oqi == NULL) {
100                                 rc = -ENOMEM;
101                                 break;
102                         }
103
104                         rc = cfs_hash_add_unique(cli->cl_quota_hash[type],
105                                                  &qid[type], &oqi->oqi_hash);
106                         /* race with others? */
107                         if (rc == -EALREADY) {
108                                 rc = 0;
109                                 OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
110                         }
111
112                         CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n",
113                                cli_name(cli),
114                                type == USRQUOTA ? "user" : "group",
115                                qid[type], rc);
116                 } else {
117                         /* This ID is now off the hook, let's remove it from
118                          * the hash table */
119                         if (oqi == NULL)
120                                 continue;
121
122                         oqi = cfs_hash_del_key(cli->cl_quota_hash[type],
123                                                &qid[type]);
124                         if (oqi)
125                                 OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
126
127                         CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n",
128                                cli_name(cli),
129                                type == USRQUOTA ? "user" : "group",
130                                qid[type], oqi);
131                 }
132         }
133
134         RETURN(rc);
135 }
136
137 /*
138  * Hash operations for uid/gid <-> osc_quota_info
139  */
140 static unsigned
141 oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
142 {
143         return cfs_hash_u32_hash(*((__u32*)key), mask);
144 }
145
146 static int
147 oqi_keycmp(const void *key, struct hlist_node *hnode)
148 {
149         struct osc_quota_info *oqi;
150         u32 uid;
151
152         LASSERT(key != NULL);
153         uid = *((u32 *)key);
154         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
155
156         return uid == oqi->oqi_id;
157 }
158
159 static void *
160 oqi_key(struct hlist_node *hnode)
161 {
162         struct osc_quota_info *oqi;
163         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
164         return &oqi->oqi_id;
165 }
166
167 static void *
168 oqi_object(struct hlist_node *hnode)
169 {
170         return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
171 }
172
173 static void
174 oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
175 {
176 }
177
178 static void
179 oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
180 {
181 }
182
183 static void
184 oqi_exit(struct cfs_hash *hs, struct hlist_node *hnode)
185 {
186         struct osc_quota_info *oqi;
187
188         oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
189
190         OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem);
191 }
192
193 #define HASH_QUOTA_BKT_BITS 5
194 #define HASH_QUOTA_CUR_BITS 5
195 #define HASH_QUOTA_MAX_BITS 15
196
197 static struct cfs_hash_ops quota_hash_ops = {
198         .hs_hash        = oqi_hashfn,
199         .hs_keycmp      = oqi_keycmp,
200         .hs_key         = oqi_key,
201         .hs_object      = oqi_object,
202         .hs_get         = oqi_get,
203         .hs_put_locked  = oqi_put_locked,
204         .hs_exit        = oqi_exit,
205 };
206
207 int osc_quota_setup(struct obd_device *obd)
208 {
209         struct client_obd *cli = &obd->u.cli;
210         int i, type;
211         ENTRY;
212
213         for (type = 0; type < LL_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 == LL_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         ENTRY;
241
242         for (type = 0; type < LL_MAXQUOTAS; type++)
243                 cfs_hash_putref(cli->cl_quota_hash[type]);
244
245         RETURN(0);
246 }
247
248 int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
249                  struct obd_quotactl *oqctl)
250 {
251         struct ptlrpc_request *req;
252         struct obd_quotactl   *oqc;
253         int                    rc;
254         ENTRY;
255
256         req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
257                                         &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
258                                         OST_QUOTACTL);
259         if (req == NULL)
260                 RETURN(-ENOMEM);
261
262         oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
263         *oqc = *oqctl;
264
265         ptlrpc_request_set_replen(req);
266         ptlrpc_at_set_req_timeout(req);
267         req->rq_no_resend = 1;
268
269         rc = ptlrpc_queue_wait(req);
270         if (rc)
271                 CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
272
273         if (req->rq_repmsg &&
274             (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
275                 *oqctl = *oqc;
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 }