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