linux/drivers/staging/lustre/lustre/osc/osc_quota.c
<<
>>
Prefs
   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 * GPL HEADER END
  17 */
  18/*
  19 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  20 *
  21 * Copyright (c) 2011, 2015, Intel Corporation.
  22 *
  23 * Code originally extracted from quota directory
  24 */
  25
  26#include "../include/obd_class.h"
  27#include "osc_internal.h"
  28
  29static inline struct osc_quota_info *osc_oqi_alloc(u32 id)
  30{
  31        struct osc_quota_info *oqi;
  32
  33        oqi = kmem_cache_zalloc(osc_quota_kmem, GFP_NOFS);
  34        if (oqi)
  35                oqi->oqi_id = id;
  36
  37        return oqi;
  38}
  39
  40int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[])
  41{
  42        int type;
  43
  44        for (type = 0; type < MAXQUOTAS; type++) {
  45                struct osc_quota_info *oqi;
  46
  47                oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
  48                if (oqi) {
  49                        /* do not try to access oqi here, it could have been
  50                         * freed by osc_quota_setdq()
  51                         */
  52
  53                        /* the slot is busy, the user is about to run out of
  54                         * quota space on this OST
  55                         */
  56                        CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n",
  57                               type == USRQUOTA ? "user" : "grout", qid[type]);
  58                        return NO_QUOTA;
  59                }
  60        }
  61
  62        return QUOTA_OK;
  63}
  64
  65#define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
  66                                                : OBD_MD_FLGRPQUOTA)
  67#define FL_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_FL_NO_USRQUOTA \
  68                                                : OBD_FL_NO_GRPQUOTA)
  69
  70int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[],
  71                    u32 valid, u32 flags)
  72{
  73        int type;
  74        int rc = 0;
  75
  76        if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0)
  77                return 0;
  78
  79        for (type = 0; type < MAXQUOTAS; type++) {
  80                struct osc_quota_info *oqi;
  81
  82                if ((valid & MD_QUOTA_FLAG(type)) == 0)
  83                        continue;
  84
  85                /* lookup the ID in the per-type hash table */
  86                oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
  87                if ((flags & FL_QUOTA_FLAG(type)) != 0) {
  88                        /* This ID is getting close to its quota limit, let's
  89                         * switch to sync I/O
  90                         */
  91                        if (oqi)
  92                                continue;
  93
  94                        oqi = osc_oqi_alloc(qid[type]);
  95                        if (!oqi) {
  96                                rc = -ENOMEM;
  97                                break;
  98                        }
  99
 100                        rc = cfs_hash_add_unique(cli->cl_quota_hash[type],
 101                                                 &qid[type], &oqi->oqi_hash);
 102                        /* race with others? */
 103                        if (rc == -EALREADY) {
 104                                rc = 0;
 105                                kmem_cache_free(osc_quota_kmem, oqi);
 106                        }
 107
 108                        CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n",
 109                               cli->cl_import->imp_obd->obd_name,
 110                               type == USRQUOTA ? "user" : "group",
 111                               qid[type], rc);
 112                } else {
 113                        /* This ID is now off the hook, let's remove it from
 114                         * the hash table
 115                         */
 116                        if (!oqi)
 117                                continue;
 118
 119                        oqi = cfs_hash_del_key(cli->cl_quota_hash[type],
 120                                               &qid[type]);
 121                        if (oqi)
 122                                kmem_cache_free(osc_quota_kmem, oqi);
 123
 124                        CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n",
 125                               cli->cl_import->imp_obd->obd_name,
 126                               type == USRQUOTA ? "user" : "group",
 127                               qid[type], oqi);
 128                }
 129        }
 130
 131        return rc;
 132}
 133
 134/*
 135 * Hash operations for uid/gid <-> osc_quota_info
 136 */
 137static unsigned
 138oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask)
 139{
 140        return cfs_hash_u32_hash(*((__u32 *)key), mask);
 141}
 142
 143static int
 144oqi_keycmp(const void *key, struct hlist_node *hnode)
 145{
 146        struct osc_quota_info *oqi;
 147        u32 uid;
 148
 149        LASSERT(key);
 150        uid = *((u32 *)key);
 151        oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
 152
 153        return uid == oqi->oqi_id;
 154}
 155
 156static void *
 157oqi_key(struct hlist_node *hnode)
 158{
 159        struct osc_quota_info *oqi;
 160
 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        kmem_cache_free(osc_quota_kmem, oqi);
 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 struct cfs_hash_ops 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])
 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)
 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)
 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 going on
 305         */
 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