4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
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
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
34 * lustre/obdclass/idmap.c
36 * Lustre user identity mapping.
38 * Author: Fan Yong <fanyong@clusterfs.com>
41 #define DEBUG_SUBSYSTEM S_SEC
43 #include <lustre_idmap.h>
44 #include <obd_support.h>
46 #define lustre_get_group_info(group_info) do { \
47 cfs_atomic_inc(&(group_info)->usage); \
50 #define lustre_put_group_info(group_info) do { \
51 if (cfs_atomic_dec_and_test(&(group_info)->usage)) \
52 cfs_groups_free(group_info); \
56 * groups_search() is copied from linux kernel!
59 static int lustre_groups_search(cfs_group_info_t *group_info,
68 right = group_info->ngroups;
69 while (left < right) {
70 int mid = (left + right) / 2;
71 int cmp = grp - CFS_GROUP_AT(group_info, mid);
83 void lustre_groups_from_list(cfs_group_info_t *ginfo, gid_t *glist)
86 int count = ginfo->ngroups;
88 /* fill group_info from gid array */
89 for (i = 0; i < ginfo->nblocks && count > 0; i++) {
90 int cp_count = min(CFS_NGROUPS_PER_BLOCK, count);
91 int off = i * CFS_NGROUPS_PER_BLOCK;
92 int len = cp_count * sizeof(*glist);
94 memcpy(ginfo->blocks[i], glist + off, len);
98 EXPORT_SYMBOL(lustre_groups_from_list);
100 /* groups_sort() is copied from linux kernel! */
101 /* a simple shell-metzner sort */
102 void lustre_groups_sort(cfs_group_info_t *group_info)
104 int base, max, stride;
105 int gidsetsize = group_info->ngroups;
107 for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
112 max = gidsetsize - stride;
113 for (base = 0; base < max; base++) {
115 int right = left + stride;
116 gid_t tmp = CFS_GROUP_AT(group_info, right);
119 CFS_GROUP_AT(group_info, left) > tmp) {
120 CFS_GROUP_AT(group_info, right) =
121 CFS_GROUP_AT(group_info, left);
125 CFS_GROUP_AT(group_info, right) = tmp;
130 EXPORT_SYMBOL(lustre_groups_sort);
132 int lustre_in_group_p(struct md_ucred *mu, gid_t grp)
136 if (grp != mu->mu_fsgid) {
137 cfs_group_info_t *group_info = NULL;
139 if (mu->mu_ginfo || !mu->mu_identity ||
140 mu->mu_valid == UCRED_OLD)
141 if (grp == mu->mu_suppgids[0] ||
142 grp == mu->mu_suppgids[1])
146 group_info = mu->mu_ginfo;
147 else if (mu->mu_identity)
148 group_info = mu->mu_identity->mi_ginfo;
153 lustre_get_group_info(group_info);
154 rc = lustre_groups_search(group_info, grp);
155 lustre_put_group_info(group_info);
159 EXPORT_SYMBOL(lustre_in_group_p);
161 struct lustre_idmap_entry {
162 cfs_list_t lie_rmt_uid_hash; /* hashed as lie_rmt_uid; */
163 cfs_list_t lie_lcl_uid_hash; /* hashed as lie_lcl_uid; */
164 cfs_list_t lie_rmt_gid_hash; /* hashed as lie_rmt_gid; */
165 cfs_list_t lie_lcl_gid_hash; /* hashed as lie_lcl_gid; */
166 uid_t lie_rmt_uid; /* remote uid */
167 uid_t lie_lcl_uid; /* local uid */
168 gid_t lie_rmt_gid; /* remote gid */
169 gid_t lie_lcl_gid; /* local gid */
172 static inline __u32 lustre_idmap_hashfunc(__u32 id)
174 return id & (CFS_IDMAP_HASHSIZE - 1);
178 struct lustre_idmap_entry *idmap_entry_alloc(uid_t rmt_uid, uid_t lcl_uid,
179 gid_t rmt_gid, gid_t lcl_gid)
181 struct lustre_idmap_entry *e;
187 CFS_INIT_LIST_HEAD(&e->lie_rmt_uid_hash);
188 CFS_INIT_LIST_HEAD(&e->lie_lcl_uid_hash);
189 CFS_INIT_LIST_HEAD(&e->lie_rmt_gid_hash);
190 CFS_INIT_LIST_HEAD(&e->lie_lcl_gid_hash);
191 e->lie_rmt_uid = rmt_uid;
192 e->lie_lcl_uid = lcl_uid;
193 e->lie_rmt_gid = rmt_gid;
194 e->lie_lcl_gid = lcl_gid;
199 static void idmap_entry_free(struct lustre_idmap_entry *e)
201 if (!cfs_list_empty(&e->lie_rmt_uid_hash))
202 cfs_list_del(&e->lie_rmt_uid_hash);
203 if (!cfs_list_empty(&e->lie_lcl_uid_hash))
204 cfs_list_del(&e->lie_lcl_uid_hash);
205 if (!cfs_list_empty(&e->lie_rmt_gid_hash))
206 cfs_list_del(&e->lie_rmt_gid_hash);
207 if (!cfs_list_empty(&e->lie_lcl_gid_hash))
208 cfs_list_del(&e->lie_lcl_gid_hash);
214 * NULL: not found entry
215 * ERR_PTR(-EACCES): found 1(remote):N(local) mapped entry
216 * others: found normal entry
219 struct lustre_idmap_entry *idmap_search_entry(struct lustre_idmap_table *t,
220 uid_t rmt_uid, uid_t lcl_uid,
221 gid_t rmt_gid, gid_t lcl_gid)
224 struct lustre_idmap_entry *e;
226 head = &t->lit_idmaps[RMT_UIDMAP_IDX][lustre_idmap_hashfunc(rmt_uid)];
227 cfs_list_for_each_entry(e, head, lie_rmt_uid_hash)
228 if (e->lie_rmt_uid == rmt_uid) {
229 if (e->lie_lcl_uid == lcl_uid) {
230 if (e->lie_rmt_gid == rmt_gid &&
231 e->lie_lcl_gid == lcl_gid)
232 /* must be quaternion match */
235 /* 1:N uid mapping */
236 CERROR("rmt uid %u already be mapped to %u"
237 " (new %u)\n", e->lie_rmt_uid,
238 e->lie_lcl_uid, lcl_uid);
239 return ERR_PTR(-EACCES);
243 head = &t->lit_idmaps[RMT_GIDMAP_IDX][lustre_idmap_hashfunc(rmt_gid)];
244 cfs_list_for_each_entry(e, head, lie_rmt_gid_hash)
245 if (e->lie_rmt_gid == rmt_gid) {
246 if (e->lie_lcl_gid == lcl_gid) {
247 if (unlikely(e->lie_rmt_uid == rmt_uid &&
248 e->lie_lcl_uid == lcl_uid))
249 /* after uid mapping search above,
250 * we should never come here */
253 /* 1:N gid mapping */
254 CERROR("rmt gid %u already be mapped to %u"
255 " (new %u)\n", e->lie_rmt_gid,
256 e->lie_lcl_gid, lcl_gid);
257 return ERR_PTR(-EACCES);
264 static __u32 idmap_lookup_uid(cfs_list_t *hash, int reverse,
267 cfs_list_t *head = &hash[lustre_idmap_hashfunc(uid)];
268 struct lustre_idmap_entry *e;
271 cfs_list_for_each_entry(e, head, lie_rmt_uid_hash)
272 if (e->lie_rmt_uid == uid)
273 return e->lie_lcl_uid;
275 cfs_list_for_each_entry(e, head, lie_lcl_uid_hash)
276 if (e->lie_lcl_uid == uid)
277 return e->lie_rmt_uid;
280 return CFS_IDMAP_NOTFOUND;
283 static __u32 idmap_lookup_gid(cfs_list_t *hash, int reverse, __u32 gid)
285 cfs_list_t *head = &hash[lustre_idmap_hashfunc(gid)];
286 struct lustre_idmap_entry *e;
289 cfs_list_for_each_entry(e, head, lie_rmt_gid_hash)
290 if (e->lie_rmt_gid == gid)
291 return e->lie_lcl_gid;
293 cfs_list_for_each_entry(e, head, lie_lcl_gid_hash)
294 if (e->lie_lcl_gid == gid)
295 return e->lie_rmt_gid;
298 return CFS_IDMAP_NOTFOUND;
301 int lustre_idmap_add(struct lustre_idmap_table *t,
302 uid_t ruid, uid_t luid,
303 gid_t rgid, gid_t lgid)
305 struct lustre_idmap_entry *e0, *e1;
309 spin_lock(&t->lit_lock);
310 e0 = idmap_search_entry(t, ruid, luid, rgid, lgid);
311 spin_unlock(&t->lit_lock);
313 e0 = idmap_entry_alloc(ruid, luid, rgid, lgid);
317 spin_lock(&t->lit_lock);
318 e1 = idmap_search_entry(t, ruid, luid, rgid, lgid);
320 cfs_list_add_tail(&e0->lie_rmt_uid_hash,
321 &t->lit_idmaps[RMT_UIDMAP_IDX]
322 [lustre_idmap_hashfunc(ruid)]);
323 cfs_list_add_tail(&e0->lie_lcl_uid_hash,
324 &t->lit_idmaps[LCL_UIDMAP_IDX]
325 [lustre_idmap_hashfunc(luid)]);
326 cfs_list_add_tail(&e0->lie_rmt_gid_hash,
327 &t->lit_idmaps[RMT_GIDMAP_IDX]
328 [lustre_idmap_hashfunc(rgid)]);
329 cfs_list_add_tail(&e0->lie_lcl_gid_hash,
330 &t->lit_idmaps[LCL_GIDMAP_IDX]
331 [lustre_idmap_hashfunc(lgid)]);
333 spin_unlock(&t->lit_lock);
335 idmap_entry_free(e0);
339 } else if (IS_ERR(e0)) {
345 EXPORT_SYMBOL(lustre_idmap_add);
347 int lustre_idmap_del(struct lustre_idmap_table *t,
348 uid_t ruid, uid_t luid,
349 gid_t rgid, gid_t lgid)
351 struct lustre_idmap_entry *e;
356 spin_lock(&t->lit_lock);
357 e = idmap_search_entry(t, ruid, luid, rgid, lgid);
362 spin_unlock(&t->lit_lock);
366 EXPORT_SYMBOL(lustre_idmap_del);
368 int lustre_idmap_lookup_uid(struct md_ucred *mu,
369 struct lustre_idmap_table *t,
370 int reverse, uid_t uid)
374 if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) {
376 if (uid == mu->mu_o_uid)
378 else if (uid == mu->mu_o_fsuid)
381 if (uid == mu->mu_uid)
383 else if (uid == mu->mu_fsuid)
384 return mu->mu_o_fsuid;
389 return CFS_IDMAP_NOTFOUND;
391 hash = t->lit_idmaps[reverse ? LCL_UIDMAP_IDX : RMT_UIDMAP_IDX];
393 spin_lock(&t->lit_lock);
394 uid = idmap_lookup_uid(hash, reverse, uid);
395 spin_unlock(&t->lit_lock);
399 EXPORT_SYMBOL(lustre_idmap_lookup_uid);
401 int lustre_idmap_lookup_gid(struct md_ucred *mu, struct lustre_idmap_table *t,
402 int reverse, gid_t gid)
406 if (mu && (mu->mu_valid == UCRED_OLD || mu->mu_valid == UCRED_NEW)) {
408 if (gid == mu->mu_o_gid)
410 else if (gid == mu->mu_o_fsgid)
413 if (gid == mu->mu_gid)
415 else if (gid == mu->mu_fsgid)
416 return mu->mu_o_fsgid;
421 return CFS_IDMAP_NOTFOUND;
423 hash = t->lit_idmaps[reverse ? LCL_GIDMAP_IDX : RMT_GIDMAP_IDX];
425 spin_lock(&t->lit_lock);
426 gid = idmap_lookup_gid(hash, reverse, gid);
427 spin_unlock(&t->lit_lock);
431 EXPORT_SYMBOL(lustre_idmap_lookup_gid);
433 struct lustre_idmap_table *lustre_idmap_init(void)
435 struct lustre_idmap_table *t;
439 if(unlikely(t == NULL))
440 return (ERR_PTR(-ENOMEM));
442 spin_lock_init(&t->lit_lock);
443 for (i = 0; i < ARRAY_SIZE(t->lit_idmaps); i++)
444 for (j = 0; j < ARRAY_SIZE(t->lit_idmaps[i]); j++)
445 CFS_INIT_LIST_HEAD(&t->lit_idmaps[i][j]);
449 EXPORT_SYMBOL(lustre_idmap_init);
451 void lustre_idmap_fini(struct lustre_idmap_table *t)
454 struct lustre_idmap_entry *e;
458 list = t->lit_idmaps[RMT_UIDMAP_IDX];
459 spin_lock(&t->lit_lock);
460 for (i = 0; i < CFS_IDMAP_HASHSIZE; i++)
461 while (!cfs_list_empty(&list[i])) {
462 e = cfs_list_entry(list[i].next,
463 struct lustre_idmap_entry,
467 spin_unlock(&t->lit_lock);
471 EXPORT_SYMBOL(lustre_idmap_fini);