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 57struct kmem_cache *ll_remote_perm_cachep = NULL; 58struct kmem_cache *ll_rmtperm_hash_cachep = NULL; 59 60static inline struct ll_remote_perm *alloc_ll_remote_perm(void) 61{ 62 struct ll_remote_perm *lrp; 63 64 OBD_SLAB_ALLOC_PTR_GFP(lrp, ll_remote_perm_cachep, GFP_KERNEL); 65 if (lrp) 66 INIT_HLIST_NODE(&lrp->lrp_list); 67 return lrp; 68} 69 70static 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 OBD_SLAB_FREE(lrp, ll_remote_perm_cachep, sizeof(*lrp)); 78} 79 80static struct hlist_head *alloc_rmtperm_hash(void) 81{ 82 struct hlist_head *hash; 83 int i; 84 85 OBD_SLAB_ALLOC_GFP(hash, ll_rmtperm_hash_cachep, 86 REMOTE_PERM_HASHSIZE * sizeof(*hash), 87 GFP_IOFS); 88 if (!hash) 89 return NULL; 90 91 for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) 92 INIT_HLIST_HEAD(hash + i); 93 94 return hash; 95} 96 97void free_rmtperm_hash(struct hlist_head *hash) 98{ 99 int i; 100 struct ll_remote_perm *lrp; 101 struct hlist_node *next; 102 103 if (!hash) 104 return; 105 106 for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) 107 hlist_for_each_entry_safe(lrp, next, hash + i, 108 lrp_list) 109 free_ll_remote_perm(lrp); 110 OBD_SLAB_FREE(hash, ll_rmtperm_hash_cachep, 111 REMOTE_PERM_HASHSIZE * sizeof(*hash)); 112} 113 114static inline int remote_perm_hashfunc(uid_t uid) 115{ 116 return uid & (REMOTE_PERM_HASHSIZE - 1); 117} 118 119/* NB: setxid permission is not checked here, instead it's done on 120 * MDT when client get remote permission. */ 121static int do_check_remote_perm(struct ll_inode_info *lli, int mask) 122{ 123 struct hlist_head *head; 124 struct ll_remote_perm *lrp; 125 int found = 0, rc; 126 127 if (!lli->lli_remote_perms) 128 return -ENOENT; 129 130 head = lli->lli_remote_perms + 131 remote_perm_hashfunc(from_kuid(&init_user_ns, current_uid())); 132 133 spin_lock(&lli->lli_lock); 134 hlist_for_each_entry(lrp, head, lrp_list) { 135 if (lrp->lrp_uid != from_kuid(&init_user_ns, current_uid())) 136 continue; 137 if (lrp->lrp_gid != from_kgid(&init_user_ns, current_gid())) 138 continue; 139 if (lrp->lrp_fsuid != from_kuid(&init_user_ns, current_fsuid())) 140 continue; 141 if (lrp->lrp_fsgid != from_kgid(&init_user_ns, current_fsgid())) 142 continue; 143 found = 1; 144 break; 145 } 146 147 if (!found) { 148 rc = -ENOENT; 149 goto out; 150 } 151 152 CDEBUG(D_SEC, "found remote perm: %u/%u/%u/%u - %#x\n", 153 lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid, 154 lrp->lrp_access_perm); 155 rc = ((lrp->lrp_access_perm & mask) == mask) ? 0 : -EACCES; 156 157out: 158 spin_unlock(&lli->lli_lock); 159 return rc; 160} 161 162int ll_update_remote_perm(struct inode *inode, struct mdt_remote_perm *perm) 163{ 164 struct ll_inode_info *lli = ll_i2info(inode); 165 struct ll_remote_perm *lrp = NULL, *tmp = NULL; 166 struct hlist_head *head, *perm_hash = NULL; 167 168 LASSERT(ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT); 169 170#if 0 171 if (perm->rp_uid != current->uid || 172 perm->rp_gid != current->gid || 173 perm->rp_fsuid != current->fsuid || 174 perm->rp_fsgid != current->fsgid) { 175 /* user might setxid in this small period */ 176 CDEBUG(D_SEC, 177 "remote perm user %u/%u/%u/%u != current %u/%u/%u/%u\n", 178 perm->rp_uid, perm->rp_gid, perm->rp_fsuid, 179 perm->rp_fsgid, current->uid, current->gid, 180 current->fsuid, current->fsgid); 181 return -EAGAIN; 182 } 183#endif 184 185 if (!lli->lli_remote_perms) { 186 perm_hash = alloc_rmtperm_hash(); 187 if (perm_hash == NULL) { 188 CERROR("alloc lli_remote_perms failed!\n"); 189 return -ENOMEM; 190 } 191 } 192 193 spin_lock(&lli->lli_lock); 194 195 if (!lli->lli_remote_perms) 196 lli->lli_remote_perms = perm_hash; 197 else if (perm_hash) 198 free_rmtperm_hash(perm_hash); 199 200 head = lli->lli_remote_perms + remote_perm_hashfunc(perm->rp_uid); 201 202again: 203 hlist_for_each_entry(tmp, head, lrp_list) { 204 if (tmp->lrp_uid != perm->rp_uid) 205 continue; 206 if (tmp->lrp_gid != perm->rp_gid) 207 continue; 208 if (tmp->lrp_fsuid != perm->rp_fsuid) 209 continue; 210 if (tmp->lrp_fsgid != perm->rp_fsgid) 211 continue; 212 if (lrp) 213 free_ll_remote_perm(lrp); 214 lrp = tmp; 215 break; 216 } 217 218 if (!lrp) { 219 spin_unlock(&lli->lli_lock); 220 lrp = alloc_ll_remote_perm(); 221 if (!lrp) { 222 CERROR("alloc memory for ll_remote_perm failed!\n"); 223 return -ENOMEM; 224 } 225 spin_lock(&lli->lli_lock); 226 goto again; 227 } 228 229 lrp->lrp_access_perm = perm->rp_access_perm; 230 if (lrp != tmp) { 231 lrp->lrp_uid = perm->rp_uid; 232 lrp->lrp_gid = perm->rp_gid; 233 lrp->lrp_fsuid = perm->rp_fsuid; 234 lrp->lrp_fsgid = perm->rp_fsgid; 235 hlist_add_head(&lrp->lrp_list, head); 236 } 237 lli->lli_rmtperm_time = cfs_time_current(); 238 spin_unlock(&lli->lli_lock); 239 240 CDEBUG(D_SEC, "new remote perm@%p: %u/%u/%u/%u - %#x\n", 241 lrp, lrp->lrp_uid, lrp->lrp_gid, lrp->lrp_fsuid, lrp->lrp_fsgid, 242 lrp->lrp_access_perm); 243 244 return 0; 245} 246 247int lustre_check_remote_perm(struct inode *inode, int mask) 248{ 249 struct ll_inode_info *lli = ll_i2info(inode); 250 struct ll_sb_info *sbi = ll_i2sbi(inode); 251 struct ptlrpc_request *req = NULL; 252 struct mdt_remote_perm *perm; 253 struct obd_capa *oc; 254 unsigned long save; 255 int i = 0, rc; 256 257 do { 258 save = lli->lli_rmtperm_time; 259 rc = do_check_remote_perm(lli, mask); 260 if (!rc || (rc != -ENOENT && i)) 261 break; 262 263 might_sleep(); 264 265 mutex_lock(&lli->lli_rmtperm_mutex); 266 /* check again */ 267 if (save != lli->lli_rmtperm_time) { 268 rc = do_check_remote_perm(lli, mask); 269 if (!rc || (rc != -ENOENT && i)) { 270 mutex_unlock(&lli->lli_rmtperm_mutex); 271 break; 272 } 273 } 274 275 if (i++ > 5) { 276 CERROR("check remote perm falls in dead loop!\n"); 277 LBUG(); 278 } 279 280 oc = ll_mdscapa_get(inode); 281 rc = md_get_remote_perm(sbi->ll_md_exp, ll_inode2fid(inode), oc, 282 ll_i2suppgid(inode), &req); 283 capa_put(oc); 284 if (rc) { 285 mutex_unlock(&lli->lli_rmtperm_mutex); 286 break; 287 } 288 289 perm = req_capsule_server_swab_get(&req->rq_pill, &RMF_ACL, 290 lustre_swab_mdt_remote_perm); 291 if (unlikely(perm == NULL)) { 292 mutex_unlock(&lli->lli_rmtperm_mutex); 293 rc = -EPROTO; 294 break; 295 } 296 297 rc = ll_update_remote_perm(inode, perm); 298 mutex_unlock(&lli->lli_rmtperm_mutex); 299 if (rc == -ENOMEM) 300 break; 301 302 ptlrpc_req_finished(req); 303 req = NULL; 304 } while (1); 305 ptlrpc_req_finished(req); 306 return rc; 307} 308 309#if 0 /* NB: remote perms can't be freed in ll_mdc_blocking_ast of UPDATE lock, 310 * because it will fail sanity test 48. 311 */ 312void ll_free_remote_perms(struct inode *inode) 313{ 314 struct ll_inode_info *lli = ll_i2info(inode); 315 struct hlist_head *hash = lli->lli_remote_perms; 316 struct ll_remote_perm *lrp; 317 struct hlist_node *node, *next; 318 int i; 319 320 LASSERT(hash); 321 322 spin_lock(&lli->lli_lock); 323 324 for (i = 0; i < REMOTE_PERM_HASHSIZE; i++) { 325 hlist_for_each_entry_safe(lrp, node, next, hash + i, 326 lrp_list) 327 free_ll_remote_perm(lrp); 328 } 329 330 spin_unlock(&lli->lli_lock); 331} 332#endif 333