Whamcloud - gitweb
land b_hd_remote_acl: support get/set ACL from remote client.
[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/bin/lacl_upcall"
61 #define RMTACL_ACQUIRE_EXPIRE           (15)
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\n",
136                        argv[0], argv[1], argv[2], argv[3]);
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                 desc->upcall_status = -EFAULT;
170                 goto out;
171         }
172
173 out:
174         return 0;
175 }
176
177 static void mds_rmtacl_upcall(struct rmtacl_upcall_desc *desc)
178 {
179         struct upcall_cache *cache = &_rmtacl_upcall_cache;
180         struct upcall_cache_entry *entry;
181
182         desc->upcall_status = 0;
183
184         entry = upcall_cache_get_entry(cache, (__u64) ((unsigned long) desc));
185         if (!entry) {
186                 desc->upcall_status = -EINVAL;
187                 return;
188         }
189
190         UC_CACHE_SET_EXPIRED(entry);
191         upcall_cache_put_entry(entry);
192 }
193
194 int mds_init_rmtacl_upcall_cache()
195 {
196         struct upcall_cache *cache = &_rmtacl_upcall_cache;
197         int i;
198         ENTRY;
199
200         cache->uc_hashtable = _rmtacl_upcall_hashtable;
201         cache->uc_hashsize = RMTACL_UPCALL_HASHSIZE;
202         cache->uc_hashlock = RW_LOCK_UNLOCKED;
203         for (i = 0; i < cache->uc_hashsize; i++)
204                 INIT_LIST_HEAD(&cache->uc_hashtable[i]);
205         cache->uc_name = "RMTACL_UPCALL";
206
207         /* set default value, proc tunable */
208         sprintf(cache->uc_upcall, RMTACL_UPCALL_PATH);
209         cache->uc_acquire_expire = RMTACL_ACQUIRE_EXPIRE;
210         cache->uc_entry_expire = RMTACL_ENTRY_EXPIRE;
211         cache->uc_err_entry_expire = RMTACL_ERR_ENTRY_EXPIRE;
212
213         cache->hash = rmtacl_hash;
214         cache->alloc_entry = rmtacl_alloc_entry;
215         cache->free_entry = rmtacl_free_entry;
216         cache->make_upcall = rmtacl_make_upcall;
217         cache->parse_downcall = rmtacl_parse_downcall;
218
219         RETURN(0);
220 }
221
222 void mds_cleanup_rmtacl_upcall_cache()
223 {
224         struct upcall_cache *cache = &_rmtacl_upcall_cache;
225
226         LASSERT(list_empty(&cache->uc_hashtable[0]));
227 }
228
229 /****************************************
230  * exported helper functions            *
231  ****************************************/
232
233 /*
234  * traverse through the mountpoint to find lustre mountpoint
235  */
236 static struct vfsmount *mds_get_lustre_mnt(void)
237 {
238         struct vfsmount *mnt, *lmnt = NULL;
239
240         LASSERT(current->fs);
241         read_lock(&current->fs->lock);
242         mnt = mntget(current->fs->rootmnt);
243         read_unlock(&current->fs->lock);
244         LASSERT(mnt);
245
246         spin_lock(&vfsmount_lock);
247 check_point:
248         if (!strcmp(mnt->mnt_sb->s_type->name, "lustre") ||
249             !strcmp(mnt->mnt_sb->s_type->name, "llite")) {
250                 lmnt = mntget(mnt);
251                 goto break_out;
252         }
253
254         if (!list_empty(&mnt->mnt_mounts)) {
255                 mnt = list_entry(mnt->mnt_mounts.next,
256                                  struct vfsmount, mnt_child);
257                 goto check_point;
258         }
259
260 follow_siblings:
261         /* check siblings */
262         if (list_empty(&mnt->mnt_child) ||
263             mnt->mnt_child.next == &mnt->mnt_parent->mnt_mounts) {
264                 /* we are the last child */
265                 LASSERT(mnt->mnt_parent != NULL);
266                 if (list_empty(&mnt->mnt_child) ||
267                     mnt->mnt_parent == NULL)
268                         goto break_out;
269                 mnt = mnt->mnt_parent;
270                 goto follow_siblings;
271         }
272
273         mnt = list_entry(mnt->mnt_child.next, struct vfsmount, mnt_child);
274         goto check_point;
275
276 break_out:
277         spin_unlock(&vfsmount_lock);
278
279         return lmnt;
280 }
281
282 void mds_do_remote_acl_upcall(struct rmtacl_upcall_desc *desc)
283 {
284         struct fs_struct *fs = current->fs;
285         struct vfsmount *lmnt;
286         char *buf = NULL, *mntpnt;
287
288         lmnt = mds_get_lustre_mnt();
289         if (!lmnt) {
290                 desc->upcall_status = -EOPNOTSUPP;
291                 return;
292         }
293
294         OBD_ALLOC(buf, PAGE_SIZE);
295         if (!buf) {
296                 desc->upcall_status = -ENOMEM;
297                 goto out;
298         }
299
300         mntpnt = __d_path(lmnt->mnt_root, lmnt, fs->root, fs->rootmnt,
301                           buf, PAGE_SIZE);
302         if (IS_ERR(mntpnt)) {
303                 desc->upcall_status = PTR_ERR(mntpnt);
304                 goto out;
305         }
306
307         desc->root = mntpnt;
308         desc->uid = current->uid;
309
310         mds_rmtacl_upcall(desc);
311
312 out:
313         if (buf)
314                 OBD_FREE(buf, PAGE_SIZE);
315         mntput(lmnt);
316 }