Whamcloud - gitweb
land b_hd_sec onto HEAD:
[fs/lustre-release.git] / lustre / mds / mds_lsd.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 2004-2005 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 #define DEBUG_SUBSYSTEM S_MDS
23
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/mm.h>
28 #include <linux/kmod.h>
29 #include <linux/string.h>
30 #include <linux/stat.h>
31 #include <linux/errno.h>
32 #include <linux/version.h>
33 #include <linux/unistd.h>
34
35 #include <asm/system.h>
36 #include <asm/uaccess.h>
37
38 #include <linux/fs.h>
39 #include <linux/stat.h>
40 #include <asm/uaccess.h>
41 #include <linux/slab.h>
42 #include <asm/segment.h>
43
44 #include <libcfs/list.h>
45 #include <linux/obd_support.h>
46 #include <linux/lustre_lib.h>
47 #include <linux/lustre_mds.h>
48 #include <linux/lustre_ucache.h>
49
50 #include "mds_internal.h"
51
52 /* 
53  * We need share hash table among the groups of MDSs (which server as the same
54  * lustre file system), maybe MDT? but there's lprocfs problems of putting this
55  * in MDT. so we make it global to the module. which brings the limitation that
56  * one node couldn't running multiple MDS which server as different Lustre FS.
57  * but which maybe not meaningful.
58  */
59
60
61 #define MDS_LSD_HASHSIZE        (256)
62 static struct upcall_cache _lsd_cache;
63 static struct list_head _lsd_hashtable[MDS_LSD_HASHSIZE];
64
65 #define MDS_LSD_UPCALL_PATH             "/usr/sbin/lsd_upcall"
66 #define MDS_LSD_ACQUIRE_EXPIRE          (5)
67 #define MDS_LSD_ENTRY_EXPIRE            (5 * 60)
68 #define MDS_LSD_ERR_ENTRY_EXPIRE        (30)
69
70 struct upcall_cache *__mds_get_global_lsd_cache()
71 {
72         return &_lsd_cache;
73 }
74
75 static unsigned int lsd_hash(struct upcall_cache *cache, __u64 key)
76 {
77         LASSERT(cache == &_lsd_cache);
78         return ((__u32) key) & (MDS_LSD_HASHSIZE - 1);
79 }
80
81 static struct upcall_cache_entry *
82 lsd_alloc_entry(struct upcall_cache *cache, __u64 key)
83 {
84         struct lsd_cache_entry *entry;
85         ENTRY;
86
87         OBD_ALLOC(entry, sizeof(*entry));
88         if (!entry) {
89                 CERROR("failed to alloc entry\n");
90                 RETURN(NULL);
91         }
92         upcall_cache_init_entry(cache, &entry->base, key);
93
94         RETURN(&entry->base);
95 }
96
97 static void lsd_free_entry(struct upcall_cache *cache,
98                            struct upcall_cache_entry *entry)
99 {
100         struct lsd_cache_entry *lentry;
101
102         lentry = container_of(entry, struct lsd_cache_entry, base);
103         if (lentry->lsd.lsd_ginfo)
104                 put_group_info(lentry->lsd.lsd_ginfo);
105         if (lentry->lsd.lsd_perms) {
106                 LASSERT(lentry->lsd.lsd_nperms);
107                 OBD_FREE(lentry->lsd.lsd_perms, lentry->lsd.lsd_nperms *
108                                                 sizeof(struct lsd_permission));
109         }
110         OBD_FREE(lentry, sizeof(*lentry));
111 }
112
113
114 static int lsd_make_upcall(struct upcall_cache *cache,
115                            struct upcall_cache_entry *entry)
116 {
117         char *argv[4];
118         char *envp[3];
119         char uidstr[16];
120         int rc;
121         ENTRY;
122
123         snprintf(uidstr, 16, "%u", (__u32) entry->ue_key);
124
125         argv[0] = cache->uc_upcall;
126         argv[1] = uidstr;
127         argv[2] = NULL;
128                                                                                                                         
129         envp[0] = "HOME=/";
130         envp[1] = "PATH=/sbin:/usr/sbin";
131         envp[2] = NULL;
132
133         rc = USERMODEHELPER(argv[0], argv, envp);
134         if (rc < 0) {
135                 CERROR("Error invoking lsd upcall %s %s: %d; check "
136                        "/proc/fs/lustre/mds/lsd_upcall\n",
137                        argv[0], argv[1], rc);
138         } else {
139                 CWARN("Invoked upcall %s %s\n",
140                         argv[0], argv[1]);
141         }
142         RETURN(rc);
143 }
144
145 static int lsd_parse_downcall(struct upcall_cache *cache,
146                               struct upcall_cache_entry *entry,
147                               void *args)
148 {
149         struct lustre_sec_desc *lsd;
150         struct lsd_cache_entry *lentry;
151         struct lsd_downcall_args *lsd_args;
152         struct group_info *ginfo;
153         int size;
154         ENTRY;
155
156         LASSERT(args);
157
158         lentry = container_of(entry, struct lsd_cache_entry, base);
159         lsd = &lentry->lsd;
160         lsd_args = (struct lsd_downcall_args *) args;
161         LASSERT(lsd_args->ngroups <= NGROUPS_MAX);
162
163         if (lsd_args->err)
164                 GOTO(err_ret, lsd_args->err);
165
166         ginfo = groups_alloc(lsd_args->ngroups);
167         if (!ginfo) {
168                 CERROR("failed to alloc %d groups\n", lsd_args->ngroups);
169                 GOTO(err_ret, -ENOMEM);
170         }
171         groups_from_buffer(ginfo, lsd_args->groups);
172         groups_sort(ginfo);
173
174         if (lsd_args->nperms) {
175                 size = lsd_args->nperms * sizeof(struct lsd_permission);
176                 OBD_ALLOC(lsd->lsd_perms, size);
177                 if (!lsd->lsd_perms) {
178                         CERROR("failed to alloc %d\n", size);
179                         GOTO(err_group, -ENOMEM);
180                 }
181                 if (copy_from_user(lsd->lsd_perms, lsd_args->perms, size)) {
182                         CERROR("error copy from user space\n");
183                         GOTO(err_free, -EFAULT);
184                 }
185         }
186
187         lsd->lsd_invalid = 0;
188         lsd->lsd_uid = lsd_args->uid;
189         lsd->lsd_gid = lsd_args->gid;
190         lsd->lsd_ginfo = ginfo;
191         lsd->lsd_nperms = lsd_args->nperms;
192
193         CWARN("LSD: %d:%d, ngrps %u, nperms %u\n", lsd->lsd_uid, lsd->lsd_gid,
194               lsd->lsd_ginfo ? lsd->lsd_ginfo->ngroups : 0, lsd->lsd_nperms);
195
196         RETURN(0);
197 err_free:
198         OBD_FREE(lsd->lsd_perms, size);
199         lsd->lsd_perms = NULL;
200 err_group:
201         put_group_info(ginfo);
202 err_ret:
203         CERROR("LSD downcall error, disable this user for %lus\n",
204                cache->uc_err_entry_expire);
205         lsd->lsd_invalid = 1;
206         RETURN(1);
207 }
208
209 struct lustre_sec_desc * mds_get_lsd(__u32 uid)
210 {
211         struct upcall_cache *cache = &_lsd_cache;
212         struct upcall_cache_entry *entry;
213         struct lsd_cache_entry *lentry;
214
215         entry = upcall_cache_get_entry(cache, (__u64) uid);
216         if (!entry)
217                 return NULL;
218
219         lentry = container_of(entry, struct lsd_cache_entry, base);
220         if (lentry->lsd.lsd_invalid) {
221                 upcall_cache_put_entry(&lentry->base);
222                 return NULL;
223         }
224
225         return &lentry->lsd;
226 }
227
228 void mds_put_lsd(struct lustre_sec_desc *lsd)
229 {
230         struct lsd_cache_entry *lentry;
231
232         LASSERT(lsd);
233
234         lentry = container_of(lsd, struct lsd_cache_entry, lsd);
235         upcall_cache_put_entry(&lentry->base);
236 }
237
238 int mds_init_lsd_cache()
239 {
240         struct upcall_cache *cache = &_lsd_cache;
241         int i;
242         ENTRY;
243
244         cache->uc_hashtable = _lsd_hashtable;
245         cache->uc_hashsize = MDS_LSD_HASHSIZE;
246         cache->uc_hashlock = RW_LOCK_UNLOCKED;
247         for (i = 0; i < cache->uc_hashsize; i++)
248                 INIT_LIST_HEAD(&cache->uc_hashtable[i]);
249         cache->uc_name = "LSD_CACHE";
250
251         /* set default value, proc tunable */
252         sprintf(cache->uc_upcall, MDS_LSD_UPCALL_PATH);
253         cache->uc_acquire_expire = MDS_LSD_ACQUIRE_EXPIRE;
254         cache->uc_entry_expire = MDS_LSD_ENTRY_EXPIRE;
255         cache->uc_err_entry_expire = MDS_LSD_ERR_ENTRY_EXPIRE;
256
257         cache->hash = lsd_hash;
258         cache->alloc_entry = lsd_alloc_entry;
259         cache->free_entry = lsd_free_entry;
260         cache->make_upcall = lsd_make_upcall;
261         cache->parse_downcall = lsd_parse_downcall;
262
263         RETURN(0);
264 }
265
266 void mds_flush_lsd(__u32 id)
267 {
268         struct upcall_cache *cache = &_lsd_cache;
269
270         if (id == -1)
271                 upcall_cache_flush_idle(cache);
272         else
273                 upcall_cache_flush_one(cache, (__u64) id);
274 }
275
276 void mds_cleanup_lsd_cache()
277 {
278         upcall_cache_flush_all(&_lsd_cache);
279 }
280
281 __u32 mds_lsd_get_perms(struct lustre_sec_desc *lsd, __u32 is_remote,
282                         ptl_netid_t netid, ptl_nid_t nid)
283 {
284         struct lsd_permission *perm = lsd->lsd_perms;
285         __u32 i;
286
287         for (i = 0; i < lsd->lsd_nperms; i++) {
288                 if (perm->netid != PTL_NETID_ANY && perm->netid != netid)
289                         continue;
290                 if (perm->nid != PTL_NID_ANY && perm->nid != nid)
291                         continue;
292                 return perm->perm;
293         }
294
295         /* default */
296         if (is_remote)
297                 return 0;
298         else
299                 return LSD_PERM_SETGRP;
300 }