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);
506 rec->ur_fsuid = req->rq_uid;
512 struct mds_idmap_table *__get_idmap_table(struct mds_export_data *med,
515 struct mds_idmap_table *new;
518 if (!create || med->med_idmap)
519 return med->med_idmap;
521 spin_unlock(&med->med_idmap_lock);
522 OBD_ALLOC(new, sizeof(*new));
523 spin_lock(&med->med_idmap_lock);
526 CERROR("fail to alloc %d\n", sizeof(*new));
530 if (med->med_idmap) {
531 OBD_FREE(new, sizeof(*new));
532 return med->med_idmap;
535 for (i = 0; i < MDS_IDMAP_HASHSIZE; i++) {
536 INIT_LIST_HEAD(&new->uidmap[i]);
537 INIT_LIST_HEAD(&new->gidmap[i]);
540 CDEBUG(D_SEC, "allocate idmap table for med %p\n", med);
541 med->med_idmap = new;
545 static void __flush_mapping_table(struct list_head *table)
547 struct mds_idmap_item *item;
550 for (i = 0; i < MDS_IDMAP_HASHSIZE; i++) {
551 while (!list_empty(&table[i])) {
552 item = list_entry(table[i].next, struct mds_idmap_item,
554 list_del(&item->hash);
555 OBD_FREE(item, sizeof(*item));
560 void mds_idmap_cleanup(struct mds_export_data *med)
564 if (!med->med_idmap) {
569 spin_lock(&med->med_idmap_lock);
570 __flush_mapping_table(med->med_idmap->uidmap);
571 __flush_mapping_table(med->med_idmap->gidmap);
572 OBD_FREE(med->med_idmap, sizeof(struct mds_idmap_table));
573 spin_unlock(&med->med_idmap_lock);
576 static inline int idmap_hash(__u32 id)
578 return (id & (MDS_IDMAP_HASHSIZE - 1));
582 int __idmap_set_item(struct mds_export_data *med,
583 struct list_head *table,
584 __u32 id1, __u32 id2)
586 struct list_head *head;
587 struct mds_idmap_item *item, *new = NULL;
590 head = table + idmap_hash(id1);
592 list_for_each_entry(item, head, hash) {
593 if (item->id1 == id1) {
601 spin_unlock(&med->med_idmap_lock);
602 OBD_ALLOC(new, sizeof(*new));
603 spin_lock(&med->med_idmap_lock);
605 CERROR("fail to alloc %d\n", sizeof(*new));
612 list_add(&new->hash, head);
615 OBD_FREE(new, sizeof(*new));
616 if (item->id2 != id2) {
617 CWARN("mapping changed: %u ==> (%u -> %u)\n",
618 id1, item->id2, id2);
621 list_move(&item->hash, head);
627 int mds_idmap_set(struct mds_export_data *med, __u32 id1, __u32 id2,
630 struct mds_idmap_table *idmap;
634 spin_lock(&med->med_idmap_lock);
636 idmap = __get_idmap_table(med, 1);
638 GOTO(out, rc = -ENOMEM);
641 rc = __idmap_set_item(med, idmap->uidmap, id1, id2);
643 rc = __idmap_set_item(med, idmap->gidmap, id1, id2);
646 spin_unlock(&med->med_idmap_lock);
650 __u32 mds_idmap_get(struct mds_export_data *med, __u32 id,
653 struct mds_idmap_table *idmap;
654 struct list_head *table;
655 struct list_head *head;
656 struct mds_idmap_item *item;
660 spin_lock(&med->med_idmap_lock);
661 idmap = __get_idmap_table(med, 0);
665 table = is_uid_mapping ? idmap->uidmap : idmap->gidmap;
666 head = table + idmap_hash(id);
668 list_for_each_entry(item, head, hash) {
669 if (item->id1 == id) {
679 spin_unlock(&med->med_idmap_lock);
682 res = is_uid_mapping ? med->med_nllu : med->med_nllg;
686 void mds_reverse_map_ugid(struct ptlrpc_request *req,
687 struct mds_body *body)
689 struct mds_export_data *med = &req->rq_export->u.eu_mds_data;
691 LASSERT(req->rq_remote);
693 if (body->valid & OBD_MD_FLUID)
694 body->uid = mds_idmap_get(med, body->uid, 1);
696 if (body->valid & OBD_MD_FLGID)
697 body->gid = mds_idmap_get(med, body->gid, 0);
700 static inline void drop_ucred_ginfo(struct lvfs_ucred *ucred)
702 if (ucred->luc_ginfo) {
703 put_group_info(ucred->luc_ginfo);
704 ucred->luc_ginfo = NULL;
708 static inline void drop_ucred_lsd(struct lvfs_ucred *ucred)
710 if (ucred->luc_lsd) {
711 mds_put_lsd(ucred->luc_lsd);
712 ucred->luc_lsd = NULL;
717 * the heart of the uid/gid handling and security checking.
719 * root could set any group_info if we allowed setgroups, while
720 * normal user only could 'reduce' their group members -- which
721 * is somewhat expensive.
723 int mds_init_ucred(struct lvfs_ucred *ucred,
724 struct ptlrpc_request *req,
725 struct mds_req_sec_desc *rsd)
727 struct mds_obd *mds = &req->rq_export->exp_obd->u.mds;
728 struct mds_export_data *med = &req->rq_export->u.eu_mds_data;
729 struct lustre_sec_desc *lsd;
730 ptl_nid_t peernid = req->rq_peer.peer_id.nid;
731 struct group_info *gnew;
732 unsigned int setuid, setgid, strong_sec;
737 LASSERT(rsd->rsd_ngroups <= LUSTRE_MAX_GROUPS);
739 strong_sec = (req->rq_auth_uid != -1);
740 LASSERT(!(req->rq_remote && !strong_sec));
742 /* sanity check & set local/remote flag */
743 if (req->rq_remote) {
744 if (med->med_local) {
745 CWARN("exp %p: client on nid "LPX64" was local, "
746 "set to remote\n", req->rq_export, peernid);
750 if (!med->med_local) {
751 CWARN("exp %p: client on nid "LPX64" was remote, "
752 "set to local\n", req->rq_export, peernid);
757 setuid = (rsd->rsd_fsuid != rsd->rsd_uid);
758 setgid = (rsd->rsd_fsgid != rsd->rsd_gid);
760 /* deny setuid/setgid for remote client */
761 if ((setuid || setgid) && !med->med_local) {
762 CWARN("deny setxid (%u/%u) from remote client "LPX64"\n",
763 setuid, setgid, peernid);
767 /* take care of uid/gid mapping for client in remote realm */
768 if (req->rq_remote) {
769 /* record the uid mapping here */
770 mds_idmap_set(med, req->rq_auth_uid, rsd->rsd_uid, 1);
772 /* now we act as the authenticated user */
773 rsd->rsd_uid = rsd->rsd_fsuid = req->rq_auth_uid;
774 } else if (strong_sec && req->rq_auth_uid != rsd->rsd_uid) {
775 /* if we use strong authentication on this request, we
776 * expect the uid which client claimed is true.
778 * FIXME root's machine_credential in krb5 will be interpret
779 * as "nobody", which is not good for mds-mds and mds-ost
782 CWARN("nid "LPX64": UID %u was authenticated while client "
783 "claimed %u, set %u by force\n",
784 peernid, req->rq_auth_uid, rsd->rsd_uid,
786 rsd->rsd_uid = req->rq_auth_uid;
789 /* now lsd come into play */
790 ucred->luc_ginfo = NULL;
791 ucred->luc_lsd = lsd = mds_get_lsd(rsd->rsd_uid);
794 ucred->luc_fsuid = req->rq_uid;
796 ucred->luc_fsuid = rsd->rsd_fsuid;
799 if (req->rq_remote) {
800 /* record the gid mapping here */
801 mds_idmap_set(med, lsd->lsd_gid, rsd->rsd_gid, 0);
802 /* now we act as the authenticated group */
803 rsd->rsd_gid = rsd->rsd_fsgid = lsd->lsd_gid;
804 } else if (rsd->rsd_gid != lsd->lsd_gid) {
805 /* verify gid which client declared is true */
806 CWARN("GID: %u while client declare %u, "
808 lsd->lsd_gid, rsd->rsd_gid,
810 rsd->rsd_gid = lsd->lsd_gid;
813 if (lsd->lsd_ginfo) {
814 ucred->luc_ginfo = lsd->lsd_ginfo;
815 get_group_info(ucred->luc_ginfo);
818 /* check permission of setuid */
820 if (!lsd->lsd_allow_setuid) {
821 CWARN("mds blocked setuid attempt: %u -> %u\n",
822 rsd->rsd_uid, rsd->rsd_fsuid);
827 /* check permission of setgid */
829 if (!lsd->lsd_allow_setgid) {
830 CWARN("mds blocked setgid attempt: %u -> %u\n",
831 rsd->rsd_gid, rsd->rsd_fsgid);
836 /* failed to get lsd, right now we simply deny any access
837 * if strong authentication is used,
840 CWARN("mds deny access without LSD\n");
844 /* and otherwise deny setuid/setgid attempt */
845 if (setuid || setgid) {
846 CWARN("mds deny setuid/setgid without LSD\n");
851 /* NOTE: we have already obtained supplementary groups,
852 * it will be retained across root_squash. will it be a
855 mds_squash_root(mds, rsd, &peernid);
857 /* remove privilege for non-root user */
859 rsd->rsd_cap &= ~CAP_FS_MASK;
861 /* by now every fields in rsd have been granted */
862 ucred->luc_fsgid = rsd->rsd_fsgid;
863 ucred->luc_cap = rsd->rsd_cap;
864 ucred->luc_uid = rsd->rsd_uid;
866 /* everything is done if we don't allow setgroups */
867 if (!lsd || !lsd->lsd_allow_setgrp)
870 if (ucred->luc_uid == 0) {
871 if (rsd->rsd_ngroups == 0) {
872 drop_ucred_ginfo(ucred);
876 gnew = groups_alloc(rsd->rsd_ngroups);
878 CERROR("out of memory\n");
879 drop_ucred_ginfo(ucred);
880 drop_ucred_lsd(ucred);
883 groups_from_buffer(gnew, rsd->rsd_groups);
884 groups_sort(gnew); /* can't rely on client */
886 drop_ucred_ginfo(ucred);
887 ucred->luc_ginfo = gnew;
889 __u32 set = 0, cur = 0;
890 struct group_info *ginfo;
892 /* if no group info in hash, we don't
893 * bother createing new
895 if (!ucred->luc_ginfo)
898 /* Note: freeing a group_info count on 'nblocks' instead of
899 * 'ngroups', thus we can safely alloc enough buffer and reduce
900 * and ngroups number later.
902 gnew = groups_alloc(rsd->rsd_ngroups);
904 CERROR("out of memory\n");
905 drop_ucred_ginfo(ucred);
906 drop_ucred_lsd(ucred);
910 ginfo = ucred->luc_ginfo;
911 while (cur < rsd->rsd_ngroups) {
912 if (groups_search(ginfo, rsd->rsd_groups[cur])) {
913 GROUP_AT(gnew, set) = rsd->rsd_groups[cur];
920 put_group_info(ucred->luc_ginfo);
921 ucred->luc_ginfo = gnew;
926 void mds_exit_ucred(struct lvfs_ucred *ucred)
929 drop_ucred_ginfo(ucred);
930 drop_ucred_lsd(ucred);