Whamcloud - gitweb
add some error message, try to catch the occasional lsd upcall failure.
[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          (10)
67 #define MDS_LSD_ENTRY_EXPIRE            (10 * 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("%lu: lsd %p Invoked upcall %s %s\n",
140                       get_seconds(), entry, 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 (%p): %d:%d, ngrps %u, nperms %u\n",
194               lentry, lsd->lsd_uid, lsd->lsd_gid,
195               lsd->lsd_ginfo ? lsd->lsd_ginfo->ngroups : 0, lsd->lsd_nperms);
196
197         RETURN(0);
198 err_free:
199         OBD_FREE(lsd->lsd_perms, size);
200         lsd->lsd_perms = NULL;
201 err_group:
202         put_group_info(ginfo);
203 err_ret:
204         CERROR("LSD downcall error, disable this user for %lus\n",
205                cache->uc_err_entry_expire);
206         lsd->lsd_invalid = 1;
207         RETURN(1);
208 }
209
210 struct lustre_sec_desc * mds_get_lsd(__u32 uid)
211 {
212         struct upcall_cache *cache = &_lsd_cache;
213         struct upcall_cache_entry *entry;
214         struct lsd_cache_entry *lentry;
215
216         entry = upcall_cache_get_entry(cache, (__u64) uid);
217         if (!entry)
218                 return NULL;
219
220         lentry = container_of(entry, struct lsd_cache_entry, base);
221         if (lentry->lsd.lsd_invalid) {
222                 upcall_cache_put_entry(&lentry->base);
223                 return NULL;
224         }
225
226         return &lentry->lsd;
227 }
228
229 void mds_put_lsd(struct lustre_sec_desc *lsd)
230 {
231         struct lsd_cache_entry *lentry;
232
233         LASSERT(lsd);
234
235         lentry = container_of(lsd, struct lsd_cache_entry, lsd);
236         upcall_cache_put_entry(&lentry->base);
237 }
238
239 int mds_init_lsd_cache()
240 {
241         struct upcall_cache *cache = &_lsd_cache;
242         int i;
243         ENTRY;
244
245         cache->uc_hashtable = _lsd_hashtable;
246         cache->uc_hashsize = MDS_LSD_HASHSIZE;
247         cache->uc_hashlock = RW_LOCK_UNLOCKED;
248         for (i = 0; i < cache->uc_hashsize; i++)
249                 INIT_LIST_HEAD(&cache->uc_hashtable[i]);
250         cache->uc_name = "LSD_CACHE";
251
252         /* set default value, proc tunable */
253         sprintf(cache->uc_upcall, MDS_LSD_UPCALL_PATH);
254         cache->uc_acquire_expire = MDS_LSD_ACQUIRE_EXPIRE;
255         cache->uc_entry_expire = MDS_LSD_ENTRY_EXPIRE;
256         cache->uc_err_entry_expire = MDS_LSD_ERR_ENTRY_EXPIRE;
257
258         cache->hash = lsd_hash;
259         cache->alloc_entry = lsd_alloc_entry;
260         cache->free_entry = lsd_free_entry;
261         cache->make_upcall = lsd_make_upcall;
262         cache->parse_downcall = lsd_parse_downcall;
263
264         RETURN(0);
265 }
266
267 void mds_flush_lsd(__u32 id)
268 {
269         struct upcall_cache *cache = &_lsd_cache;
270
271         if (id == -1)
272                 upcall_cache_flush_idle(cache);
273         else
274                 upcall_cache_flush_one(cache, (__u64) id);
275 }
276
277 void mds_cleanup_lsd_cache()
278 {
279         upcall_cache_flush_all(&_lsd_cache);
280 }
281
282 __u32 mds_lsd_get_perms(struct lustre_sec_desc *lsd, __u32 is_remote,
283                         ptl_netid_t netid, ptl_nid_t nid)
284 {
285         struct lsd_permission *perm = lsd->lsd_perms;
286         __u32 i;
287
288         for (i = 0; i < lsd->lsd_nperms; i++) {
289                 if (perm->netid != PTL_NETID_ANY && perm->netid != netid)
290                         continue;
291                 if (perm->nid != PTL_NID_ANY && perm->nid != nid)
292                         continue;
293                 return perm->perm;
294         }
295
296         /* default */
297         if (is_remote)
298                 return 0;
299         else
300                 return LSD_PERM_SETGRP;
301 }