Whamcloud - gitweb
b=3031
[fs/lustre-release.git] / lustre / osc / osc_quota.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2003 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
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.
11  *
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.
16  *
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.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_OSC
26
27 #ifdef __KERNEL__
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>
38 # else
39 #  include <linux/locks.h>
40 # endif
41 #endif
42
43 #include "osc_internal.h"
44
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 */
51 };
52
53 spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
54
55 static struct list_head qinfo_hash[NR_DQHASH];
56 /* SLAB cache for client quota context */
57 kmem_cache_t *qinfo_cachep = NULL;
58
59 static inline int const hashfn(struct client_obd *cli, 
60                                unsigned long id, 
61                                int type)
62 {
63         unsigned long tmp = ((unsigned long)cli>>6) ^ id;
64         tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
65         return tmp;
66 }
67
68 static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
69 {
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);
73 }
74
75 static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
76 {
77         list_del_init(&oqi->oqi_hash);
78 }
79
80 static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
81                                                 unsigned int id, int type)
82 {
83         unsigned int hashent = hashfn(cli, id, type);
84         struct list_head *head;
85         struct osc_quota_info *oqi;
86
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)
93                         return oqi;
94         }
95         return NULL;
96 }
97
98 static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
99                                           unsigned int id, int type)
100 {
101         struct osc_quota_info *oqi;
102         ENTRY;
103                                                                                                                              
104         OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL,
105                        sizeof(*oqi));
106         if(!oqi)
107                 RETURN(NULL);
108                                                                                                                              
109         INIT_LIST_HEAD(&oqi->oqi_hash);
110         oqi->oqi_cli = cli;
111         oqi->oqi_id = id;
112         oqi->oqi_type = type;
113                                                                                                                              
114         RETURN(oqi);
115 }
116                                                                                                                              
117 static void free_qinfo(struct osc_quota_info *oqi)
118 {
119         OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
120 }
121
122 int osc_get_quota_flag(struct client_obd *cli, 
123                        unsigned int uid, unsigned int gid)
124 {
125         unsigned int id;
126         int cnt, rc = QUOTA_OK;
127         ENTRY;
128
129         spin_lock(&qinfo_list_lock);
130         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
131                 struct osc_quota_info *oqi = NULL;
132
133                 id = (cnt == USRQUOTA) ? uid : gid;
134                 oqi = find_qinfo(cli, id, cnt);
135                 if (oqi) {
136                         rc = NO_QUOTA;
137                         break;
138                 }
139         }
140         spin_unlock(&qinfo_list_lock);
141
142         RETURN(rc);
143 }
144
145 int osc_set_quota_flag(struct client_obd *cli, 
146                        unsigned int uid, unsigned int gid,
147                        obd_flag valid, obd_flag flags)
148 {
149         unsigned int id;
150         obd_flag noquota;
151         int cnt, rc = 0;
152         ENTRY;
153
154         spin_lock(&qinfo_list_lock);
155
156         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
157                 struct osc_quota_info *oqi = NULL;
158
159                 if (!(valid & ((cnt == USRQUOTA) ? 
160                     OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
161                         continue; 
162
163                 id = (cnt == USRQUOTA) ? uid : gid;
164                 noquota = (cnt == USRQUOTA) ? 
165                     (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
166                 
167                 oqi = find_qinfo(cli, id, cnt);
168                 
169                 if (oqi && !noquota) {
170                         remove_qinfo_hash(oqi);
171                         free_qinfo(oqi);
172                 } else if (!oqi && noquota) {
173                         oqi = alloc_qinfo(cli, id, cnt);
174                         if (!oqi) {
175                                 CERROR("not enough mem!\n");
176                                 rc = -ENOMEM;
177                                 break;
178                         }
179                         oqi->oqi_flag = NO_QUOTA;
180                         insert_qinfo_hash(oqi);
181                 }
182         }
183
184         spin_unlock(&qinfo_list_lock);
185
186         RETURN(rc);
187 }
188
189 int osc_qinfo_cleanup(struct client_obd *cli)
190 {
191         struct osc_quota_info *oqi, *n;
192         int i;
193         ENTRY;
194
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)
199                                 continue;
200                         remove_qinfo_hash(oqi);
201                         free_qinfo(oqi);
202                 }
203         }
204         spin_unlock(&qinfo_list_lock);
205
206         RETURN(0);
207 }
208
209 int osc_qinfo_init(void)
210 {
211         int i;
212         ENTRY;
213
214         LASSERT(qinfo_cachep == NULL);
215         qinfo_cachep = kmem_cache_create("osc_quota_info",
216                                          sizeof(struct osc_quota_info),
217                                          0, 0, NULL, NULL);
218         if (!qinfo_cachep)
219                 RETURN(-ENOMEM);
220
221         for (i = 0; i < NR_DQHASH; i++)
222                 INIT_LIST_HEAD(qinfo_hash + i);
223
224         RETURN(0);        
225 }
226
227 void osc_qinfo_exit(void)
228 {
229         struct osc_quota_info *oqi, *n;
230         int i;
231         ENTRY;
232                                                                                                                              
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);
237                         free_qinfo(oqi);
238                 }
239         }
240         spin_unlock(&qinfo_list_lock);
241         
242         LASSERTF(kmem_cache_destroy(qinfo_cachep) == 0,
243                  "couldn't destroy osc quota info slab\n"); 
244 }