Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / mds / mds_acl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (c) 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  * handle remote getfacl/setfacl upcall *
54  ****************************************/
55
56 #define RMTACL_UPCALL_HASHSIZE        (1)
57 static struct upcall_cache _rmtacl_upcall_cache;
58 static struct list_head _rmtacl_upcall_hashtable[RMTACL_UPCALL_HASHSIZE];
59
60 #define RMTACL_UPCALL_PATH              "/usr/sbin/lacl_upcall"
61 #define RMTACL_ACQUIRE_EXPIRE           (20)
62 #define RMTACL_ENTRY_EXPIRE             (0)
63 #define RMTACL_ERR_ENTRY_EXPIRE         (0)
64
65 struct upcall_cache *__mds_get_global_rmtacl_upcall_cache()
66 {
67         return &_rmtacl_upcall_cache;
68 }
69
70 static unsigned int rmtacl_hash(struct upcall_cache *cache, __u64 key)
71 {
72         LASSERT(cache == &_rmtacl_upcall_cache);
73         return 0;
74 }
75
76 static struct upcall_cache_entry *
77 rmtacl_alloc_entry(struct upcall_cache *cache, __u64 key)
78 {
79         struct rmtacl_upcall_entry *entry;
80
81         OBD_ALLOC(entry, sizeof(*entry));
82         if (!entry)
83                 return NULL;
84
85         upcall_cache_init_entry(cache, &entry->base, key);
86         entry->desc = (struct rmtacl_upcall_desc *) ((unsigned long) key);
87
88         return &entry->base;
89 }
90
91 static void rmtacl_free_entry(struct upcall_cache *cache,
92                               struct upcall_cache_entry *entry)
93 {
94         struct rmtacl_upcall_entry *rentry;
95
96         rentry = container_of(entry, struct rmtacl_upcall_entry, base);
97         OBD_FREE(rentry, sizeof(*rentry));
98 }
99
100 static int rmtacl_make_upcall(struct upcall_cache *cache,
101                               struct upcall_cache_entry *entry)
102 {
103         struct rmtacl_upcall_entry *rentry;
104         struct rmtacl_upcall_desc *desc;
105         char *argv[7];
106         char *envp[3];
107         char keystr[20];
108         char uidstr[16];
109         int rc;
110
111         rentry = container_of(entry, struct rmtacl_upcall_entry, base);
112         desc = rentry->desc;
113
114         snprintf(keystr, 20, LPX64, entry->ue_key);
115         snprintf(uidstr, 16, "%u", desc->uid);
116
117         argv[0] = cache->uc_upcall;
118         argv[1] = keystr;
119         argv[2] = uidstr;
120         argv[3] = desc->root;
121         argv[4] = desc->get ? "get" : "set";
122         argv[5] = desc->cmd;
123         argv[6] = NULL;
124                                                                                                                         
125         envp[0] = "HOME=/";
126         envp[1] = "PATH=/bin:/usr/bin:/usr/local/bin";
127         envp[2] = NULL;
128
129         rc = USERMODEHELPER(argv[0], argv, envp);
130         if (rc < 0) {
131                 CERROR("Error invoking upcall %s: %d; check "
132                        "/proc/fs/lustre/mds/lacl_upcall\n",
133                        argv[0], rc);
134         } else {
135                 CDEBUG(D_SEC, "Invoked upcall %s %s %s %s %s %s\n",
136                        argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
137         }
138         return rc;
139 }
140
141 static int rmtacl_parse_downcall(struct upcall_cache *cache,
142                                  struct upcall_cache_entry *entry,
143                                  void *args)
144 {
145         struct rmtacl_upcall_entry *rentry;
146         struct rmtacl_upcall_desc *desc;
147         struct rmtacl_downcall_args *rargs;
148
149         LASSERT(args);
150
151         rentry = container_of(entry, struct rmtacl_upcall_entry, base);
152         desc = rentry->desc;
153         rargs = (struct rmtacl_downcall_args *) args;
154
155         desc->status = rargs->status;
156
157         if (desc->reslen < rargs->reslen) {
158                 CERROR("bufsize %u, while %u passed down\n",
159                        desc->reslen, rargs->reslen);
160                 desc->upcall_status = -ENOMEM;
161                 goto out;
162         }
163
164         desc->reslen = rargs->reslen;
165         if (!rargs->reslen)
166                 goto out;
167
168         if (copy_from_user(desc->res, rargs->res, rargs->reslen)) {
169                 CERROR("can't copy from userspace\n");
170                 desc->upcall_status = -EFAULT;
171                 goto out;
172         }
173
174 out:
175         return 0;
176 }
177
178 static void mds_rmtacl_upcall(struct rmtacl_upcall_desc *desc)
179 {
180         struct upcall_cache *cache = &_rmtacl_upcall_cache;
181         struct upcall_cache_entry *entry;
182
183         desc->upcall_status = 0;
184
185         entry = upcall_cache_get_entry(cache, (__u64) ((unsigned long) desc));
186         if (!entry) {
187                 desc->upcall_status = -EINVAL;
188                 return;
189         }
190
191         UC_CACHE_SET_EXPIRED(entry);
192         upcall_cache_put_entry(entry);
193 }
194
195 int mds_init_rmtacl_upcall_cache()
196 {
197         struct upcall_cache *cache = &_rmtacl_upcall_cache;
198         int i;
199         ENTRY;
200
201         cache->uc_hashtable = _rmtacl_upcall_hashtable;
202         cache->uc_hashsize = RMTACL_UPCALL_HASHSIZE;
203         cache->uc_hashlock = RW_LOCK_UNLOCKED;
204         for (i = 0; i < cache->uc_hashsize; i++)
205                 INIT_LIST_HEAD(&cache->uc_hashtable[i]);
206         cache->uc_name = "RMTACL_UPCALL";
207
208         /* set default value, proc tunable */
209         sprintf(cache->uc_upcall, RMTACL_UPCALL_PATH);
210         cache->uc_acquire_expire = RMTACL_ACQUIRE_EXPIRE;
211         cache->uc_entry_expire = RMTACL_ENTRY_EXPIRE;
212         cache->uc_err_entry_expire = RMTACL_ERR_ENTRY_EXPIRE;
213
214         cache->hash = rmtacl_hash;
215         cache->alloc_entry = rmtacl_alloc_entry;
216         cache->free_entry = rmtacl_free_entry;
217         cache->make_upcall = rmtacl_make_upcall;
218         cache->parse_downcall = rmtacl_parse_downcall;
219
220         RETURN(0);
221 }
222
223 void mds_cleanup_rmtacl_upcall_cache()
224 {
225         struct upcall_cache *cache = &_rmtacl_upcall_cache;
226
227         LASSERT(list_empty(&cache->uc_hashtable[0]));
228 }
229
230 /****************************************
231  * exported helper functions            *
232  ****************************************/
233
234 /*
235  * traverse through the mountpoint to find lustre mountpoint
236  */
237 static struct vfsmount *mds_get_lustre_mnt(void)
238 {
239         struct vfsmount *mnt, *lmnt = NULL;
240
241         LASSERT(current->fs);
242         read_lock(&current->fs->lock);
243         mnt = mntget(current->fs->rootmnt);
244         read_unlock(&current->fs->lock);
245         LASSERT(mnt);
246
247         spin_lock(&vfsmount_lock);
248 check_point:
249         if (!strcmp(mnt->mnt_sb->s_type->name, "lustre") ||
250             !strcmp(mnt->mnt_sb->s_type->name, "llite")) {
251                 lmnt = mntget(mnt);
252                 goto break_out;
253         }
254
255         if (!list_empty(&mnt->mnt_mounts)) {
256                 mnt = list_entry(mnt->mnt_mounts.next,
257                                  struct vfsmount, mnt_child);
258                 goto check_point;
259         }
260
261 follow_siblings:
262         /* check siblings */
263         if (list_empty(&mnt->mnt_child) ||
264             mnt->mnt_child.next == &mnt->mnt_parent->mnt_mounts) {
265                 /* we are the last child */
266                 LASSERT(mnt->mnt_parent != NULL);
267                 if (list_empty(&mnt->mnt_child) ||
268                     mnt->mnt_parent == NULL)
269                         goto break_out;
270                 mnt = mnt->mnt_parent;
271                 goto follow_siblings;
272         }
273
274         mnt = list_entry(mnt->mnt_child.next, struct vfsmount, mnt_child);
275         goto check_point;
276
277 break_out:
278         spin_unlock(&vfsmount_lock);
279
280         return lmnt;
281 }
282
283 void mds_do_remote_acl_upcall(struct rmtacl_upcall_desc *desc)
284 {
285         struct fs_struct *fs = current->fs;
286         struct vfsmount *lmnt;
287         char *buf = NULL, *mntpnt;
288
289         lmnt = mds_get_lustre_mnt();
290         if (!lmnt) {
291                 desc->upcall_status = -EOPNOTSUPP;
292                 return;
293         }
294
295         OBD_ALLOC(buf, PAGE_SIZE);
296         if (!buf) {
297                 desc->upcall_status = -ENOMEM;
298                 goto out;
299         }
300
301         mntpnt = __d_path(lmnt->mnt_root, lmnt, fs->root, fs->rootmnt,
302                           buf, PAGE_SIZE);
303         if (IS_ERR(mntpnt)) {
304                 desc->upcall_status = PTR_ERR(mntpnt);
305                 goto out;
306         }
307
308         desc->root = mntpnt;
309         desc->uid = current->uid;
310
311         mds_rmtacl_upcall(desc);
312
313 out:
314         if (buf)
315                 OBD_FREE(buf, PAGE_SIZE);
316         mntput(lmnt);
317 }