1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2003 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
22 #define DEBUG_SUBSYSTEM S_MDS
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/kernel.h>
28 #include <linux/string.h>
29 #include <linux/stat.h>
30 #include <linux/errno.h>
31 #include <linux/version.h>
32 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
33 # include <linux/locks.h> // for wait_on_buffer
35 # include <linux/buffer_head.h> // for wait_on_buffer
37 #include <linux/unistd.h>
39 #include <asm/system.h>
40 #include <asm/uaccess.h>
43 #include <linux/stat.h>
44 #include <asm/uaccess.h>
45 #include <linux/slab.h>
46 #include <asm/segment.h>
48 #include <linux/obd_support.h>
49 #include <linux/lustre_lib.h>
50 #include "mds_internal.h"
52 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)
53 struct group_info *groups_alloc(int ngroups)
55 struct group_info *ginfo;
57 LASSERT(ngroups <= NGROUPS_SMALL);
59 OBD_ALLOC(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
62 ginfo->ngroups = ngroups;
64 ginfo->blocks[0] = ginfo->small_block;
65 atomic_set(&ginfo->usage, 1);
70 void groups_free(struct group_info *ginfo)
72 LASSERT(ginfo->ngroups <= NGROUPS_SMALL);
73 LASSERT(ginfo->nblocks == 1);
74 LASSERT(ginfo->blocks[0] == ginfo->small_block);
76 OBD_FREE(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
79 /* for 2.4 the group number is small, so simply search the
82 int groups_search(struct group_info *ginfo, gid_t grp)
89 for (i = 0; i < ginfo->ngroups; i++)
90 if (GROUP_AT(ginfo, i) == grp)
97 void groups_sort(struct group_info *ginfo)
99 int base, max, stride;
100 int gidsetsize = ginfo->ngroups;
102 for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
107 max = gidsetsize - stride;
108 for (base = 0; base < max; base++) {
110 int right = left + stride;
111 gid_t tmp = GROUP_AT(ginfo, right);
113 while (left >= 0 && GROUP_AT(ginfo, left) > tmp) {
114 GROUP_AT(ginfo, right) =
115 GROUP_AT(ginfo, left);
119 GROUP_AT(ginfo, right) = tmp;
125 int groups_search(struct group_info *ginfo, gid_t grp)
133 right = ginfo->ngroups;
134 while (left < right) {
135 int mid = (left + right) / 2;
136 int cmp = grp - GROUP_AT(ginfo, mid);
148 void groups_from_buffer(struct group_info *ginfo, __u32 *gids)
150 int i, ngroups = ginfo->ngroups;
152 for (i = 0; i < ginfo->nblocks; i++) {
153 int count = min(NGROUPS_PER_BLOCK, ngroups);
155 memcpy(ginfo->blocks[i], gids, count * sizeof(__u32));
156 gids += NGROUPS_PER_BLOCK;
161 void mds_pack_dentry2id(struct obd_device *obd,
162 struct lustre_id *id,
163 struct dentry *dentry,
166 id_ino(id) = dentry->d_inum;
167 id_gen(id) = dentry->d_generation;
170 id_fid(id) = dentry->d_fid;
171 id_group(id) = dentry->d_mdsnum;
175 void mds_pack_dentry2body(struct obd_device *obd,
177 struct dentry *dentry,
180 b->valid |= OBD_MD_FLID | OBD_MD_FLGENER |
184 b->valid |= OBD_MD_FID;
186 mds_pack_dentry2id(obd, &b->id1, dentry, fid);
189 int mds_pack_inode2id(struct obd_device *obd,
190 struct lustre_id *id,
198 /* we have to avoid deadlock. */
199 if (!down_trylock(&inode->i_sem)) {
200 rc = mds_read_inode_sid(obd, inode, id);
203 rc = mds_read_inode_sid(obd, inode, id);
208 id_ino(id) = inode->i_ino;
209 id_gen(id) = inode->i_generation;
210 id_type(id) = (S_IFMT & inode->i_mode);
215 /* Note that we can copy all of the fields, just some will not be "valid" */
216 void mds_pack_inode2body(struct obd_device *obd, struct mds_body *b,
217 struct inode *inode, int fid)
219 b->valid |= OBD_MD_FLID | OBD_MD_FLCTIME | OBD_MD_FLUID |
220 OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLTYPE |
221 OBD_MD_FLMODE | OBD_MD_FLNLINK | OBD_MD_FLGENER |
222 OBD_MD_FLATIME | OBD_MD_FLMTIME; /* bug 2020 */
224 if (!S_ISREG(inode->i_mode)) {
225 b->valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS |
226 OBD_MD_FLATIME | OBD_MD_FLMTIME |
229 b->atime = LTIME_S(inode->i_atime);
230 b->mtime = LTIME_S(inode->i_mtime);
231 b->ctime = LTIME_S(inode->i_ctime);
232 b->mode = inode->i_mode;
233 b->size = inode->i_size;
234 b->blocks = inode->i_blocks;
235 b->uid = inode->i_uid;
236 b->gid = inode->i_gid;
237 b->flags = inode->i_flags;
238 b->rdev = inode->i_rdev;
240 /* Return the correct link count for orphan inodes */
241 if (mds_inode_is_orphan(inode)) {
243 } else if (S_ISDIR(inode->i_mode)) {
246 b->nlink = inode->i_nlink;
250 b->valid |= OBD_MD_FID;
252 mds_pack_inode2id(obd, &b->id1, inode, fid);
256 static int mds_setattr_unpack(struct ptlrpc_request *req, int offset,
257 struct mds_update_record *r)
259 struct iattr *attr = &r->ur_iattr;
260 struct mds_rec_setattr *rec;
263 rec = lustre_swab_reqbuf(req, offset, sizeof(*rec),
264 lustre_swab_mds_rec_setattr);
268 r->ur_id1 = &rec->sa_id;
269 attr->ia_valid = rec->sa_valid;
270 attr->ia_mode = rec->sa_mode;
271 attr->ia_uid = rec->sa_uid;
272 attr->ia_gid = rec->sa_gid;
273 attr->ia_size = rec->sa_size;
274 LTIME_S(attr->ia_atime) = rec->sa_atime;
275 LTIME_S(attr->ia_mtime) = rec->sa_mtime;
276 LTIME_S(attr->ia_ctime) = rec->sa_ctime;
277 attr->ia_attr_flags = rec->sa_attr_flags;
279 LASSERT_REQSWAB (req, offset + 1);
280 if (req->rq_reqmsg->bufcount > offset + 1) {
281 r->ur_eadata = lustre_msg_buf (req->rq_reqmsg,
283 if (r->ur_eadata == NULL)
285 r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 1];
288 if (req->rq_reqmsg->bufcount > offset + 2) {
289 r->ur_ea2data = lustre_msg_buf(req->rq_reqmsg, offset + 2, 0);
290 if (r->ur_ea2data == NULL)
293 r->ur_ea2datalen = req->rq_reqmsg->buflens[offset + 2];
299 static int mds_create_unpack(struct ptlrpc_request *req, int offset,
300 struct mds_update_record *r)
302 struct mds_rec_create *rec;
305 rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
306 lustre_swab_mds_rec_create);
310 r->ur_id1 = &rec->cr_id;
311 r->ur_id2 = &rec->cr_replayid;
312 r->ur_mode = rec->cr_mode;
313 r->ur_rdev = rec->cr_rdev;
314 r->ur_time = rec->cr_time;
315 r->ur_flags = rec->cr_flags;
317 LASSERT_REQSWAB (req, offset + 1);
318 r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
319 if (r->ur_name == NULL)
321 r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
323 LASSERT_REQSWAB (req, offset + 2);
324 if (req->rq_reqmsg->bufcount > offset + 2) {
325 if (S_ISLNK(r->ur_mode)) {
326 r->ur_tgt = lustre_msg_string(req->rq_reqmsg,
328 if (r->ur_tgt == NULL)
330 r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
331 } else if (S_ISDIR(r->ur_mode)) {
332 /* Stripe info for mkdir - just a 16bit integer */
333 if (req->rq_reqmsg->buflens[offset + 2] != 2) {
334 CERROR("mkdir stripe info does not match "
335 "expected size %d vs 2\n",
336 req->rq_reqmsg->buflens[offset + 2]);
339 r->ur_eadata = lustre_swab_buf (req->rq_reqmsg,
340 offset + 2, 2, __swab16s);
341 r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 2];
343 /* Hm, no other users so far? */
350 static int mds_link_unpack(struct ptlrpc_request *req, int offset,
351 struct mds_update_record *r)
353 struct mds_rec_link *rec;
356 rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
357 lustre_swab_mds_rec_link);
361 r->ur_id1 = &rec->lk_id1;
362 r->ur_id2 = &rec->lk_id2;
363 r->ur_time = rec->lk_time;
365 LASSERT_REQSWAB (req, offset + 1);
366 r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
367 if (r->ur_name == NULL)
369 r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
373 static int mds_unlink_unpack(struct ptlrpc_request *req, int offset,
374 struct mds_update_record *r)
376 struct mds_rec_unlink *rec;
379 rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
380 lustre_swab_mds_rec_unlink);
384 r->ur_mode = rec->ul_mode;
385 r->ur_id1 = &rec->ul_id1;
386 r->ur_id2 = &rec->ul_id2;
387 r->ur_time = rec->ul_time;
389 LASSERT_REQSWAB (req, offset + 1);
390 r->ur_name = lustre_msg_string(req->rq_reqmsg, offset + 1, 0);
391 if (r->ur_name == NULL)
393 r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
397 static int mds_rename_unpack(struct ptlrpc_request *req, int offset,
398 struct mds_update_record *r)
400 struct mds_rec_rename *rec;
403 rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
404 lustre_swab_mds_rec_rename);
408 r->ur_id1 = &rec->rn_id1;
409 r->ur_id2 = &rec->rn_id2;
410 r->ur_time = rec->rn_time;
412 LASSERT_REQSWAB (req, offset + 1);
413 r->ur_name = lustre_msg_string(req->rq_reqmsg, offset + 1, 0);
414 if (r->ur_name == NULL)
416 r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
418 LASSERT_REQSWAB (req, offset + 2);
419 r->ur_tgt = lustre_msg_string(req->rq_reqmsg, offset + 2, 0);
420 if (r->ur_tgt == NULL)
422 r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
426 static int mds_open_unpack(struct ptlrpc_request *req, int offset,
427 struct mds_update_record *r)
429 struct mds_rec_create *rec;
432 rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
433 lustre_swab_mds_rec_create);
437 r->ur_id1 = &rec->cr_id;
438 r->ur_id2 = &rec->cr_replayid;
439 r->ur_mode = rec->cr_mode;
440 r->ur_rdev = rec->cr_rdev;
441 r->ur_time = rec->cr_time;
442 r->ur_flags = rec->cr_flags;
444 LASSERT_REQSWAB (req, offset + 1);
445 r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
446 if (r->ur_name == NULL)
448 r->ur_namelen = req->rq_reqmsg->buflens[offset + 1];
450 LASSERT_REQSWAB (req, offset + 2);
451 if (req->rq_reqmsg->bufcount > offset + 2) {
452 r->ur_eadata = lustre_msg_buf(req->rq_reqmsg, offset + 2, 0);
453 if (r->ur_eadata == NULL)
455 r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 2];
460 typedef int (*update_unpacker)(struct ptlrpc_request *req, int offset,
461 struct mds_update_record *r);
463 static update_unpacker mds_unpackers[REINT_MAX + 1] = {
464 [REINT_SETATTR] mds_setattr_unpack,
465 [REINT_CREATE] mds_create_unpack,
466 [REINT_LINK] mds_link_unpack,
467 [REINT_UNLINK] mds_unlink_unpack,
468 [REINT_RENAME] mds_rename_unpack,
469 [REINT_OPEN] mds_open_unpack,
472 int mds_update_unpack(struct ptlrpc_request *req, int offset,
473 struct mds_update_record *rec)
481 * NB don't lustre_swab_reqbuf() here. We're just taking a peek and we
482 * want to leave it to the specific unpacker once we've identified the
485 opcodep = lustre_msg_buf (req->rq_reqmsg, offset, sizeof(*opcodep));
490 if (lustre_msg_swabbed (req->rq_reqmsg))
493 if (opcode > REINT_MAX ||
494 mds_unpackers[opcode] == NULL) {
495 CERROR ("Unexpected opcode %d\n", opcode);
501 rec->ur_opcode = opcode;
503 rc = mds_unpackers[opcode](req, offset, rec);
508 struct mds_idmap_table *__get_idmap_table(struct mds_export_data *med,
511 struct mds_idmap_table *new;
514 if (!create || med->med_idmap)
515 return med->med_idmap;
517 spin_unlock(&med->med_idmap_lock);
518 OBD_ALLOC(new, sizeof(*new));
519 spin_lock(&med->med_idmap_lock);
522 CERROR("fail to alloc %d\n", sizeof(*new));
526 if (med->med_idmap) {
527 OBD_FREE(new, sizeof(*new));
528 return med->med_idmap;
531 for (i = 0; i < MDS_IDMAP_HASHSIZE; i++) {
532 INIT_LIST_HEAD(&new->uidmap[i]);
533 INIT_LIST_HEAD(&new->gidmap[i]);
536 CDEBUG(D_SEC, "allocate idmap table for med %p\n", med);
537 med->med_idmap = new;
541 static void __flush_mapping_table(struct list_head *table)
543 struct mds_idmap_item *item;
546 for (i = 0; i < MDS_IDMAP_HASHSIZE; i++) {
547 while (!list_empty(&table[i])) {
548 item = list_entry(table[i].next, struct mds_idmap_item,
550 list_del(&item->hash);
551 OBD_FREE(item, sizeof(*item));
556 void mds_idmap_cleanup(struct mds_export_data *med)
560 if (!med->med_idmap) {
565 spin_lock(&med->med_idmap_lock);
566 __flush_mapping_table(med->med_idmap->uidmap);
567 __flush_mapping_table(med->med_idmap->gidmap);
568 OBD_FREE(med->med_idmap, sizeof(struct mds_idmap_table));
569 spin_unlock(&med->med_idmap_lock);
572 static inline int idmap_hash(__u32 id)
574 return (id & (MDS_IDMAP_HASHSIZE - 1));
578 int __idmap_set_item(struct mds_export_data *med,
579 struct list_head *table,
580 __u32 id1, __u32 id2)
582 struct list_head *head;
583 struct mds_idmap_item *item, *new = NULL;
586 head = table + idmap_hash(id1);
588 list_for_each_entry(item, head, hash) {
589 if (item->id1 == id1) {
597 spin_unlock(&med->med_idmap_lock);
598 OBD_ALLOC(new, sizeof(*new));
599 spin_lock(&med->med_idmap_lock);
601 CERROR("fail to alloc %d\n", sizeof(*new));
608 list_add(&new->hash, head);
611 OBD_FREE(new, sizeof(*new));
612 if (item->id2 != id2) {
613 CWARN("mapping changed: %u ==> (%u -> %u)\n",
614 id1, item->id2, id2);
617 list_move(&item->hash, head);
623 int mds_idmap_set(struct mds_export_data *med, __u32 id1, __u32 id2,
626 struct mds_idmap_table *idmap;
630 spin_lock(&med->med_idmap_lock);
632 idmap = __get_idmap_table(med, 1);
634 GOTO(out, rc = -ENOMEM);
637 rc = __idmap_set_item(med, idmap->uidmap, id1, id2);
639 rc = __idmap_set_item(med, idmap->gidmap, id1, id2);
642 spin_unlock(&med->med_idmap_lock);
646 __u32 mds_idmap_get(struct mds_export_data *med, __u32 id,
649 struct mds_idmap_table *idmap;
650 struct list_head *table;
651 struct list_head *head;
652 struct mds_idmap_item *item;
656 spin_lock(&med->med_idmap_lock);
657 idmap = __get_idmap_table(med, 0);
661 table = is_uid_mapping ? idmap->uidmap : idmap->gidmap;
662 head = table + idmap_hash(id);
664 list_for_each_entry(item, head, hash) {
665 if (item->id1 == id) {
675 spin_unlock(&med->med_idmap_lock);
678 res = is_uid_mapping ? med->med_nllu : med->med_nllg;
682 void mds_reverse_map_ugid(struct ptlrpc_request *req,
683 struct mds_body *body)
685 struct mds_export_data *med = &req->rq_export->u.eu_mds_data;
687 LASSERT(req->rq_remote);
689 if (body->valid & OBD_MD_FLUID)
690 body->uid = mds_idmap_get(med, body->uid, 1);
692 if (body->valid & OBD_MD_FLGID)
693 body->gid = mds_idmap_get(med, body->gid, 0);
696 static inline void drop_ucred_ginfo(struct lvfs_ucred *ucred)
698 if (ucred->luc_ginfo) {
699 put_group_info(ucred->luc_ginfo);
700 ucred->luc_ginfo = NULL;
704 static inline void drop_ucred_lsd(struct lvfs_ucred *ucred)
706 if (ucred->luc_lsd) {
707 mds_put_lsd(ucred->luc_lsd);
708 ucred->luc_lsd = NULL;
713 * the heart of the uid/gid handling and security checking.
715 * root could set any group_info if we allowed setgroups, while
716 * normal user only could 'reduce' their group members -- which
717 * is somewhat expensive.
719 int mds_init_ucred(struct lvfs_ucred *ucred,
720 struct ptlrpc_request *req,
721 struct mds_req_sec_desc *rsd)
723 struct mds_obd *mds = &req->rq_export->exp_obd->u.mds;
724 struct mds_export_data *med = &req->rq_export->u.eu_mds_data;
725 struct lustre_sec_desc *lsd;
726 ptl_nid_t peernid = req->rq_peer.peer_id.nid;
727 struct group_info *gnew;
728 unsigned int setuid, setgid, strong_sec;
733 LASSERT(rsd->rsd_ngroups <= LUSTRE_MAX_GROUPS);
735 strong_sec = (req->rq_auth_uid != -1);
736 LASSERT(!(req->rq_remote && !strong_sec));
738 /* sanity check & set local/remote flag */
739 if (req->rq_remote) {
740 if (med->med_local) {
741 CWARN("exp %p: client on nid "LPX64" was local, "
742 "set to remote\n", req->rq_export, peernid);
746 if (!med->med_local) {
747 CWARN("exp %p: client on nid "LPX64" was remote, "
748 "set to local\n", req->rq_export, peernid);
753 setuid = (rsd->rsd_fsuid != rsd->rsd_uid);
754 setgid = (rsd->rsd_fsgid != rsd->rsd_gid);
756 /* deny setuid/setgid for remote client */
757 if ((setuid || setgid) && !med->med_local) {
758 CWARN("deny setxid (%u/%u) from remote client "LPX64"\n",
759 setuid, setgid, peernid);
763 /* take care of uid/gid mapping for client in remote realm */
764 if (req->rq_remote) {
765 /* record the uid mapping here */
766 mds_idmap_set(med, req->rq_auth_uid, rsd->rsd_uid, 1);
768 /* now we act as the authenticated user */
769 rsd->rsd_uid = rsd->rsd_fsuid = req->rq_auth_uid;
770 } else if (strong_sec && req->rq_auth_uid != rsd->rsd_uid) {
771 /* if we use strong authentication on this request, we
772 * expect the uid which client claimed is true.
774 * FIXME root's machine_credential in krb5 will be interpret
775 * as "nobody", which is not good for mds-mds and mds-ost
778 CWARN("nid "LPX64": UID %u was authenticated while client "
779 "claimed %u, set %u by force\n",
780 peernid, req->rq_auth_uid, rsd->rsd_uid,
782 rsd->rsd_uid = req->rq_auth_uid;
785 /* now lsd come into play */
786 ucred->luc_ginfo = NULL;
787 ucred->luc_lsd = lsd = mds_get_lsd(rsd->rsd_uid);
790 if (req->rq_remote) {
791 /* record the gid mapping here */
792 mds_idmap_set(med, lsd->lsd_gid, rsd->rsd_gid, 0);
793 /* now we act as the authenticated group */
794 rsd->rsd_gid = rsd->rsd_fsgid = lsd->lsd_gid;
795 } else if (rsd->rsd_gid != lsd->lsd_gid) {
796 /* verify gid which client declared is true */
797 CWARN("GID: %u while client declare %u, "
799 lsd->lsd_gid, rsd->rsd_gid,
801 rsd->rsd_gid = lsd->lsd_gid;
804 if (lsd->lsd_ginfo) {
805 ucred->luc_ginfo = lsd->lsd_ginfo;
806 get_group_info(ucred->luc_ginfo);
809 /* check permission of setuid */
811 if (!lsd->lsd_allow_setuid) {
812 CWARN("mds blocked setuid attempt: %u -> %u\n",
813 rsd->rsd_uid, rsd->rsd_fsuid);
818 /* check permission of setgid */
820 if (!lsd->lsd_allow_setgid) {
821 CWARN("mds blocked setgid attempt: %u -> %u\n",
822 rsd->rsd_gid, rsd->rsd_fsgid);
827 /* failed to get lsd, right now we simply deny any access
828 * if strong authentication is used,
831 CWARN("mds deny access without LSD\n");
835 /* and otherwise deny setuid/setgid attempt */
836 if (setuid || setgid) {
837 CWARN("mds deny setuid/setgid without LSD\n");
842 /* NOTE: we have already obtained supplementary groups,
843 * it will be retained across root_squash. will it be a
846 mds_squash_root(mds, rsd, &peernid);
848 /* remove privilege for non-root user */
850 rsd->rsd_cap &= ~CAP_FS_MASK;
852 /* by now every fields in rsd have been granted */
853 ucred->luc_fsuid = rsd->rsd_fsuid;
854 ucred->luc_fsgid = rsd->rsd_fsgid;
855 ucred->luc_cap = rsd->rsd_cap;
856 ucred->luc_uid = rsd->rsd_uid;
858 /* everything is done if we don't allow setgroups */
859 if (!lsd || !lsd->lsd_allow_setgrp)
862 if (ucred->luc_uid == 0) {
863 if (rsd->rsd_ngroups == 0) {
864 drop_ucred_ginfo(ucred);
868 gnew = groups_alloc(rsd->rsd_ngroups);
870 CERROR("out of memory\n");
871 drop_ucred_ginfo(ucred);
872 drop_ucred_lsd(ucred);
875 groups_from_buffer(gnew, rsd->rsd_groups);
876 groups_sort(gnew); /* can't rely on client */
878 drop_ucred_ginfo(ucred);
879 ucred->luc_ginfo = gnew;
881 __u32 set = 0, cur = 0;
882 struct group_info *ginfo;
884 /* if no group info in hash, we don't
885 * bother createing new
887 if (!ucred->luc_ginfo)
890 /* Note: freeing a group_info count on 'nblocks' instead of
891 * 'ngroups', thus we can safely alloc enough buffer and reduce
892 * and ngroups number later.
894 gnew = groups_alloc(rsd->rsd_ngroups);
896 CERROR("out of memory\n");
897 drop_ucred_ginfo(ucred);
898 drop_ucred_lsd(ucred);
902 ginfo = ucred->luc_ginfo;
903 while (cur < rsd->rsd_ngroups) {
904 if (groups_search(ginfo, rsd->rsd_groups[cur])) {
905 GROUP_AT(gnew, set) = rsd->rsd_groups[cur];
912 put_group_info(ucred->luc_ginfo);
913 ucred->luc_ginfo = gnew;
918 void mds_exit_ucred(struct lvfs_ucred *ucred)
921 drop_ucred_ginfo(ucred);
922 drop_ucred_lsd(ucred);