1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2003 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
8 * Lustre is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * Lustre is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Lustre; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 # define EXPORT_SYMTAB
25 #define DEBUG_SUBSYSTEM S_OSC
28 # include <linux/module.h>
29 # include <linux/obd.h>
30 # include <linux/obd_ost.h>
31 # include <linux/lustre_net.h>
32 # include <linux/lustre_dlm.h>
33 # include <linux/lustre_lib.h>
34 # include <linux/lustre_compat25.h>
35 # if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
36 # include <linux/workqueue.h>
37 # include <linux/smp_lock.h>
39 # include <linux/locks.h>
43 #include "osc_internal.h"
45 struct osc_quota_info {
46 struct list_head oqi_hash; /* hash list */
47 struct client_obd *oqi_cli; /* osc obd */
48 unsigned int oqi_id; /* uid/gid of a file */
49 short oqi_type; /* quota type */
50 unsigned long oqi_flag; /* flag, NO_QUOTA */
53 spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
55 static struct list_head qinfo_hash[NR_DQHASH];
56 /* SLAB cache for client quota context */
57 kmem_cache_t *qinfo_cachep = NULL;
59 static inline int const hashfn(struct client_obd *cli,
63 unsigned long tmp = ((unsigned long)cli>>6) ^ id;
64 tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
68 static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
70 struct list_head *head = qinfo_hash +
71 hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
72 list_add(&oqi->oqi_hash, head);
75 static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
77 list_del_init(&oqi->oqi_hash);
80 static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
81 unsigned int id, int type)
83 unsigned int hashent = hashfn(cli, id, type);
84 struct list_head *head;
85 struct osc_quota_info *oqi;
87 for (head = qinfo_hash[hashent].next;
88 head != qinfo_hash+hashent; head = head->next) {
89 oqi = list_entry(head, struct osc_quota_info, oqi_hash);
90 LASSERT(oqi->oqi_flag == NO_QUOTA);
91 if (oqi->oqi_cli == cli &&
92 oqi->oqi_id == id && oqi->oqi_type == type)
98 static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
99 unsigned int id, int type)
101 struct osc_quota_info *oqi;
104 OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL,
109 INIT_LIST_HEAD(&oqi->oqi_hash);
112 oqi->oqi_type = type;
117 static void free_qinfo(struct osc_quota_info *oqi)
119 OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
122 int osc_get_quota_flag(struct client_obd *cli,
123 unsigned int uid, unsigned int gid)
126 int cnt, rc = QUOTA_OK;
129 spin_lock(&qinfo_list_lock);
130 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
131 struct osc_quota_info *oqi = NULL;
133 id = (cnt == USRQUOTA) ? uid : gid;
134 oqi = find_qinfo(cli, id, cnt);
140 spin_unlock(&qinfo_list_lock);
145 int osc_set_quota_flag(struct client_obd *cli,
146 unsigned int uid, unsigned int gid,
147 obd_flag valid, obd_flag flags)
154 spin_lock(&qinfo_list_lock);
156 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
157 struct osc_quota_info *oqi = NULL;
159 if (!(valid & ((cnt == USRQUOTA) ?
160 OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
163 id = (cnt == USRQUOTA) ? uid : gid;
164 noquota = (cnt == USRQUOTA) ?
165 (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
167 oqi = find_qinfo(cli, id, cnt);
169 if (oqi && !noquota) {
170 remove_qinfo_hash(oqi);
172 } else if (!oqi && noquota) {
173 oqi = alloc_qinfo(cli, id, cnt);
175 CERROR("not enough mem!\n");
179 oqi->oqi_flag = NO_QUOTA;
180 insert_qinfo_hash(oqi);
184 spin_unlock(&qinfo_list_lock);
189 int osc_qinfo_cleanup(struct client_obd *cli)
191 struct osc_quota_info *oqi, *n;
195 spin_lock(&qinfo_list_lock);
196 for (i = 0; i < NR_DQHASH; i++) {
197 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
198 if (oqi->oqi_cli != cli)
200 remove_qinfo_hash(oqi);
204 spin_unlock(&qinfo_list_lock);
209 int osc_qinfo_init(void)
214 LASSERT(qinfo_cachep == NULL);
215 qinfo_cachep = kmem_cache_create("osc_quota_info",
216 sizeof(struct osc_quota_info),
221 for (i = 0; i < NR_DQHASH; i++)
222 INIT_LIST_HEAD(qinfo_hash + i);
227 void osc_qinfo_exit(void)
229 struct osc_quota_info *oqi, *n;
233 spin_lock(&qinfo_list_lock);
234 for (i = 0; i < NR_DQHASH; i++) {
235 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
236 remove_qinfo_hash(oqi);
240 spin_unlock(&qinfo_list_lock);
242 LASSERTF(kmem_cache_destroy(qinfo_cachep) == 0,
243 "couldn't destroy osc quota info slab\n");