These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / lustre / lustre / llite / remote_perm.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/llite/remote_perm.c
37  *
38  * Lustre Permission Cache for Remote Client
39  *
40  * Author: Lai Siyao <lsy@clusterfs.com>
41  * Author: Fan Yong <fanyong@clusterfs.com>
42  */
43
44 #define DEBUG_SUBSYSTEM S_LLITE
45
46 #include <linux/module.h>
47 #include <linux/types.h>
48
49 #include "../include/lustre_lite.h"
50 #include "../include/lustre_ha.h"
51 #include "../include/lustre_dlm.h"
52 #include "../include/lprocfs_status.h"
53 #include "../include/lustre_disk.h"
54 #include "../include/lustre_param.h"
55 #include "llite_internal.h"
56
57 struct kmem_cache *ll_remote_perm_cachep;
58 struct kmem_cache *ll_rmtperm_hash_cachep;
59
60 static inline struct ll_remote_perm *alloc_ll_remote_perm(void)
61 {
62         struct ll_remote_perm *lrp;
63
64         lrp = kmem_cache_alloc(ll_remote_perm_cachep, GFP_KERNEL | __GFP_ZERO);
65         if (lrp)
66                 INIT_HLIST_NODE(&lrp->lrp_list);
67         return lrp;
68 }
69
70 static inline void free_ll_remote_perm(struct ll_remote_perm *lrp)
71 {
72         if (!lrp)
73                 return;
74
75         if (!hlist_unhashed(&lrp->lrp_list))
76                 hlist_del(&lrp->lrp_list);
77         kmem_cache_free(ll_remote_perm_cachep, lrp);
78 }
79
80 static struct hlist_head *alloc_rmtperm_hash(void)
81 {
82         struct hlist_head *hash;
83         int i;
84
85         hash = kmem_cache_alloc(ll_rmtperm_hash_cachep, GFP_NOFS | __GFP_ZERO);
86         if (!hash)
87                 return NULL;
88
89         for (i = 0; i < REMOTE_PERM_HASHSIZE; i++)
90                 INIT_HLIST_HEAD(hash + i);
91
92         return hash;
93 }
94
95 void free_rmtperm_hash(struct hlist_head *hash)
96 {
97         int i;
98         struct ll_remote_perm *lrp;
99         struct hlist_node *next;
100
101         if (!hash)
102                 return;
103
104         for (i = 0; i < REMOTE_PERM_HASHSIZE; i++)
105                 hlist_for_each_entry_safe(lrp, next, hash + i, lrp_list)
106                         free_ll_remote_perm(lrp);
107         kmem_cache_free(ll_rmtperm_hash_cachep, hash);
108 }
109
110 static inline int remote_perm_hashfunc(uid_t uid)
111 {
112         return uid & (REMOTE_PERM_HASHSIZE - 1);
113 }
114
115 /* NB: setxid permission is not checked here, instead it's done on
116  * MDT when client get remote permission.
117  */
118 static int do_check_remote_perm(struct ll_inode_info *lli, int mask)
119 {
120         struct hlist_head *head;
121         struct ll_remote_perm *lrp;
122         int found = 0, rc;
123
124         if (!lli->lli_remote_perms)
125                 return -ENOENT;
126
127         head = lli->lli_remote_perms +
128                 remote_perm_hashfunc(from_kuid(&init_user_ns, current_uid()));
129
130         spin_lock(&lli->lli_lock);
131         hlist_for_each_entry(lrp, head, lrp_list) {
132                 if (lrp->lrp_uid != from_kuid(&init_user_ns, current_uid()))
133                         continue;
134                 if (lrp->lrp_gid != from_kgid(&init_user_ns, current_gid()))
135                         continue;
136                 if (lrp->lrp_fsuid != from_kuid(&init_user_ns, current_fsuid()))
137                         continue;
138                 if (lrp->lrp_fsgid != from_kgid(&init_user_ns, current_fsgid()))
139                         continue;
140                 found = 1;
141                 break;
142         }
143
144         if (!found) {
145                 rc = -ENOENT;
146                 goto out;
147         }
148
149         CDEBUG(D_SEC, "found remote perm: %u/%u/%u/%u - %#x\n",
150                lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid,
151                lrp->lrp_access_perm);
152         rc = ((lrp->lrp_access_perm & mask) == mask) ? 0 : -EACCES;
153
154 out:
155         spin_unlock(&lli->lli_lock);
156         return rc;
157 }
158
159 int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm)
160 {
161         struct ll_inode_info *lli = ll_i2info(inode);
162         struct ll_remote_perm *lrp = NULL, *tmp = NULL;
163         struct hlist_head *head, *perm_hash = NULL;
164
165         LASSERT(ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT);
166
167 #if 0
168         if (perm->rp_uid != current->uid ||
169             perm->rp_gid != current->gid ||
170             perm->rp_fsuid != current->fsuid ||
171             perm->rp_fsgid != current->fsgid) {
172                 /* user might setxid in this small period */
173                 CDEBUG(D_SEC,
174                        "remote perm user %u/%u/%u/%u != current %u/%u/%u/%u\n",
175                        perm->rp_uid, perm->rp_gid, perm->rp_fsuid,
176                        perm->rp_fsgid, current->uid, current->gid,
177                        current->fsuid, current->fsgid);
178                 return -EAGAIN;
179         }
180 #endif
181
182         if (!lli->lli_remote_perms) {
183                 perm_hash = alloc_rmtperm_hash();
184                 if (!perm_hash) {
185                         CERROR("alloc lli_remote_perms failed!\n");
186                         return -ENOMEM;
187                 }
188         }
189
190         spin_lock(&lli->lli_lock);
191
192         if (!lli->lli_remote_perms)
193                 lli->lli_remote_perms = perm_hash;
194         else
195                 free_rmtperm_hash(perm_hash);
196
197         head = lli->lli_remote_perms + remote_perm_hashfunc(perm->rp_uid);
198
199 again:
200         hlist_for_each_entry(tmp, head, lrp_list) {
201                 if (tmp->lrp_uid != perm->rp_uid)
202                         continue;
203                 if (tmp->lrp_gid != perm->rp_gid)
204                         continue;
205                 if (tmp->lrp_fsuid != perm->rp_fsuid)
206                         continue;
207                 if (tmp->lrp_fsgid != perm->rp_fsgid)
208                         continue;
209                 free_ll_remote_perm(lrp);
210                 lrp = tmp;
211                 break;
212         }
213
214         if (!lrp) {
215                 spin_unlock(&lli->lli_lock);
216                 lrp = alloc_ll_remote_perm();
217                 if (!lrp) {
218                         CERROR("alloc memory for ll_remote_perm failed!\n");
219                         return -ENOMEM;
220                 }
221                 spin_lock(&lli->lli_lock);
222                 goto again;
223         }
224
225         lrp->lrp_access_perm = perm->rp_access_perm;
226         if (lrp != tmp) {
227                 lrp->lrp_uid     = perm->rp_uid;
228                 lrp->lrp_gid     = perm->rp_gid;
229                 lrp->lrp_fsuid       = perm->rp_fsuid;
230                 lrp->lrp_fsgid       = perm->rp_fsgid;
231                 hlist_add_head(&lrp->lrp_list, head);
232         }
233         lli->lli_rmtperm_time = cfs_time_current();
234         spin_unlock(&lli->lli_lock);
235
236         CDEBUG(D_SEC, "new remote perm@%p: %u/%u/%u/%u - %#x\n",
237                lrp, lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid,
238                lrp->lrp_access_perm);
239
240         return 0;
241 }
242
243 int lustre_check_remote_perm(struct inode *inode, int mask)
244 {
245         struct ll_inode_info *lli = ll_i2info(inode);
246         struct ll_sb_info *sbi = ll_i2sbi(inode);
247         struct ptlrpc_request *req = NULL;
248         struct mdt_remote_perm *perm;
249         unsigned long save;
250         int i = 0, rc;
251
252         do {
253                 save = lli->lli_rmtperm_time;
254                 rc = do_check_remote_perm(lli, mask);
255                 if (!rc || (rc != -ENOENT && i))
256                         break;
257
258                 might_sleep();
259
260                 mutex_lock(&lli->lli_rmtperm_mutex);
261                 /* check again */
262                 if (save != lli->lli_rmtperm_time) {
263                         rc = do_check_remote_perm(lli, mask);
264                         if (!rc || (rc != -ENOENT && i)) {
265                                 mutex_unlock(&lli->lli_rmtperm_mutex);
266                                 break;
267                         }
268                 }
269
270                 if (i++ > 5) {
271                         CERROR("check remote perm falls in dead loop!\n");
272                         LBUG();
273                 }
274
275                 rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode),
276                                         ll_i2suppgid(inode), &req);
277                 if (rc) {
278                         mutex_unlock(&lli->lli_rmtperm_mutex);
279                         break;
280                 }
281
282                 perm = req_capsule_server_swab_get(&req->rq_pill, &RMF_ACL,
283                                                    lustre_swab_mdt_remote_perm);
284                 if (unlikely(!perm)) {
285                         mutex_unlock(&lli->lli_rmtperm_mutex);
286                         rc = -EPROTO;
287                         break;
288                 }
289
290                 rc = ll_update_remote_perm(inode, perm);
291                 mutex_unlock(&lli->lli_rmtperm_mutex);
292                 if (rc == -ENOMEM)
293                         break;
294
295                 ptlrpc_req_finished(req);
296                 req = NULL;
297         } while (1);
298         ptlrpc_req_finished(req);
299         return rc;
300 }
301
302 #if 0  /* NB: remote perms can't be freed in ll_mdc_blocking_ast of UPDATE lock,
303         * because it will fail sanity test 48.
304         */
305 void ll_free_remote_perms(struct inode *inode)
306 {
307         struct ll_inode_info *lli = ll_i2info(inode);
308         struct hlist_head *hash = lli->lli_remote_perms;
309         struct ll_remote_perm *lrp;
310         struct hlist_node *node, *next;
311         int i;
312
313         LASSERT(hash);
314
315         spin_lock(&lli->lli_lock);
316
317         for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) {
318                 hlist_for_each_entry_safe(lrp, node, next, hash + i, lrp_list)
319                         free_ll_remote_perm(lrp);
320         }
321
322         spin_unlock(&lli->lli_lock);
323 }
324 #endif