#include <linux/obd_support.h>
#include <linux/lustre_lib.h>
-#include <linux/lustre_mds.h>
+#include "mds_internal.h"
-void mds_pack_inode2fid(struct ll_fid *fid, struct inode *inode)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)
+struct group_info *groups_alloc(int ngroups)
{
- fid->id = inode->i_ino;
- fid->generation = inode->i_generation;
- fid->f_type = (S_IFMT & inode->i_mode);
+ struct group_info *ginfo;
+
+ LASSERT(ngroups <= NGROUPS_SMALL);
+
+ OBD_ALLOC(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
+ if (!ginfo)
+ return NULL;
+ ginfo->ngroups = ngroups;
+ ginfo->nblocks = 1;
+ ginfo->blocks[0] = ginfo->small_block;
+ atomic_set(&ginfo->usage, 1);
+
+ return ginfo;
}
-/* Note that we can copy all of the fields, just some will not be "valid" */
-void mds_pack_inode2body(struct mds_body *b, struct inode *inode)
+void groups_free(struct group_info *ginfo)
{
- b->valid |= OBD_MD_FLID | OBD_MD_FLCTIME | OBD_MD_FLUID |
- OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLTYPE |
- OBD_MD_FLMODE | OBD_MD_FLNLINK | OBD_MD_FLGENER |
- OBD_MD_FLATIME | OBD_MD_FLMTIME; /* bug 2020 */
+ LASSERT(ginfo->ngroups <= NGROUPS_SMALL);
+ LASSERT(ginfo->nblocks == 1);
+ LASSERT(ginfo->blocks[0] == ginfo->small_block);
+
+ OBD_FREE(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));
+}
+
+/* for 2.4 the group number is small, so simply search the
+ * whole array.
+ */
+int groups_search(struct group_info *ginfo, gid_t grp)
+{
+ int i;
+
+ if (!ginfo)
+ return 0;
+
+ for (i = 0; i < ginfo->ngroups; i++)
+ if (GROUP_AT(ginfo, i) == grp)
+ return 1;
+ return 0;
+}
+
+#else /* >= 2.6.4 */
+
+void groups_sort(struct group_info *ginfo)
+{
+ int base, max, stride;
+ int gidsetsize = ginfo->ngroups;
+
+ for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
+ ; /* nothing */
+ stride /= 3;
+
+ while (stride) {
+ max = gidsetsize - stride;
+ for (base = 0; base < max; base++) {
+ int left = base;
+ int right = left + stride;
+ gid_t tmp = GROUP_AT(ginfo, right);
+
+ while (left >= 0 && GROUP_AT(ginfo, left) > tmp) {
+ GROUP_AT(ginfo, right) =
+ GROUP_AT(ginfo, left);
+ right = left;
+ left -= stride;
+ }
+ GROUP_AT(ginfo, right) = tmp;
+ }
+ stride /= 3;
+ }
+}
+
+int groups_search(struct group_info *ginfo, gid_t grp)
+{
+ int left, right;
+
+ if (!ginfo)
+ return 0;
+
+ left = 0;
+ right = ginfo->ngroups;
+ while (left < right) {
+ int mid = (left + right) / 2;
+ int cmp = grp - GROUP_AT(ginfo, mid);
+ if (cmp > 0)
+ left = mid + 1;
+ else if (cmp < 0)
+ right = mid;
+ else
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+void groups_from_buffer(struct group_info *ginfo, __u32 *gids)
+{
+ int i, ngroups = ginfo->ngroups;
+
+ for (i = 0; i < ginfo->nblocks; i++) {
+ int count = min(NGROUPS_PER_BLOCK, ngroups);
+
+ memcpy(ginfo->blocks[i], gids, count * sizeof(__u32));
+ gids += NGROUPS_PER_BLOCK;
+ ngroups -= count;
+ }
+}
+
+void mds_pack_dentry2id(struct obd_device *obd,
+ struct lustre_id *id,
+ struct dentry *dentry,
+ int read_fid)
+{
+ id_ino(id) = dentry->d_inum;
+ id_gen(id) = dentry->d_generation;
- if (!S_ISREG(inode->i_mode))
- b->valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS | OBD_MD_FLATIME |
- OBD_MD_FLMTIME | OBD_MD_FLRDEV;
+ if (read_fid) {
+ id_fid(id) = dentry->d_fid;
+ id_group(id) = dentry->d_mdsnum;
+ }
+}
+
+void mds_pack_dentry2body(struct obd_device *obd,
+ struct mds_body *b,
+ struct dentry *dentry,
+ int read_fid)
+{
+ b->valid |= OBD_MD_FLID | OBD_MD_FLGENER |
+ OBD_MD_MDS;
+
+ if (read_fid)
+ b->valid |= OBD_MD_FID;
+
+ mds_pack_dentry2id(obd, &b->id1, dentry,
+ read_fid);
+}
- b->ino = inode->i_ino;
+int mds_pack_inode2id(struct obd_device *obd,
+ struct lustre_id *id,
+ struct inode *inode,
+ int read_fid)
+{
+ int rc = 0;
+ ENTRY;
+
+ if (read_fid) {
+ /* we have to avoid deadlock. */
+ if (!down_trylock(&inode->i_sem)) {
+ rc = mds_read_inode_sid(obd, inode, id);
+ up(&inode->i_sem);
+ } else {
+ rc = mds_read_inode_sid(obd, inode, id);
+ }
+ }
+ if (rc == 0) {
+ id_ino(id) = inode->i_ino;
+ id_gen(id) = inode->i_generation;
+ id_type(id) = (S_IFMT & inode->i_mode);
+ }
+ RETURN(rc);
+}
+
+/* Note that we can copy all of the fields, just some will not be "valid" */
+void mds_pack_inode2body(struct obd_device *obd, struct mds_body *b,
+ struct inode *inode, int read_fid)
+{
+ b->valid |= OBD_MD_FLID | OBD_MD_FLCTIME | OBD_MD_FLUID |
+ OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLTYPE |
+ OBD_MD_FLMODE | OBD_MD_FLNLINK | OBD_MD_FLGENER |
+ OBD_MD_FLATIME | OBD_MD_FLMTIME; /* bug 2020 */
+
+ if (!S_ISREG(inode->i_mode)) {
+ b->valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS |
+ OBD_MD_FLATIME | OBD_MD_FLMTIME |
+ OBD_MD_FLRDEV;
+ }
b->atime = LTIME_S(inode->i_atime);
b->mtime = LTIME_S(inode->i_mtime);
b->ctime = LTIME_S(inode->i_ctime);
b->gid = inode->i_gid;
b->flags = inode->i_flags;
b->rdev = inode->i_rdev;
+
/* Return the correct link count for orphan inodes */
- b->nlink = mds_inode_is_orphan(inode) ? 0 : inode->i_nlink;
- b->generation = inode->i_generation;
- b->suppgid = -1;
+ if (mds_inode_is_orphan(inode)) {
+ b->nlink = 0;
+ } else if (S_ISDIR(inode->i_mode)) {
+ b->nlink = 1;
+ } else {
+ b->nlink = inode->i_nlink;
+ }
+ if (read_fid)
+ b->valid |= OBD_MD_FID;
+ mds_pack_inode2id(obd, &b->id1, inode, read_fid);
}
/* unpacking */
if (rec == NULL)
RETURN (-EFAULT);
- r->ur_fsuid = rec->sa_fsuid;
- r->ur_fsgid = rec->sa_fsgid;
- r->ur_cap = rec->sa_cap;
- r->ur_suppgid1 = rec->sa_suppgid;
- r->ur_suppgid2 = -1;
- r->ur_fid1 = &rec->sa_fid;
+ r->ur_id1 = &rec->sa_id;
attr->ia_valid = rec->sa_valid;
attr->ia_mode = rec->sa_mode;
attr->ia_uid = rec->sa_uid;
}
if (req->rq_reqmsg->bufcount > offset + 2) {
- r->ur_logcookies = lustre_msg_buf(req->rq_reqmsg, offset + 2,0);
+ r->ur_logcookies = lustre_msg_buf(req->rq_reqmsg, offset + 2, 0);
if (r->ur_eadata == NULL)
RETURN (-EFAULT);
if (rec == NULL)
RETURN (-EFAULT);
- r->ur_fsuid = rec->cr_fsuid;
- r->ur_fsgid = rec->cr_fsgid;
- r->ur_cap = rec->cr_cap;
- r->ur_fid1 = &rec->cr_fid;
- r->ur_fid2 = &rec->cr_replayfid;
+ r->ur_id1 = &rec->cr_id;
+ r->ur_id2 = &rec->cr_replayid;
r->ur_mode = rec->cr_mode;
r->ur_rdev = rec->cr_rdev;
r->ur_time = rec->cr_time;
r->ur_flags = rec->cr_flags;
- r->ur_suppgid1 = rec->cr_suppgid;
- r->ur_suppgid2 = -1;
LASSERT_REQSWAB (req, offset + 1);
r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
LASSERT_REQSWAB (req, offset + 2);
if (req->rq_reqmsg->bufcount > offset + 2) {
- /* NB for now, we only seem to pass NULL terminated symlink
- * target strings here. If this ever changes, we'll have
- * to stop checking for a buffer filled completely with a
- * NULL terminated string here, and make the callers check
- * depending on what they expect. We should probably stash
- * it in r->ur_eadata in that case, so it's obvious... -eeb
- */
- r->ur_tgt = lustre_msg_string(req->rq_reqmsg, offset + 2, 0);
- if (r->ur_tgt == NULL)
- RETURN (-EFAULT);
- r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
+ if (S_ISLNK(r->ur_mode)) {
+ r->ur_tgt = lustre_msg_string(req->rq_reqmsg,
+ offset + 2, 0);
+ if (r->ur_tgt == NULL)
+ RETURN (-EFAULT);
+ r->ur_tgtlen = req->rq_reqmsg->buflens[offset + 2];
+ } else if (S_ISDIR(r->ur_mode)) {
+ /* Stripe info for mkdir - just a 16bit integer */
+ if (req->rq_reqmsg->buflens[offset + 2] != 2) {
+ CERROR("mkdir stripe info does not match "
+ "expected size %d vs 2\n",
+ req->rq_reqmsg->buflens[offset + 2]);
+ RETURN (-EINVAL);
+ }
+ r->ur_eadata = lustre_swab_buf (req->rq_reqmsg,
+ offset + 2, 2, __swab16s);
+ r->ur_eadatalen = req->rq_reqmsg->buflens[offset + 2];
+ } else {
+ /* Hm, no other users so far? */
+ LBUG();
+ }
}
RETURN(0);
}
if (rec == NULL)
RETURN (-EFAULT);
- r->ur_fsuid = rec->lk_fsuid;
- r->ur_fsgid = rec->lk_fsgid;
- r->ur_cap = rec->lk_cap;
- r->ur_suppgid1 = rec->lk_suppgid1;
- r->ur_suppgid2 = rec->lk_suppgid2;
- r->ur_fid1 = &rec->lk_fid1;
- r->ur_fid2 = &rec->lk_fid2;
+ r->ur_id1 = &rec->lk_id1;
+ r->ur_id2 = &rec->lk_id2;
r->ur_time = rec->lk_time;
LASSERT_REQSWAB (req, offset + 1);
if (rec == NULL)
RETURN(-EFAULT);
- r->ur_fsuid = rec->ul_fsuid;
- r->ur_fsgid = rec->ul_fsgid;
- r->ur_cap = rec->ul_cap;
r->ur_mode = rec->ul_mode;
- r->ur_suppgid1 = rec->ul_suppgid;
- r->ur_suppgid2 = -1;
- r->ur_fid1 = &rec->ul_fid1;
- r->ur_fid2 = &rec->ul_fid2;
+ r->ur_id1 = &rec->ul_id1;
+ r->ur_id2 = &rec->ul_id2;
r->ur_time = rec->ul_time;
LASSERT_REQSWAB (req, offset + 1);
ENTRY;
rec = lustre_swab_reqbuf (req, offset, sizeof (*rec),
- lustre_swab_mds_rec_unlink);
+ lustre_swab_mds_rec_rename);
if (rec == NULL)
RETURN(-EFAULT);
- r->ur_fsuid = rec->rn_fsuid;
- r->ur_fsgid = rec->rn_fsgid;
- r->ur_cap = rec->rn_cap;
- r->ur_suppgid1 = rec->rn_suppgid1;
- r->ur_suppgid2 = rec->rn_suppgid2;
- r->ur_fid1 = &rec->rn_fid1;
- r->ur_fid2 = &rec->rn_fid2;
+ r->ur_id1 = &rec->rn_id1;
+ r->ur_id2 = &rec->rn_id2;
r->ur_time = rec->rn_time;
LASSERT_REQSWAB (req, offset + 1);
if (rec == NULL)
RETURN (-EFAULT);
- r->ur_fsuid = rec->cr_fsuid;
- r->ur_fsgid = rec->cr_fsgid;
- r->ur_cap = rec->cr_cap;
- r->ur_fid1 = &rec->cr_fid;
- r->ur_fid2 = &rec->cr_replayfid;
+ r->ur_id1 = &rec->cr_id;
+ r->ur_id2 = &rec->cr_replayid;
r->ur_mode = rec->cr_mode;
r->ur_rdev = rec->cr_rdev;
r->ur_time = rec->cr_time;
r->ur_flags = rec->cr_flags;
- r->ur_suppgid1 = rec->cr_suppgid;
- r->ur_suppgid2 = -1;
LASSERT_REQSWAB (req, offset + 1);
r->ur_name = lustre_msg_string (req->rq_reqmsg, offset + 1, 0);
int rc;
ENTRY;
- /* NB don't lustre_swab_reqbuf() here. We're just taking a peek
- * and we want to leave it to the specific unpacker once we've
- * identified the message type */
- opcodep = lustre_msg_buf (req->rq_reqmsg, offset, sizeof (*opcodep));
+ /*
+ * NB don't lustre_swab_reqbuf() here. We're just taking a peek and we
+ * want to leave it to the specific unpacker once we've identified the
+ * message type.
+ */
+ opcodep = lustre_msg_buf (req->rq_reqmsg, offset, sizeof(*opcodep));
if (opcodep == NULL)
RETURN(-EFAULT);
RETURN(-EFAULT);
}
+ rec->ur_id1 = NULL;
+ rec->ur_id2 = NULL;
rec->ur_opcode = opcode;
+
rc = mds_unpackers[opcode](req, offset, rec);
RETURN(rc);
}
+
+static inline void drop_ucred_ginfo(struct lvfs_ucred *ucred)
+{
+ if (ucred->luc_ginfo) {
+ put_group_info(ucred->luc_ginfo);
+ ucred->luc_ginfo = NULL;
+ }
+}
+
+/*
+ * root could set any group_info if we allowed setgroups, while
+ * normal user only could 'reduce' their group members -- which
+ * is somewhat expensive.
+ */
+int mds_init_ucred(struct lvfs_ucred *ucred, struct mds_req_sec_desc *rsd)
+{
+ struct group_info *gnew;
+
+ ENTRY;
+ LASSERT(ucred);
+ LASSERT(rsd);
+
+ ucred->luc_fsuid = rsd->rsd_fsuid;
+ ucred->luc_fsgid = rsd->rsd_fsgid;
+ ucred->luc_cap = rsd->rsd_cap;
+ ucred->luc_uid = rsd->rsd_uid;
+ ucred->luc_ghash = mds_get_group_entry(NULL, rsd->rsd_uid);
+ ucred->luc_ginfo = NULL;
+
+ if (ucred->luc_ghash && ucred->luc_ghash->ge_group_info) {
+ ucred->luc_ginfo = ucred->luc_ghash->ge_group_info;
+ get_group_info(ucred->luc_ginfo);
+ }
+
+ /* everything is done if we don't allow set groups */
+ if (!mds_allow_setgroups())
+ RETURN(0);
+
+ if (rsd->rsd_ngroups > LUSTRE_MAX_GROUPS) {
+ CERROR("client provide too many groups: %d\n",
+ rsd->rsd_ngroups);
+ drop_ucred_ginfo(ucred);
+ mds_put_group_entry(NULL, ucred->luc_ghash);
+ RETURN(-EFAULT);
+ }
+
+ if (ucred->luc_uid == 0) {
+ if (rsd->rsd_ngroups == 0) {
+ drop_ucred_ginfo(ucred);
+ RETURN(0);
+ }
+
+ gnew = groups_alloc(rsd->rsd_ngroups);
+ if (!gnew) {
+ CERROR("out of memory\n");
+ drop_ucred_ginfo(ucred);
+ mds_put_group_entry(NULL, ucred->luc_ghash);
+ RETURN(-ENOMEM);
+ }
+ groups_from_buffer(gnew, rsd->rsd_groups);
+ /* can't rely on client to sort them */
+ groups_sort(gnew);
+
+ drop_ucred_ginfo(ucred);
+ ucred->luc_ginfo = gnew;
+ } else {
+ __u32 set = 0, cur = 0;
+ struct group_info *ginfo;
+
+ /* if no group info in hash, we don't
+ * bother createing new
+ */
+ if (!ucred->luc_ginfo)
+ RETURN(0);
+
+ /* Note: freeing a group_info count on 'nblocks' instead of
+ * 'ngroups', thus we can safely alloc enough buffer and reduce
+ * and ngroups number later.
+ */
+ gnew = groups_alloc(rsd->rsd_ngroups);
+ if (!gnew) {
+ CERROR("out of memory\n");
+ drop_ucred_ginfo(ucred);
+ mds_put_group_entry(NULL, ucred->luc_ghash);
+ RETURN(-ENOMEM);
+ }
+
+ ginfo = ucred->luc_ginfo;
+ while (cur < rsd->rsd_ngroups) {
+ if (groups_search(ginfo, rsd->rsd_groups[cur])) {
+ GROUP_AT(gnew, set) = rsd->rsd_groups[cur];
+ set++;
+ }
+ cur++;
+ }
+ gnew->ngroups = set;
+
+ put_group_info(ucred->luc_ginfo);
+ ucred->luc_ginfo = gnew;
+ }
+ RETURN(0);
+}
+
+void mds_exit_ucred(struct lvfs_ucred *ucred)
+{
+ ENTRY;
+
+ if (ucred->luc_ginfo)
+ put_group_info(ucred->luc_ginfo);
+ if (ucred->luc_ghash)
+ mds_put_group_entry(NULL, ucred->luc_ghash);
+
+ EXIT;
+}