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 "a_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