From: Joshua Walgenbach Date: Mon, 3 Mar 2014 08:10:20 +0000 (+0100) Subject: LU-4647 nodemap: add mapping functionality X-Git-Tag: 2.6.90~38 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=83f04354ff68a14d7492e35a9576c91492a1206c LU-4647 nodemap: add mapping functionality Add functions to allow the MDT to use the nodemap module functions to map UIDs and GIDs. When a client connects to the MDT, the NID of the client is classified by nodemap and a pointer to the nodemap is added to the export structure. In old_init_ucred and old_init_ucred_reint, the body ids and fs ids are mapped according to the nodemap state (enabled, maps, squashed ids, trust_client_ids and allow_root_access). ACLs are mapped in mdt_getattr_internal. Squashed ACLs are discarded before the ACLs are sent to clients. Trusted administrative nodes are allowed to use setfacl on all users. Mapped nodes can only use setfacl for users also mapped into the node. Change-Id: I9648f6837f8bb4ff145c8a0d647fc934c08aaffe Signed-off-by: Joshua Walgenbach Signed-off-by: Kit Westneat Reviewed-on: http://review.whamcloud.com/9299 Tested-by: Jenkins Reviewed-by: Andreas Dilger Reviewed-by: Nathaniel Clark Tested-by: Maloo --- diff --git a/lustre/Makefile.in b/lustre/Makefile.in index 3e033ca..2794a62 100644 --- a/lustre/Makefile.in +++ b/lustre/Makefile.in @@ -4,7 +4,7 @@ subdir-m += ptlrpc subdir-m += obdecho subdir-m += mgc -@SERVER_TRUE@subdir-m += ost mgs mdt mdd ofd quota osp lod lfsck nodemap +@SERVER_TRUE@subdir-m += ost mgs mdt mdd ofd quota osp lod lfsck @CLIENT_TRUE@subdir-m += lov osc mdc lmv llite fld @LDISKFS_ENABLED_TRUE@subdir-m += osd-ldiskfs @ZFS_ENABLED_TRUE@subdir-m += osd-zfs diff --git a/lustre/autoMakefile.am b/lustre/autoMakefile.am index b52da49..95fb7df 100644 --- a/lustre/autoMakefile.am +++ b/lustre/autoMakefile.am @@ -43,7 +43,7 @@ ALWAYS_SUBDIRS = include obdclass ldlm ptlrpc obdecho \ mgc fid fld doc utils tests scripts autoconf contrib conf SERVER_SUBDIRS = ost mgs mdt mdd ofd osd-zfs osd-ldiskfs \ - quota osp lod target lfsck nodemap + quota osp lod target lfsck CLIENT_SUBDIRS = mdc lmv llite lov osc diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index 07e19b6..7639075 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -2004,8 +2004,6 @@ lustre/lfsck/Makefile lustre/lfsck/autoMakefile lustre/mdt/Makefile lustre/mdt/autoMakefile -lustre/nodemap/Makefile -lustre/nodemap/autoMakefile lustre/mdd/Makefile lustre/mdd/autoMakefile lustre/fld/Makefile diff --git a/lustre/include/lustre_export.h b/lustre/include/lustre_export.h index 318c8dd..3fe565f 100644 --- a/lustre/include/lustre_export.h +++ b/lustre/include/lustre_export.h @@ -67,6 +67,10 @@ struct tg_export_data { loff_t ted_lr_off; /** Client index in last_rcvd file */ int ted_lr_idx; + + /** nodemap this export is a member of */ + struct lu_nodemap *ted_nodemap; + struct hlist_node ted_nodemap_member; }; /** @@ -264,7 +268,6 @@ struct obd_export { struct mgs_export_data eu_mgs_data; } u; - struct nodemap *exp_nodemap; struct adaptive_timeout exp_bl_lock_at; }; diff --git a/lustre/include/lustre_nodemap.h b/lustre/include/lustre_nodemap.h index 23a5f8b..2e0cf6b 100644 --- a/lustre/include/lustre_nodemap.h +++ b/lustre/include/lustre_nodemap.h @@ -71,6 +71,8 @@ struct lu_nodemap { gid_t nm_squash_gid; /* NID range list */ struct list_head nm_ranges; + /* lock for idmap red/black trees */ + rwlock_t nm_idmap_lock; /* UID map keyed by local UID */ struct rb_root nm_fs_to_client_uidmap; /* UID map keyed by remote UID */ @@ -82,7 +84,7 @@ struct lu_nodemap { /* proc directory entry */ struct proc_dir_entry *nm_proc_entry; /* attached client members of this nodemap */ - struct list_head nm_exports; + cfs_hash_t *nm_member_hash; /* access by nodemap name */ struct hlist_node nm_hash; }; @@ -91,14 +93,17 @@ void nodemap_activate(const bool value); int nodemap_add(const char *nodemap_name); int nodemap_del(const char *nodemap_name); struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid); +int nodemap_add_member(lnet_nid_t nid, struct obd_export *exp); +void nodemap_del_member(struct obd_export *exp); int nodemap_parse_range(const char *range_string, lnet_nid_t range[2]); -int nodemap_parse_idmap(const char *idmap_string, __u32 idmap[2]); +int nodemap_parse_idmap(char *idmap_string, __u32 idmap[2]); int nodemap_add_range(const char *name, const lnet_nid_t nid[2]); int nodemap_del_range(const char *name, const lnet_nid_t nid[2]); int nodemap_set_allow_root(const char *name, bool allow_root); int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids); int nodemap_set_squash_uid(const char *name, uid_t uid); int nodemap_set_squash_gid(const char *name, gid_t gid); +bool nodemap_can_setquota(const struct lu_nodemap *nodemap); int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, const __u32 map[2]); int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, @@ -106,4 +111,6 @@ int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, __u32 nodemap_map_id(struct lu_nodemap *nodemap, enum nodemap_id_type id_type, enum nodemap_tree_type tree_type, __u32 id); +ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size, + enum nodemap_tree_type tree_type); #endif /* _LUSTRE_NODEMAP_H */ diff --git a/lustre/mdt/mdt_handler.c b/lustre/mdt/mdt_handler.c index f244e61..0dd6781 100644 --- a/lustre/mdt/mdt_handler.c +++ b/lustre/mdt/mdt_handler.c @@ -69,6 +69,7 @@ #include #include #include +#include mdl_mode_t mdt_mdl_lock_modes[] = { [LCK_MINMODE] = MDL_MINMODE, @@ -391,9 +392,11 @@ static void mdt_pack_size2body(struct mdt_thread_info *info, void mdt_pack_attr2body(struct mdt_thread_info *info, struct mdt_body *b, const struct lu_attr *attr, const struct lu_fid *fid) { - struct md_attr *ma = &info->mti_attr; + struct md_attr *ma = &info->mti_attr; + struct obd_export *exp = info->mti_exp; + struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap; - LASSERT(ma->ma_valid & MA_INODE); + LASSERT(ma->ma_valid & MA_INODE); b->mbo_atime = attr->la_atime; b->mbo_mtime = attr->la_mtime; @@ -401,8 +404,12 @@ void mdt_pack_attr2body(struct mdt_thread_info *info, struct mdt_body *b, b->mbo_mode = attr->la_mode; b->mbo_size = attr->la_size; b->mbo_blocks = attr->la_blocks; - b->mbo_uid = attr->la_uid; - b->mbo_gid = attr->la_gid; + b->mbo_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_FS_TO_CLIENT, + attr->la_uid); + b->mbo_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_FS_TO_CLIENT, + attr->la_gid); b->mbo_flags = attr->la_flags; b->mbo_nlink = attr->la_nlink; b->mbo_rdev = attr->la_rdev; @@ -779,25 +786,27 @@ out: static int mdt_getattr_internal(struct mdt_thread_info *info, struct mdt_object *o, int ma_need) { - struct md_object *next = mdt_object_child(o); - const struct mdt_body *reqbody = info->mti_body; - struct ptlrpc_request *req = mdt_info_req(info); - struct md_attr *ma = &info->mti_attr; - struct lu_attr *la = &ma->ma_attr; - struct req_capsule *pill = info->mti_pill; - const struct lu_env *env = info->mti_env; - struct mdt_body *repbody; - struct lu_buf *buffer = &info->mti_buf; - int rc; - int is_root; - ENTRY; + struct md_object *next = mdt_object_child(o); + const struct mdt_body *reqbody = info->mti_body; + struct ptlrpc_request *req = mdt_info_req(info); + struct md_attr *ma = &info->mti_attr; + struct lu_attr *la = &ma->ma_attr; + struct req_capsule *pill = info->mti_pill; + const struct lu_env *env = info->mti_env; + struct mdt_body *repbody; + struct lu_buf *buffer = &info->mti_buf; + struct obd_export *exp = info->mti_exp; + struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap; + int rc; + int is_root; + ENTRY; - if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETATTR_PACK)) - RETURN(err_serious(-ENOMEM)); + if (OBD_FAIL_CHECK(OBD_FAIL_MDS_GETATTR_PACK)) + RETURN(err_serious(-ENOMEM)); - repbody = req_capsule_server_get(pill, &RMF_MDT_BODY); + repbody = req_capsule_server_get(pill, &RMF_MDT_BODY); - ma->ma_valid = 0; + ma->ma_valid = 0; if (mdt_object_remote(o)) { /* This object is located on remote node.*/ @@ -1018,9 +1027,19 @@ static int mdt_getattr_internal(struct mdt_thread_info *info, PFID(mdt_object_fid(o)), rc); } } else { - repbody->mbo_aclsize = rc; - repbody->mbo_valid |= OBD_MD_FLACL; - rc = 0; + rc = nodemap_map_acl(nodemap, buffer->lb_buf, + rc, NODEMAP_FS_TO_CLIENT); + /* if all ACLs mapped out, rc is still >= 0 */ + if (rc < 0) { + CERROR("%s: nodemap_map_acl unable to" + " parse "DFID" ACL: rc = %d\n", + mdt_obd_name(info->mti_mdt), + PFID(mdt_object_fid(o)), rc); + } else { + repbody->mbo_aclsize = rc; + repbody->mbo_valid |= OBD_MD_FLACL; + rc = 0; + } } } } @@ -1973,6 +1992,7 @@ static int mdt_quotactl(struct tgt_session_info *tsi) int id, rc; struct mdt_device *mdt = mdt_exp2dev(exp); struct lu_device *qmt = mdt->mdt_qmt_dev; + struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap; ENTRY; oqctl = req_capsule_client_get(pill, &RMF_OBD_QUOTACTL); @@ -1993,9 +2013,11 @@ static int mdt_quotactl(struct tgt_session_info *tsi) /* deprecated, not used any more */ RETURN(-EOPNOTSUPP); /* master quotactl */ - case Q_GETINFO: case Q_SETINFO: case Q_SETQUOTA: + if (!nodemap_can_setquota(nodemap)) + RETURN(-EPERM); + case Q_GETINFO: case Q_GETQUOTA: if (qmt == NULL) RETURN(-EOPNOTSUPP); @@ -2034,6 +2056,13 @@ static int mdt_quotactl(struct tgt_session_info *tsi) } } + if (oqctl->qc_type == USRQUOTA) + id = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, id); + else if (oqctl->qc_type == GRPQUOTA) + id = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, id); + repoqc = req_capsule_server_get(pill, &RMF_OBD_QUOTACTL); if (repoqc == NULL) RETURN(err_serious(-EFAULT)); @@ -4994,92 +5023,6 @@ static int mdt_connect_internal(struct obd_export *exp, return 0; } -/* mds_connect copy */ -static int mdt_obd_connect(const struct lu_env *env, - struct obd_export **exp, struct obd_device *obd, - struct obd_uuid *cluuid, - struct obd_connect_data *data, - void *localdata) -{ - struct obd_export *lexp; - struct lustre_handle conn = { 0 }; - struct mdt_device *mdt; - int rc; - ENTRY; - - LASSERT(env != NULL); - if (!exp || !obd || !cluuid) - RETURN(-EINVAL); - - mdt = mdt_dev(obd->obd_lu_dev); - - /* - * first, check whether the stack is ready to handle requests - * XXX: probably not very appropriate method is used now - * at some point we should find a better one - */ - if (!test_bit(MDT_FL_SYNCED, &mdt->mdt_state) && data != NULL && - !(data->ocd_connect_flags & OBD_CONNECT_LIGHTWEIGHT)) { - rc = obd_get_info(env, mdt->mdt_child_exp, - sizeof(KEY_OSP_CONNECTED), - KEY_OSP_CONNECTED, NULL, NULL, NULL); - if (rc) - RETURN(-EAGAIN); - set_bit(MDT_FL_SYNCED, &mdt->mdt_state); - } - - rc = class_connect(&conn, obd, cluuid); - if (rc) - RETURN(rc); - - lexp = class_conn2export(&conn); - LASSERT(lexp != NULL); - - rc = mdt_connect_internal(lexp, mdt, data); - if (rc == 0) { - struct lsd_client_data *lcd = lexp->exp_target_data.ted_lcd; - - LASSERT(lcd); - memcpy(lcd->lcd_uuid, cluuid, sizeof lcd->lcd_uuid); - rc = tgt_client_new(env, lexp); - if (rc == 0) - mdt_export_stats_init(obd, lexp, localdata); - - /* For phase I, sync for cross-ref operation. */ - spin_lock(&lexp->exp_lock); - lexp->exp_keep_sync = 1; - spin_unlock(&lexp->exp_lock); - } - - if (rc != 0) { - class_disconnect(lexp); - *exp = NULL; - } else { - *exp = lexp; - } - - RETURN(rc); -} - -static int mdt_obd_reconnect(const struct lu_env *env, - struct obd_export *exp, struct obd_device *obd, - struct obd_uuid *cluuid, - struct obd_connect_data *data, - void *localdata) -{ - int rc; - ENTRY; - - if (exp == NULL || obd == NULL || cluuid == NULL) - RETURN(-EINVAL); - - rc = mdt_connect_internal(exp, mdt_dev(obd->obd_lu_dev), data); - if (rc == 0) - mdt_export_stats_init(obd, exp, localdata); - - RETURN(rc); -} - static int mdt_ctxt_add_dirty_flag(struct lu_env *env, struct mdt_thread_info *info, struct mdt_file_data *mfd) @@ -5195,6 +5138,7 @@ static int mdt_obd_disconnect(struct obd_export *exp) LASSERT(exp); class_export_get(exp); + nodemap_del_member(exp); rc = server_disconnect_export(exp); if (rc != 0) CDEBUG(D_IOCTL, "server disconnect error: rc = %d\n", rc); @@ -5204,6 +5148,102 @@ static int mdt_obd_disconnect(struct obd_export *exp) RETURN(rc); } +/* mds_connect copy */ +static int mdt_obd_connect(const struct lu_env *env, + struct obd_export **exp, struct obd_device *obd, + struct obd_uuid *cluuid, + struct obd_connect_data *data, + void *localdata) +{ + struct obd_export *lexp; + struct lustre_handle conn = { 0 }; + struct mdt_device *mdt; + int rc; + lnet_nid_t *client_nid = localdata; + ENTRY; + + LASSERT(env != NULL); + if (!exp || !obd || !cluuid) + RETURN(-EINVAL); + + mdt = mdt_dev(obd->obd_lu_dev); + + /* + * first, check whether the stack is ready to handle requests + * XXX: probably not very appropriate method is used now + * at some point we should find a better one + */ + if (!test_bit(MDT_FL_SYNCED, &mdt->mdt_state) && data != NULL && + !(data->ocd_connect_flags & OBD_CONNECT_LIGHTWEIGHT)) { + rc = obd_get_info(env, mdt->mdt_child_exp, + sizeof(KEY_OSP_CONNECTED), + KEY_OSP_CONNECTED, NULL, NULL, NULL); + if (rc) + RETURN(-EAGAIN); + set_bit(MDT_FL_SYNCED, &mdt->mdt_state); + } + + rc = class_connect(&conn, obd, cluuid); + if (rc) + RETURN(rc); + + lexp = class_conn2export(&conn); + LASSERT(lexp != NULL); + + rc = mdt_connect_internal(lexp, mdt, data); + if (rc == 0) { + struct lsd_client_data *lcd = lexp->exp_target_data.ted_lcd; + + LASSERT(lcd); + memcpy(lcd->lcd_uuid, cluuid, sizeof lcd->lcd_uuid); + rc = tgt_client_new(env, lexp); + if (rc == 0) { + rc = nodemap_add_member(*client_nid, lexp); + if (rc != 0 && rc != -EEXIST) + goto out; + + mdt_export_stats_init(obd, lexp, localdata); + } + + /* For phase I, sync for cross-ref operation. */ + spin_lock(&lexp->exp_lock); + lexp->exp_keep_sync = 1; + spin_unlock(&lexp->exp_lock); + } +out: + if (rc != 0) { + class_disconnect(lexp); + *exp = NULL; + } else { + *exp = lexp; + } + + RETURN(rc); +} + +static int mdt_obd_reconnect(const struct lu_env *env, + struct obd_export *exp, struct obd_device *obd, + struct obd_uuid *cluuid, + struct obd_connect_data *data, + void *localdata) +{ + lnet_nid_t *client_nid = localdata; + int rc; + ENTRY; + + if (exp == NULL || obd == NULL || cluuid == NULL) + RETURN(-EINVAL); + + rc = mdt_connect_internal(exp, mdt_dev(obd->obd_lu_dev), data); + if (rc == 0) { + rc = nodemap_add_member(*client_nid, exp); + if (rc == 0 || rc == -EEXIST) + mdt_export_stats_init(obd, exp, localdata); + } + + RETURN(rc); +} + /* FIXME: Can we avoid using these two interfaces? */ static int mdt_init_export(struct obd_export *exp) { diff --git a/lustre/mdt/mdt_internal.h b/lustre/mdt/mdt_internal.h index b87cb65..68750e0 100644 --- a/lustre/mdt/mdt_internal.h +++ b/lustre/mdt/mdt_internal.h @@ -326,7 +326,7 @@ struct mdt_reint_record { const struct lu_fid *rr_fid2; struct lu_name rr_name; struct lu_name rr_tgt_name; - const void *rr_eadata; + void *rr_eadata; int rr_eadatalen; __u32 rr_flags; }; diff --git a/lustre/mdt/mdt_lib.c b/lustre/mdt/mdt_lib.c index 3c1099a..e7af669 100644 --- a/lustre/mdt/mdt_lib.c +++ b/lustre/mdt/mdt_lib.c @@ -50,6 +50,7 @@ #include "mdt_internal.h" #include +#include typedef enum ucred_init_type { NONE_INIT = 0, @@ -421,15 +422,38 @@ out: return rc; } +static void mdt_squash_nodemap_id(struct lu_ucred *ucred, + struct lu_nodemap *nodemap) +{ + if (ucred->uc_o_uid == nodemap->nm_squash_uid) { + ucred->uc_fsuid = nodemap->nm_squash_uid; + ucred->uc_fsgid = nodemap->nm_squash_gid; + ucred->uc_cap = 0; + ucred->uc_suppgids[0] = -1; + ucred->uc_suppgids[1] = -1; + } +} + + static int old_init_ucred(struct mdt_thread_info *info, struct mdt_body *body) { - struct lu_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct md_identity *identity = NULL; - + struct lu_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + struct md_identity *identity = NULL; + struct lu_nodemap *nodemap = + info->mti_exp->exp_target_data.ted_nodemap; ENTRY; + body->mbo_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, body->mbo_uid); + body->mbo_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, body->mbo_gid); + body->mbo_fsuid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, body->mbo_fsuid); + body->mbo_fsgid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, body->mbo_fsgid); + LASSERT(uc != NULL); uc->uc_valid = UCRED_INVALID; uc->uc_o_uid = uc->uc_uid = body->mbo_uid; @@ -454,6 +478,8 @@ static int old_init_ucred(struct mdt_thread_info *info, } uc->uc_identity = identity; + mdt_squash_nodemap_id(uc, nodemap); + /* process root_squash here. */ mdt_root_squash(info, mdt_info_req(info)->rq_peer.nid); @@ -470,17 +496,25 @@ static int old_init_ucred(struct mdt_thread_info *info, static int old_init_ucred_reint(struct mdt_thread_info *info) { - struct lu_ucred *uc = mdt_ucred(info); - struct mdt_device *mdt = info->mti_mdt; - struct md_identity *identity = NULL; - + struct lu_ucred *uc = mdt_ucred(info); + struct mdt_device *mdt = info->mti_mdt; + struct md_identity *identity = NULL; + struct lu_nodemap *nodemap = + info->mti_exp->exp_target_data.ted_nodemap; ENTRY; LASSERT(uc != NULL); + + uc->uc_fsuid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, uc->uc_fsuid); + uc->uc_fsgid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, uc->uc_fsgid); + uc->uc_valid = UCRED_INVALID; uc->uc_o_uid = uc->uc_o_fsuid = uc->uc_uid = uc->uc_fsuid; uc->uc_o_gid = uc->uc_o_fsgid = uc->uc_gid = uc->uc_fsgid; uc->uc_ginfo = NULL; + if (!is_identity_get_disabled(mdt->mdt_identity_cache)) { identity = mdt_identity_get(mdt->mdt_identity_cache, uc->uc_fsuid); @@ -884,12 +918,14 @@ int mdt_name_unpack(struct req_capsule *pill, static int mdt_setattr_unpack_rec(struct mdt_thread_info *info) { - struct lu_ucred *uc = mdt_ucred(info); - struct md_attr *ma = &info->mti_attr; - struct lu_attr *la = &ma->ma_attr; - struct req_capsule *pill = info->mti_pill; - struct mdt_reint_record *rr = &info->mti_rr; - struct mdt_rec_setattr *rec; + struct lu_ucred *uc = mdt_ucred(info); + struct md_attr *ma = &info->mti_attr; + struct lu_attr *la = &ma->ma_attr; + struct req_capsule *pill = info->mti_pill; + struct mdt_reint_record *rr = &info->mti_rr; + struct mdt_rec_setattr *rec; + struct lu_nodemap *nodemap = + info->mti_exp->exp_target_data.ted_nodemap; ENTRY; CLASSERT(sizeof(struct mdt_rec_setattr)== sizeof(struct mdt_rec_reint)); @@ -920,16 +956,18 @@ static int mdt_setattr_unpack_rec(struct mdt_thread_info *info) (rec->sa_valid & MDS_ATTR_CTIME)) la->la_valid |= LA_CTIME; } - la->la_mode = rec->sa_mode; - la->la_flags = rec->sa_attr_flags; - la->la_uid = rec->sa_uid; - la->la_gid = rec->sa_gid; - la->la_size = rec->sa_size; - la->la_blocks = rec->sa_blocks; - la->la_ctime = rec->sa_ctime; - la->la_atime = rec->sa_atime; - la->la_mtime = rec->sa_mtime; - ma->ma_valid = MA_INODE; + la->la_mode = rec->sa_mode; + la->la_flags = rec->sa_attr_flags; + la->la_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, rec->sa_uid); + la->la_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, rec->sa_gid); + la->la_size = rec->sa_size; + la->la_blocks = rec->sa_blocks; + la->la_ctime = rec->sa_ctime; + la->la_atime = rec->sa_atime; + la->la_mtime = rec->sa_mtime; + ma->ma_valid = MA_INODE; if (rec->sa_bias & MDS_DATA_MODIFIED) ma->ma_attr_flags |= MDS_DATA_MODIFIED; diff --git a/lustre/mdt/mdt_xattr.c b/lustre/mdt/mdt_xattr.c index 9678397..480377a 100644 --- a/lustre/mdt/mdt_xattr.c +++ b/lustre/mdt/mdt_xattr.c @@ -46,6 +46,8 @@ #define DEBUG_SUBSYSTEM S_MDS #include +#include +#include #include #include "mdt_internal.h" @@ -354,25 +356,27 @@ _out: int mdt_reint_setxattr(struct mdt_thread_info *info, struct mdt_lock_handle *unused) { - struct ptlrpc_request *req = mdt_info_req(info); - struct lu_ucred *uc = lu_ucred(info->mti_env); - struct mdt_lock_handle *lh; - const struct lu_env *env = info->mti_env; - struct lu_buf *buf = &info->mti_buf; - struct mdt_reint_record *rr = &info->mti_rr; - struct md_attr *ma = &info->mti_attr; - struct lu_attr *attr = &info->mti_attr.ma_attr; - struct mdt_object *obj; - struct md_object *child; - __u64 valid = attr->la_valid; + struct ptlrpc_request *req = mdt_info_req(info); + struct lu_ucred *uc = lu_ucred(info->mti_env); + struct mdt_lock_handle *lh; + const struct lu_env *env = info->mti_env; + struct lu_buf *buf = &info->mti_buf; + struct mdt_reint_record *rr = &info->mti_rr; + struct md_attr *ma = &info->mti_attr; + struct lu_attr *attr = &info->mti_attr.ma_attr; + struct mdt_object *obj; + struct md_object *child; + struct obd_export *exp = info->mti_exp; + struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap; + __u64 valid = attr->la_valid; const char *xattr_name = rr->rr_name.ln_name; - int xattr_len = rr->rr_eadatalen; - __u64 lockpart; - int rc; - posix_acl_xattr_header *new_xattr = NULL; - __u32 remote = exp_connect_rmtclient(info->mti_exp); - __u32 perm; - ENTRY; + int xattr_len = rr->rr_eadatalen; + __u64 lockpart; + int rc; + posix_acl_xattr_header *new_xattr = NULL; + __u32 remote = exp_connect_rmtclient(info->mti_exp); + __u32 perm; + ENTRY; CDEBUG(D_INODE, "setxattr for "DFID"\n", PFID(rr->rr_fid1)); @@ -422,9 +426,19 @@ int mdt_reint_setxattr(struct mdt_thread_info *info, } else if ((valid & OBD_MD_FLXATTR) && (strcmp(xattr_name, XATTR_NAME_ACL_ACCESS) == 0 || strcmp(xattr_name, XATTR_NAME_ACL_DEFAULT) == 0)) { + /* currently lustre limit acl access size */ if (xattr_len > LUSTRE_POSIX_ACL_MAX_SIZE) GOTO(out, rc = -ERANGE); + + rc = nodemap_map_acl(nodemap, rr->rr_eadata, xattr_len, + NODEMAP_CLIENT_TO_FS); + if (rc < 0) + GOTO(out, rc); + + /* ACLs were mapped out, return an error so the user knows */ + if (rc != xattr_len) + GOTO(out, rc = -EPERM); } lockpart = MDS_INODELOCK_UPDATE; @@ -447,8 +461,8 @@ int mdt_reint_setxattr(struct mdt_thread_info *info, * to cancel them. */ mdt_lock_reg_init(lh, LCK_EX); obj = mdt_object_find_lock(info, rr->rr_fid1, lh, lockpart); - if (IS_ERR(obj)) - GOTO(out, rc = PTR_ERR(obj)); + if (IS_ERR(obj)) + GOTO(out, rc = PTR_ERR(obj)); tgt_vbr_obj_set(env, mdt_obj2dt(obj)); rc = mdt_version_get_check_save(info, obj, 0); @@ -464,10 +478,10 @@ int mdt_reint_setxattr(struct mdt_thread_info *info, PFID(rr->rr_fid1), valid); attr->la_ctime = cfs_time_current_sec(); } - attr->la_valid = LA_CTIME; - child = mdt_object_child(obj); - if (valid & OBD_MD_FLXATTR) { - char *xattr = (void *)rr->rr_eadata; + attr->la_valid = LA_CTIME; + child = mdt_object_child(obj); + if (valid & OBD_MD_FLXATTR) { + char *xattr = rr->rr_eadata; if (xattr_len > 0) { int flags = 0; diff --git a/lustre/mgs/mgs_internal.h b/lustre/mgs/mgs_internal.h index 9948ae8..d400c67 100644 --- a/lustre/mgs/mgs_internal.h +++ b/lustre/mgs/mgs_internal.h @@ -217,7 +217,7 @@ int mgs_pool_cmd(const struct lu_env *env, struct mgs_device *mgs, char *ostname); int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs, enum lcfg_command_type cmd, const char *nodemap_name, - const char *param); + char *param); /* mgs_handler.c */ int mgs_get_lock(struct obd_device *obd, struct ldlm_res_id *res, diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c index 64be40c..60a0685 100644 --- a/lustre/mgs/mgs_llog.c +++ b/lustre/mgs/mgs_llog.c @@ -3972,7 +3972,7 @@ out: int mgs_nodemap_cmd(const struct lu_env *env, struct mgs_device *mgs, enum lcfg_command_type cmd, const char *nodemap_name, - const char *param) + char *param) { lnet_nid_t nid[2]; __u32 idmap[2]; diff --git a/lustre/nodemap/Makefile.in b/lustre/nodemap/Makefile.in deleted file mode 100644 index f43aed7..0000000 --- a/lustre/nodemap/Makefile.in +++ /dev/null @@ -1,5 +0,0 @@ -MODULES = nodemap -nodemap-objs = nodemap_handler.o nodemap_lproc.o nodemap_range.o -nodemap-objs += nodemap_idmap.o nodemap_rbtree.o - -@INCLUDE_RULES@ diff --git a/lustre/nodemap/autoMakefile.am b/lustre/nodemap/autoMakefile.am deleted file mode 100644 index ec793f6..0000000 --- a/lustre/nodemap/autoMakefile.am +++ /dev/null @@ -1,27 +0,0 @@ -# -# GPL HEADER START -# -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 only, -# as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License version 2 for more details (a copy is included -# in the LICENSE file that accompanied this code). -# -# You should have received a copy of the GNU General Public License -# version 2 along with this program; If not, see -# http://www.gnu.org/licenses/gpl-2.0.html -# -# GPL HEADER END - -if MODULES -modulefs_DATA = nodemap$(KMODEXT) -endif - -MOSTLYCLEANFILES := @MOSTLYCLEANFILES@ -EXTRA_DIST := $(nodemap-objs:%.o=%.c) nodemap_internal.h diff --git a/lustre/nodemap/nodemap_lproc.c b/lustre/nodemap/nodemap_lproc.c deleted file mode 100644 index 5eecd68..0000000 --- a/lustre/nodemap/nodemap_lproc.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see - * http://www.gnu.org/licenses/gpl-2.0.html - * - * GPL HEADER END - */ -/* - * Copyright (C) 2013, Trustees of Indiana University - * Author: Joshua Walgenbach - */ - -#define NODEMAP_LPROC_ID_LEN 16 -#define NODEMAP_LPROC_FLAG_LEN 2 - -#include -#include -#include -#include "nodemap_internal.h" - -static int nodemap_idmap_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - struct lu_idmap *idmap; - struct rb_node *node; - bool cont = 0; - - seq_printf(m, "[\n"); - for (node = rb_first(&nodemap->nm_client_to_fs_uidmap); node; - node = rb_next(node)) { - if (cont) - seq_printf(m, ",\n"); - cont = 1; - idmap = rb_entry(node, struct lu_idmap, id_client_to_fs); - if (idmap != NULL) - seq_printf(m, " { idtype: uid, client_id: %u, " - "fs_id: %u }", idmap->id_client, - idmap->id_fs); - } - for (node = rb_first(&nodemap->nm_client_to_fs_gidmap); - node; node = rb_next(node)) { - if (cont) - seq_printf(m, ",\n"); - idmap = rb_entry(node, struct lu_idmap, id_client_to_fs); - if (idmap != NULL) - seq_printf(m, " { idtype: gid, client_id: %u, " - "fs_id: %u }", idmap->id_client, - idmap->id_fs); - } - seq_printf(m, "\n"); - seq_printf(m, "]\n"); - - return 0; -} - -static int nodemap_idmap_open(struct inode *inode, struct file *file) -{ - struct lu_nodemap *nodemap = PDE_DATA(inode); - - return single_open(file, nodemap_idmap_show, nodemap); -} - -static int nodemap_ranges_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - struct lu_nid_range *range; - struct interval_node_extent ext; - bool cont = 0; - - seq_printf(m, "[\n"); - list_for_each_entry(range, &nodemap->nm_ranges, rn_list) { - if (cont) - seq_printf(m, ",\n"); - cont = 1; - ext = range->rn_node.in_extent; - seq_printf(m, " { id: %u, start_nid: %s, " - "end_nid: %s }", - range->rn_id, libcfs_nid2str(ext.start), - libcfs_nid2str(ext.end)); - } - seq_printf(m, "\n"); - seq_printf(m, "]\n"); - - return 0; -} - -static int nodemap_ranges_open(struct inode *inode, struct file *file) -{ - struct lu_nodemap *nodemap = PDE_DATA(inode); - - return single_open(file, nodemap_ranges_show, nodemap); -} - -static int nodemap_active_seq_show(struct seq_file *m, void *data) -{ - return seq_printf(m, "%u\n", (unsigned int)nodemap_active); -} - -static ssize_t -nodemap_active_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - char active_string[NODEMAP_LPROC_FLAG_LEN + 1]; - __u32 active; - int rc = count; - - if (count == 0) - return 0; - - if (count > NODEMAP_LPROC_FLAG_LEN) - return -EINVAL; - - if (copy_from_user(active_string, buffer, count)) - return -EFAULT; - - active_string[count] = '\0'; - active = simple_strtoul(active_string, NULL, 10); - nodemap_active = active; - - return rc; -} -LPROC_SEQ_FOPS(nodemap_active); - -static int nodemap_id_seq_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - - return seq_printf(m, "%u\n", nodemap->nm_id); -} -LPROC_SEQ_FOPS_RO(nodemap_id); - -static int nodemap_squash_uid_seq_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - - return seq_printf(m, "%u\n", nodemap->nm_squash_uid); -} - -static int nodemap_squash_gid_seq_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - - return seq_printf(m, "%u\n", nodemap->nm_squash_gid); -} - -static int nodemap_trusted_seq_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - - return seq_printf(m, "%d\n", (int)nodemap->nmf_trust_client_ids); -} - -static int nodemap_admin_seq_show(struct seq_file *m, void *data) -{ - struct lu_nodemap *nodemap = m->private; - - return seq_printf(m, "%d\n", (int)nodemap->nmf_allow_root_access); -} - -#ifdef NODEMAP_PROC_DEBUG -static int nodemap_proc_read_flag(const char __user *buffer, - unsigned long count, unsigned int *flag_p) -{ - char scratch[NODEMAP_LPROC_FLAG_LEN + 1]; - - if (count == 0) - return 0; - - if (count > NODEMAP_LPROC_FLAG_LEN) - return -EINVAL; - - if (copy_from_user(scratch, buffer, count)) - return -EFAULT; - - scratch[count] = '\0'; - *flag_p = simple_strtoul(scratch, NULL, 10); - - return 0; -} - -static ssize_t -nodemap_squash_uid_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - char squash[NODEMAP_LPROC_ID_LEN + 1]; - struct seq_file *m = file->private_data; - struct lu_nodemap *nodemap = m->private; - uid_t squash_uid; - int rc = count; - - if (count == 0) - return 0; - - if (count > NODEMAP_LPROC_FLAG_LEN) - return -EINVAL; - - if (copy_from_user(squash, buffer, count)) - return -EFAULT; - - squash[count] = '\0'; - squash_uid = simple_strtoul(squash, NULL, 10); - nodemap->nm_squash_uid = squash_uid; - - return rc; -} - -static ssize_t -nodemap_squash_gid_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - char squash[NODEMAP_LPROC_ID_LEN + 1]; - struct seq_file *m = file->private_data; - struct lu_nodemap *nodemap = m->private; - gid_t squash_gid; - int rc = count; - - if (count == 0) - return 0; - - if (count > NODEMAP_LPROC_FLAG_LEN) - return -EINVAL; - - if (copy_from_user(squash, buffer, count)) - return -EFAULT; - - squash[count] = '\0'; - squash_gid = simple_strtoul(squash, NULL, 10); - nodemap->nm_squash_gid = squash_gid; - - return rc; -} - -static ssize_t -nodemap_trusted_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct seq_file *m = file->private_data; - struct lu_nodemap *nodemap = m->private; - int flags; - int rc; - - rc = nodemap_proc_read_flag(buffer, count, &flags); - if (rc == 0) - nodemap->nmf_trust_client_ids = !!flags; - - return rc; -} - -static ssize_t -nodemap_admin_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - struct seq_file *m = file->private_data; - struct lu_nodemap *nodemap = m->private; - int flags; - int rc; - - rc = nodemap_proc_read_flag(buffer, count, &flags); - if (rc == 0) - nodemap->nmf_allow_root_access = !!flags; - - return rc; -} - -static ssize_t -lprocfs_add_nodemap_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - char buf[LUSTRE_NODEMAP_NAME_LENGTH + 1]; - char *cpybuf = NULL; - char *name; - char *pos; - int rc = count; - - if (count == 0) - return 0; - - if (count > LUSTRE_NODEMAP_NAME_LENGTH) - return -EINVAL; - - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - - buf[count] = '\0'; - pos = strchr(buf, '\n'); - if (pos != NULL) - *pos = '\0'; - - cpybuf = buf; - name = strsep(&cpybuf, " "); - if (name == NULL) - return -EINVAL; - - rc = nodemap_add(name); - if (rc == 0) - rc = count; - - return rc; -} -LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap); - -static ssize_t -lprocfs_del_nodemap_seq_write(struct file *file, const char __user *buffer, - size_t count, loff_t *off) -{ - char buf[LUSTRE_NODEMAP_NAME_LENGTH + 1]; - char *cpybuf = NULL; - char *name; - char *pos; - int rc = count; - - if (count == 0) - return 0; - - if (count > LUSTRE_NODEMAP_NAME_LENGTH) - return -EINVAL; - - if (copy_from_user(buf, buffer, count)) - return -EFAULT; - - buf[count] = '\0'; - pos = strchr(buf, '\n'); - if (pos != NULL) - *pos = '\0'; - - cpybuf = buf; - name = strsep(&cpybuf, " "); - if (name == NULL) - return -EINVAL; - - rc = nodemap_del(name); - if (rc == 0) - rc = count; - - return rc; - -} -LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap); - -#endif /* NODEMAP_PROC_DEBUG */ - -static struct lprocfs_seq_vars lprocfs_nodemap_module_vars[] = { - { - .name = "active", - .fops = &nodemap_active_fops, - }, -#ifdef NODEMAP_PROC_DEBUG - { - .name = "add_nodemap", - .fops = &nodemap_add_nodemap_fops, - }, - { - .name = "remove_nodemap", - .fops = &nodemap_del_nodemap_fops, - }, -#endif /* NODEMAP_PROC_DEBUG */ - { - NULL - } -}; - -#ifdef NODEMAP_PROC_DEBUG -LPROC_SEQ_FOPS(nodemap_trusted); -LPROC_SEQ_FOPS(nodemap_admin); -LPROC_SEQ_FOPS(nodemap_squash_uid); -LPROC_SEQ_FOPS(nodemap_squash_gid); -#else -LPROC_SEQ_FOPS_RO(nodemap_trusted); -LPROC_SEQ_FOPS_RO(nodemap_admin); -LPROC_SEQ_FOPS_RO(nodemap_squash_uid); -LPROC_SEQ_FOPS_RO(nodemap_squash_gid); -#endif - -const struct file_operations nodemap_ranges_fops = { - .open = nodemap_ranges_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; - -const struct file_operations nodemap_idmap_fops = { - .open = nodemap_idmap_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release -}; - -static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = { - { - .name = "id", - .fops = &nodemap_id_fops, - }, - { - .name = "trusted_nodemap", - .fops = &nodemap_trusted_fops, - }, - { - .name = "admin_nodemap", - .fops = &nodemap_admin_fops, - }, - { - .name = "squash_uid", - .fops = &nodemap_squash_uid_fops, - }, - { - .name = "squash_gid", - .fops = &nodemap_squash_gid_fops, - }, - { - .name = "ranges", - .fops = &nodemap_ranges_fops, - }, - { - .name = "idmap", - .fops = &nodemap_idmap_fops, - }, - { - NULL - } -}; - -static struct lprocfs_seq_vars lprocfs_default_nodemap_vars[] = { - { - .name = "id", - .fops = &nodemap_id_fops, - }, - { - .name = "trusted_nodemap", - .fops = &nodemap_trusted_fops, - }, - { - .name = "admin_nodemap", - .fops = &nodemap_admin_fops, - }, - { - .name = "squash_uid", - .fops = &nodemap_squash_uid_fops, - }, - { - .name = "squash_gid", - .fops = &nodemap_squash_gid_fops, - }, - { - NULL - } -}; - -int nodemap_procfs_init(void) -{ - int rc = 0; - - proc_lustre_nodemap_root = lprocfs_seq_register(LUSTRE_NODEMAP_NAME, - proc_lustre_root, - lprocfs_nodemap_module_vars, - NULL); - - if (IS_ERR(proc_lustre_nodemap_root)) { - rc = PTR_ERR(proc_lustre_nodemap_root); - CERROR("cannot create 'nodemap' directory: rc = %d\n", - rc); - proc_lustre_nodemap_root = NULL; - } - - return rc; -} - -/** - * Register the proc directory for a nodemap - * - * \param name name of nodemap - * \param is_default: 1 if default nodemap - * \retval 0 success - */ -int lprocfs_nodemap_register(const char *name, - bool is_default, - struct lu_nodemap *nodemap) -{ - struct proc_dir_entry *nodemap_proc_entry; - int rc = 0; - - if (is_default) - nodemap_proc_entry = - lprocfs_seq_register(name, - proc_lustre_nodemap_root, - lprocfs_default_nodemap_vars, - nodemap); - else - nodemap_proc_entry = lprocfs_seq_register(name, - proc_lustre_nodemap_root, - lprocfs_nodemap_vars, - nodemap); - - if (IS_ERR(nodemap_proc_entry)) { - rc = PTR_ERR(nodemap_proc_entry); - CERROR("cannot create 'nodemap/%s': rc = %d\n", name, rc); - nodemap_proc_entry = NULL; - } - - nodemap->nm_proc_entry = nodemap_proc_entry; - - return rc; -} diff --git a/lustre/obdclass/lprocfs_status_server.c b/lustre/obdclass/lprocfs_status_server.c index a4541cf..f0d0916 100644 --- a/lustre/obdclass/lprocfs_status_server.c +++ b/lustre/obdclass/lprocfs_status_server.c @@ -38,6 +38,7 @@ #include #include #include +#include #if defined(LPROCFS) @@ -172,6 +173,16 @@ int lprocfs_exp_print_uuid_seq(cfs_hash_t *hs, cfs_hash_bd_t *bd, return 0; } +int lprocfs_exp_nodemap_seq_show(struct seq_file *m, void *data) +{ + struct obd_export *exp = m->private; + if (exp->exp_target_data.ted_nodemap) + return seq_printf(m, "%s\n", + exp->exp_target_data.ted_nodemap->nm_name); + return seq_printf(m, "null\n"); +} +LPROC_SEQ_FOPS_RO(lprocfs_exp_nodemap); + int lprocfs_exp_uuid_seq_show(struct seq_file *m, void *data) { struct nid_stat *stats = m->private; @@ -342,19 +353,27 @@ int lprocfs_exp_setup(struct obd_export *exp, lnet_nid_t *nid, int *newnid) GOTO(destroy_new_ns, rc); } + entry = lprocfs_add_simple(new_stat->nid_proc, "nodemap", + exp, &lprocfs_exp_nodemap_fops); + if (IS_ERR(entry)) { + rc = PTR_ERR(entry); + CWARN("Error adding the nodemap file: rc = %d\n", rc); + GOTO(destroy_new_ns, rc); + } + entry = lprocfs_add_simple(new_stat->nid_proc, "uuid", new_stat, &lprocfs_exp_uuid_fops); if (IS_ERR(entry)) { - CWARN("Error adding the NID stats file\n"); rc = PTR_ERR(entry); + CWARN("Error adding the NID stats file: rc = %d\n", rc); GOTO(destroy_new_ns, rc); } entry = lprocfs_add_simple(new_stat->nid_proc, "hash", new_stat, &lprocfs_exp_hash_fops); if (IS_ERR(entry)) { - CWARN("Error adding the hash file\n"); rc = PTR_ERR(entry); + CWARN("Error adding the hash file: rc = %d\n", rc); GOTO(destroy_new_ns, rc); } diff --git a/lustre/ofd/ofd_dev.c b/lustre/ofd/ofd_dev.c index 928bf29..698fd7f 100644 --- a/lustre/ofd/ofd_dev.c +++ b/lustre/ofd/ofd_dev.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "ofd_internal.h" @@ -2100,6 +2101,9 @@ out: static int ofd_quotactl(struct tgt_session_info *tsi) { struct obd_quotactl *oqctl, *repoqc; + struct lu_nodemap *nodemap = + tsi->tsi_exp->exp_target_data.ted_nodemap; + int id; int rc; ENTRY; @@ -2118,11 +2122,28 @@ static int ofd_quotactl(struct tgt_session_info *tsi) RETURN(0); *repoqc = *oqctl; + + id = repoqc->qc_id; + if (oqctl->qc_type == USRQUOTA) + id = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, + repoqc->qc_id); + else if (oqctl->qc_type == GRPQUOTA) + id = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, + repoqc->qc_id); + + if (repoqc->qc_id != id) + swap(repoqc->qc_id, id); + rc = lquotactl_slv(tsi->tsi_env, tsi->tsi_tgt->lut_bottom, repoqc); ofd_counter_incr(tsi->tsi_exp, LPROC_OFD_STATS_QUOTACTL, tsi->tsi_jobid, 1); + if (repoqc->qc_id != id) + swap(repoqc->qc_id, id); + RETURN(rc); } diff --git a/lustre/ofd/ofd_obd.c b/lustre/ofd/ofd_obd.c index a0f0d1e..231c177 100644 --- a/lustre/ofd/ofd_obd.c +++ b/lustre/ofd/ofd_obd.c @@ -49,6 +49,7 @@ #include #include #include +#include /** * Initialize OFD per-export statistics. @@ -64,7 +65,8 @@ * \retval negative value on error */ static int ofd_export_stats_init(struct ofd_device *ofd, - struct obd_export *exp, void *client_nid) + struct obd_export *exp, + lnet_nid_t *client_nid) { struct obd_device *obd = ofd_obd(ofd); struct nid_stat *stats; @@ -296,7 +298,8 @@ static int ofd_parse_connect_data(const struct lu_env *env, */ static int ofd_obd_reconnect(const struct lu_env *env, struct obd_export *exp, struct obd_device *obd, struct obd_uuid *cluuid, - struct obd_connect_data *data, void *localdata) + struct obd_connect_data *data, + void *client_nid) { struct ofd_device *ofd; int rc; @@ -310,7 +313,9 @@ static int ofd_obd_reconnect(const struct lu_env *env, struct obd_export *exp, rc = ofd_parse_connect_data(env, exp, data, false); if (rc == 0) - ofd_export_stats_init(ofd, exp, localdata); + ofd_export_stats_init(ofd, exp, client_nid); + + nodemap_add_member(*(lnet_nid_t *)client_nid, exp); RETURN(rc); } @@ -340,6 +345,7 @@ static int ofd_obd_connect(const struct lu_env *env, struct obd_export **_exp, struct ofd_device *ofd; struct lustre_handle conn = { 0 }; int rc; + lnet_nid_t *client_nid; ENTRY; if (_exp == NULL || obd == NULL || cluuid == NULL) @@ -358,6 +364,11 @@ static int ofd_obd_connect(const struct lu_env *env, struct obd_export **_exp, if (rc) GOTO(out, rc); + if (localdata != NULL) { + client_nid = localdata; + nodemap_add_member(*client_nid, exp); + } + if (obd->obd_replayable) { struct tg_export_data *ted = &exp->exp_target_data; @@ -374,6 +385,7 @@ static int ofd_obd_connect(const struct lu_env *env, struct obd_export **_exp, out: if (rc != 0) { + nodemap_del_member(exp); class_disconnect(exp); *_exp = NULL; } else { @@ -407,6 +419,7 @@ int ofd_obd_disconnect(struct obd_export *exp) if (!(exp->exp_flags & OBD_OPT_FORCE)) ofd_grant_sanity_check(ofd_obd(ofd), __FUNCTION__); + nodemap_del_member(exp); rc = server_disconnect_export(exp); ofd_grant_discard(exp); diff --git a/lustre/ptlrpc/Makefile.in b/lustre/ptlrpc/Makefile.in index d591555..2a54e95 100644 --- a/lustre/ptlrpc/Makefile.in +++ b/lustre/ptlrpc/Makefile.in @@ -21,8 +21,11 @@ target_objs := $(TARGET)tgt_main.o $(TARGET)tgt_lastrcvd.o target_objs += $(TARGET)tgt_handler.o $(TARGET)out_handler.o target_objs += $(TARGET)out_lib.o +nodemap_objs = nodemap_handler.o nodemap_lproc.o nodemap_range.o +nodemap_objs += nodemap_idmap.o nodemap_rbtree.o nodemap_member.o + ptlrpc-objs := $(ldlm_objs) $(ptlrpc_objs) -@SERVER_TRUE@ptlrpc-objs += $(target_objs) +@SERVER_TRUE@ptlrpc-objs += $(target_objs) $(nodemap_objs) @GSS_TRUE@subdir-m += gss @@ -44,7 +47,7 @@ out_%.c: @LUSTRE@/target/out_%.c ln -sf $< $@ EXTRA_DIST := $(ptlrpc_objs:.o=.c) ptlrpc_internal.h -EXTRA_DIST += $(TARGET)tgt_internal.h +EXTRA_DIST += $(TARGET)tgt_internal.h nodemap_internal.h @SERVER_FALSE@EXTRA_DIST += $(target_objs:.o=.c) EXTRA_PRE_CFLAGS := -I@LUSTRE@/ldlm -I@LUSTRE@/target diff --git a/lustre/ptlrpc/autoMakefile.am b/lustre/ptlrpc/autoMakefile.am index f2a5d7d..52d652d 100644 --- a/lustre/ptlrpc/autoMakefile.am +++ b/lustre/ptlrpc/autoMakefile.am @@ -50,12 +50,15 @@ LDLM_COMM_SOURCES= $(top_srcdir)/lustre/ldlm/l_lock.c \ $(top_srcdir)/lustre/ldlm/ldlm_flock.c \ $(top_srcdir)/lustre/ldlm/ldlm_pool.c +NODEMAP_SOURCES = nodemap_handler.c nodemap_idmap.c nodemap_lproc.c \ + nodemap_member.c nodemap_range.c nodemap_rbtree.c + COMMON_SOURCES = client.c recover.c connection.c niobuf.c pack_generic.c \ events.c ptlrpc_module.c service.c pinger.c llog_net.c sec_ctx.c \ llog_client.c llog_server.c import.c ptlrpcd.c pers.c wiretest.c \ ptlrpc_internal.h layout.c sec.c sec_bulk.c sec_gc.c sec_config.c \ sec_lproc.c sec_null.c sec_plain.c lproc_ptlrpc.c nrs.c nrs_fifo.c \ - errno.c $(LDLM_COMM_SOURCES) + errno.c $(LDLM_COMM_SOURCES) $(NODEMAP_SOURCES) if LIBLUSTRE diff --git a/lustre/nodemap/nodemap_handler.c b/lustre/ptlrpc/nodemap_handler.c similarity index 72% rename from lustre/nodemap/nodemap_handler.c rename to lustre/ptlrpc/nodemap_handler.c index 837d808..4648514 100644 --- a/lustre/nodemap/nodemap_handler.c +++ b/lustre/ptlrpc/nodemap_handler.c @@ -24,8 +24,12 @@ * Author: Joshua Walgenbach */ #include +#include #include #include +#include +#include +#include #include "nodemap_internal.h" #define HASH_NODEMAP_BKT_BITS 3 @@ -51,6 +55,11 @@ bool nodemap_active; static struct lu_nodemap *default_nodemap; /** + * Lock required to access the range tree. + */ +rwlock_t nm_range_tree_lock; + +/** * Hash keyed on nodemap name containing all * nodemaps */ @@ -64,16 +73,24 @@ static cfs_hash_t *nodemap_hash; static void nodemap_destroy(struct lu_nodemap *nodemap) { struct lu_nid_range *range; - struct lu_nid_range *temp; + struct lu_nid_range *range_temp; - list_for_each_entry_safe(range, temp, &nodemap->nm_ranges, + write_lock(&nm_range_tree_lock); + list_for_each_entry_safe(range, range_temp, &nodemap->nm_ranges, rn_list) { range_delete(range); } + write_unlock(&nm_range_tree_lock); + write_lock(&nodemap->nm_idmap_lock); idmap_delete_tree(nodemap); + write_unlock(&nodemap->nm_idmap_lock); + nm_member_reclassify_nodemap(nodemap); + if (!cfs_hash_is_empty(nodemap->nm_member_hash)) + CWARN("nodemap_destroy failed to reclassify all members\n"); + + nm_member_delete_hash(nodemap); - lprocfs_remove(&nodemap->nm_proc_entry); OBD_FREE_PTR(nodemap); } @@ -82,7 +99,6 @@ static void nodemap_destroy(struct lu_nodemap *nodemap) */ static void nodemap_getref(struct lu_nodemap *nodemap) { - CDEBUG(D_INFO, "nodemap %p\n", nodemap); atomic_inc(&nodemap->nm_refcount); } @@ -98,10 +114,7 @@ void nodemap_putref(struct lu_nodemap *nodemap) static __u32 nodemap_hashfn(cfs_hash_t *hash_body, const void *key, unsigned mask) { - const struct lu_nodemap *nodemap = key; - - return cfs_hash_djb2_hash(nodemap->nm_name, strlen(nodemap->nm_name), - mask); + return cfs_hash_djb2_hash(key, strlen(key), mask); } static void *nodemap_hs_key(struct hlist_node *hnode) @@ -225,6 +238,7 @@ static bool nodemap_name_is_valid(const char *name) if (!isalnum(*name) && *name != '_') return false; } + return true; } @@ -322,33 +336,79 @@ EXPORT_SYMBOL(nodemap_parse_range); * \param idmap array[2] of __u32 * * \retval 0 on success + * \retval -EINVAL if idmap cannot be parsed */ -int nodemap_parse_idmap(const char *idmap_str, __u32 idmap[2]) +int nodemap_parse_idmap(char *idmap_str, __u32 idmap[2]) { - char *end; + char *sep; + long unsigned int idmap_buf; + int rc; if (idmap_str == NULL) return -EINVAL; - idmap[0] = simple_strtoul(idmap_str, &end, 10); - if (end == idmap_str || *end != ':') + sep = strchr(idmap_str, ':'); + if (sep == NULL) return -EINVAL; + *sep = '\0'; + sep++; - idmap_str = end + 1; - idmap[1] = simple_strtoul(idmap_str, &end, 10); - if (end == idmap_str) + rc = kstrtoul(idmap_str, 10, &idmap_buf); + if (rc != 0) + return -EINVAL; + idmap[0] = idmap_buf; + + rc = kstrtoul(sep, 10, &idmap_buf); + if (rc != 0) return -EINVAL; + idmap[1] = idmap_buf; return 0; } EXPORT_SYMBOL(nodemap_parse_idmap); /** + * add a member to a nodemap + * + * \param nid nid to add to the members + * \param exp obd_export structure for the connection + * that is being added + * \retval -EINVAL export is NULL + * \retval -EEXIST export is already member of a nodemap + */ +int nodemap_add_member(lnet_nid_t nid, struct obd_export *exp) +{ + struct lu_nodemap *nodemap; + int rc; + + read_lock(&nm_range_tree_lock); + nodemap = nodemap_classify_nid(nid); + rc = nm_member_add(nodemap, exp); + read_unlock(&nm_range_tree_lock); + return rc; +} +EXPORT_SYMBOL(nodemap_add_member); + +/** + * delete a member from a nodemap + * + * \param exp export to remove from a nodemap + */ +void nodemap_del_member(struct obd_export *exp) +{ + struct lu_nodemap *nodemap = exp->exp_target_data.ted_nodemap; + + if (nodemap != NULL) + nm_member_del(nodemap, exp); +} +EXPORT_SYMBOL(nodemap_del_member); + +/** * add an idmap to the proper nodemap trees * * \param name name of nodemap * \param id_type NODEMAP_UID or NODEMAP_GID - * \param map array[2] __u32 containing the mapA values + * \param map array[2] __u32 containing the map values * map[0] is client id * map[1] is the filesystem id * @@ -369,7 +429,10 @@ int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type, if (idmap == NULL) GOTO(out_putref, rc = -ENOMEM); + write_lock(&nodemap->nm_idmap_lock); idmap_insert(id_type, idmap, nodemap); + write_unlock(&nodemap->nm_idmap_lock); + nm_member_revoke_locks(nodemap); out_putref: nodemap_putref(nodemap); @@ -400,12 +463,17 @@ int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type, if (nodemap == NULL || is_default_nodemap(nodemap)) GOTO(out, rc = -EINVAL); + write_lock(&nodemap->nm_idmap_lock); idmap = idmap_search(nodemap, NODEMAP_CLIENT_TO_FS, id_type, map[0]); - if (idmap == NULL) + if (idmap == NULL) { + write_unlock(&nodemap->nm_idmap_lock); GOTO(out_putref, rc = -EINVAL); + } idmap_delete(id_type, idmap, nodemap); + write_unlock(&nodemap->nm_idmap_lock); + nm_member_revoke_locks(nodemap); out_putref: nodemap_putref(nodemap); @@ -427,14 +495,14 @@ EXPORT_SYMBOL(nodemap_del_idmap); * * if the nodemap_active is false, just return the passed id without mapping * - * if the id to be looked up in 0, check that root access is allowed and if it + * if the id to be looked up is 0, check that root access is allowed and if it * is, return 0. Otherwise, return the squash uid or gid. * * if the nodemap is configured to trusted the ids from the client system, just * return the passwd id without mapping. * * if by this point, we haven't returned and the nodemap in question is the - * default nodemap, return the dquash uid or gid. + * default nodemap, return the squash uid or gid. * * after these checks, search the proper tree for the mapping, and if found * return the mapped value, otherwise return the squash uid or gid. @@ -444,10 +512,14 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap, enum nodemap_tree_type tree_type, __u32 id) { struct lu_idmap *idmap = NULL; + __u32 found_id; if (!nodemap_active) goto out; + if (unlikely(nodemap == NULL)) + goto out; + if (id == 0) { if (nodemap->nmf_allow_root_access) goto out; @@ -461,14 +533,19 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap, if (is_default_nodemap(nodemap)) goto squash; + read_lock(&nodemap->nm_idmap_lock); idmap = idmap_search(nodemap, tree_type, id_type, id); - if (idmap == NULL) + if (idmap == NULL) { + read_unlock(&nodemap->nm_idmap_lock); goto squash; + } if (tree_type == NODEMAP_FS_TO_CLIENT) - return idmap->id_client; - - return idmap->id_fs; + found_id = idmap->id_client; + else + found_id = idmap->id_fs; + read_unlock(&nodemap->nm_idmap_lock); + return found_id; squash: if (id_type == NODEMAP_UID) @@ -480,6 +557,70 @@ out: } EXPORT_SYMBOL(nodemap_map_id); +/** + * Map posix ACL entries according to the nodemap membership. Removes any + * squashed ACLs. + * + * \param lu_nodemap nodemap + * \param buf buffer containing xattr encoded ACLs + * \param size size of ACLs in bytes + * \param tree_type direction of mapping + * \retval size new size of ACLs in bytes + * \retval -EINVAL bad \a size param, see posix_acl_xattr_count() + */ +ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size, + enum nodemap_tree_type tree_type) +{ + posix_acl_xattr_header *header = buf; + posix_acl_xattr_entry *entry = &header->a_entries[0]; + posix_acl_xattr_entry *new_entry = entry; + posix_acl_xattr_entry *end; + int count; + + if (!nodemap_active) + return size; + + if (unlikely(nodemap == NULL)) + return size; + + count = posix_acl_xattr_count(size); + if (count < 0) + return -EINVAL; + if (count == 0) + return 0; + + for (end = entry + count; entry != end; entry++) { + __u16 tag = le16_to_cpu(entry->e_tag); + __u32 id = le32_to_cpu(entry->e_id); + + switch (tag) { + case ACL_USER: + id = nodemap_map_id(nodemap, NODEMAP_UID, + tree_type, id); + if (id == nodemap->nm_squash_uid) + continue; + entry->e_id = cpu_to_le32(id); + break; + case ACL_GROUP: + id = nodemap_map_id(nodemap, NODEMAP_GID, + tree_type, id); + if (id == nodemap->nm_squash_gid) + continue; + entry->e_id = cpu_to_le32(id); + break; + } + + /* if we skip an ACL, copy the following ones over it */ + if (new_entry != entry) + *new_entry = *entry; + + new_entry++; + } + + return (void *)new_entry - (void *)header; +} +EXPORT_SYMBOL(nodemap_map_acl); + /* * add nid range to nodemap * \param name nodemap name @@ -503,16 +644,23 @@ int nodemap_add_range(const char *name, const lnet_nid_t nid[2]) if (range == NULL) GOTO(out_putref, rc = -ENOMEM); + write_lock(&nm_range_tree_lock); rc = range_insert(range); if (rc != 0) { CERROR("cannot insert nodemap range into '%s': rc = %d\n", nodemap->nm_name, rc); + write_unlock(&nm_range_tree_lock); list_del(&range->rn_list); range_destroy(range); GOTO(out_putref, rc = -ENOMEM); } list_add(&range->rn_list, &nodemap->nm_ranges); + write_unlock(&nm_range_tree_lock); + + nm_member_reclassify_nodemap(default_nodemap); + nm_member_revoke_locks(default_nodemap); + nm_member_revoke_locks(nodemap); out_putref: nodemap_putref(nodemap); @@ -540,11 +688,18 @@ int nodemap_del_range(const char *name, const lnet_nid_t nid[2]) if (nodemap == NULL || is_default_nodemap(nodemap)) GOTO(out, rc = -EINVAL); + write_lock(&nm_range_tree_lock); range = range_find(nid[0], nid[1]); - if (range == NULL) + if (range == NULL) { + write_unlock(&nm_range_tree_lock); GOTO(out_putref, rc = -EINVAL); + } range_delete(range); + write_unlock(&nm_range_tree_lock); + nm_member_reclassify_nodemap(nodemap); + nm_member_revoke_locks(default_nodemap); + nm_member_revoke_locks(nodemap); out_putref: nodemap_putref(nodemap); @@ -571,19 +726,13 @@ EXPORT_SYMBOL(nodemap_del_range); */ static int nodemap_create(const char *name, bool is_default) { - struct lu_nodemap *nodemap = NULL; - int rc = 0; + struct lu_nodemap *nodemap = NULL; + int rc = 0; - rc = nodemap_lookup(name, &nodemap); - if (rc == -EINVAL) - goto out; + if (!nodemap_name_is_valid(name)) + GOTO(out, rc = -EINVAL); - if (rc != -ENOENT) { - nodemap_putref(nodemap); - GOTO(out, rc = -EEXIST); - } OBD_ALLOC_PTR(nodemap); - if (nodemap == NULL) { CERROR("cannot allocate memory (%zu bytes)" "for nodemap '%s'\n", sizeof(*nodemap), @@ -591,9 +740,28 @@ static int nodemap_create(const char *name, bool is_default) GOTO(out, rc = -ENOMEM); } + /* + * take an extra reference to prevent nodemap from being destroyed + * while its being created. + */ + atomic_set(&nodemap->nm_refcount, 2); snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name); + rc = cfs_hash_add_unique(nodemap_hash, name, &nodemap->nm_hash); + if (rc != 0) { + OBD_FREE_PTR(nodemap); + GOTO(out, rc = -EEXIST); + } + + + rc = nm_member_init_hash(nodemap); + if (rc != 0) { + OBD_FREE_PTR(nodemap); + goto out; + } - INIT_LIST_HEAD(&(nodemap->nm_ranges)); + INIT_LIST_HEAD(&nodemap->nm_ranges); + + rwlock_init(&nodemap->nm_idmap_lock); nodemap->nm_fs_to_client_uidmap = RB_ROOT; nodemap->nm_client_to_fs_uidmap = RB_ROOT; nodemap->nm_fs_to_client_gidmap = RB_ROOT; @@ -626,11 +794,10 @@ static int nodemap_create(const char *name, bool is_default) lprocfs_nodemap_register(name, is_default, nodemap); } - atomic_set(&nodemap->nm_refcount, 1); - rc = cfs_hash_add_unique(nodemap_hash, name, &nodemap->nm_hash); - - if (rc == 0) + if (rc == 0) { + nodemap_putref(nodemap); goto out; + } CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc); nodemap_destroy(nodemap); @@ -657,6 +824,7 @@ int nodemap_set_allow_root(const char *name, bool allow_root) GOTO(out, rc = -ENOENT); nodemap->nmf_allow_root_access = allow_root; + nm_member_revoke_locks(nodemap); nodemap_putref(nodemap); out: return rc; @@ -682,6 +850,7 @@ int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids) GOTO(out, rc = -ENOENT); nodemap->nmf_trust_client_ids = trust_client_ids; + nm_member_revoke_locks(nodemap); nodemap_putref(nodemap); out: return rc; @@ -710,6 +879,7 @@ int nodemap_set_squash_uid(const char *name, uid_t uid) GOTO(out, rc = -ENOENT); nodemap->nm_squash_uid = uid; + nm_member_revoke_locks(nodemap); nodemap_putref(nodemap); out: return rc; @@ -717,7 +887,7 @@ out: EXPORT_SYMBOL(nodemap_set_squash_uid); /** - * update the squash_gid for a nodemap + * Update the squash_gid for a nodemap. * * \param name nodemap name * \param gid_string string containing new squash_gid value @@ -738,6 +908,7 @@ int nodemap_set_squash_gid(const char *name, gid_t gid) GOTO(out, rc = -ENOENT); nodemap->nm_squash_gid = gid; + nm_member_revoke_locks(nodemap); nodemap_putref(nodemap); out: return rc; @@ -745,6 +916,18 @@ out: EXPORT_SYMBOL(nodemap_set_squash_gid); /** + * Returns true if this nodemap has root user access. Always returns true if + * nodemaps are not active. + * + * \param nodemap nodemap to check access for + */ +bool nodemap_can_setquota(const struct lu_nodemap *nodemap) +{ + return !nodemap_active || nodemap->nmf_allow_root_access; +} +EXPORT_SYMBOL(nodemap_can_setquota); + +/** * Add a nodemap * * \param name name of nodemap @@ -753,9 +936,9 @@ EXPORT_SYMBOL(nodemap_set_squash_gid); * \retval -EEXIST nodemap already exists * \retval -ENOMEM cannot allocate memory for nodemap */ -int nodemap_add(const char *name) +int nodemap_add(const char *nodemap_name) { - return nodemap_create(name, 0); + return nodemap_create(nodemap_name, 0); } EXPORT_SYMBOL(nodemap_add); @@ -767,18 +950,23 @@ EXPORT_SYMBOL(nodemap_add); * \retval -EINVAL invalid input * \retval -ENOENT no existing nodemap */ -int nodemap_del(const char *name) +int nodemap_del(const char *nodemap_name) { struct lu_nodemap *nodemap; int rc = 0; - if (strcmp(name, DEFAULT_NODEMAP) == 0) + if (strcmp(nodemap_name, DEFAULT_NODEMAP) == 0) GOTO(out, rc = -EINVAL); - nodemap = cfs_hash_del_key(nodemap_hash, name); + nodemap = cfs_hash_del_key(nodemap_hash, nodemap_name); if (nodemap == NULL) GOTO(out, rc = -ENOENT); + /* + * remove procfs here in case nodemap_create called with same name + * before nodemap_destory is run. + */ + lprocfs_remove(&nodemap->nm_proc_entry); nodemap_putref(nodemap); out: return rc; @@ -793,13 +981,14 @@ EXPORT_SYMBOL(nodemap_del); void nodemap_activate(const bool value) { nodemap_active = value; + nm_member_revoke_all(); } EXPORT_SYMBOL(nodemap_activate); /** * Cleanup nodemap module on exit */ -static void nodemap_mod_exit(void) +void nodemap_mod_exit(void) { nodemap_cleanup_all(); lprocfs_remove(&proc_lustre_nodemap_root); @@ -808,7 +997,7 @@ static void nodemap_mod_exit(void) /** * Initialize the nodemap module */ -static int __init nodemap_mod_init(void) +int nodemap_mod_init(void) { int rc = 0; @@ -816,6 +1005,7 @@ static int __init nodemap_mod_init(void) if (rc != 0) goto cleanup; + rwlock_init(&nm_range_tree_lock); nodemap_procfs_init(); rc = nodemap_create(DEFAULT_NODEMAP, 1); @@ -826,9 +1016,21 @@ cleanup: return rc; } -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Lustre Client Nodemap Management Module"); -MODULE_AUTHOR("Joshua Walgenbach "); +static int nm_member_revoke_all_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd, + struct hlist_node *hnode, void *data) +{ + struct lu_nodemap *nodemap; + + nodemap = hlist_entry(hnode, struct lu_nodemap, nm_hash); + nm_member_revoke_locks(nodemap); + return 0; +} + +/** + * Revoke locks for all nodemaps. + */ +void nm_member_revoke_all() +{ + cfs_hash_for_each_safe(nodemap_hash, nm_member_revoke_all_cb, NULL); +} -module_init(nodemap_mod_init); -module_exit(nodemap_mod_exit); diff --git a/lustre/nodemap/nodemap_idmap.c b/lustre/ptlrpc/nodemap_idmap.c similarity index 96% rename from lustre/nodemap/nodemap_idmap.c rename to lustre/ptlrpc/nodemap_idmap.c index 8ff3063..91dec43 100644 --- a/lustre/nodemap/nodemap_idmap.c +++ b/lustre/ptlrpc/nodemap_idmap.c @@ -29,7 +29,7 @@ #include "nodemap_internal.h" /** - * allocate the lu_idmap structure + * Allocate the lu_idmap structure * * \param client_id client uid or gid * \param fs_id filesystem uid or gid @@ -63,7 +63,7 @@ static void idmap_destroy(struct lu_idmap *idmap) } /** - * insert idmap into the proper trees + * Insert idmap into the proper trees * * \param node_type 0 for UID * 1 for GID @@ -102,7 +102,7 @@ void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap, bck_node = &bck_root->rb_node; /* find fwd and bck idmap nodes before insertion or - * replacing to precent split brain idmaps + * replacing to prevent split brain idmaps */ while (*fwd_node) { fwd_parent = *fwd_node; @@ -117,7 +117,6 @@ void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap, replace = true; break; } - } if (!replace) { @@ -134,7 +133,6 @@ void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap, replace = true; break; } - } } @@ -156,7 +154,7 @@ void idmap_insert(enum nodemap_id_type id_type, struct lu_idmap *idmap, } /** - * delete idmap from the correct nodemap tree + * Delete idmap from the correct nodemap tree * * \param node_type 0 for UID * 1 for GID @@ -184,7 +182,7 @@ void idmap_delete(enum nodemap_id_type id_type, struct lu_idmap *idmap, } /** - * search for an existing id in the nodemap trees + * Search for an existing id in the nodemap trees. * * \param nodemap nodemap trees to search * \param tree_type 0 for filesystem to client maps diff --git a/lustre/nodemap/nodemap_internal.h b/lustre/ptlrpc/nodemap_internal.h similarity index 88% rename from lustre/nodemap/nodemap_internal.h rename to lustre/ptlrpc/nodemap_internal.h index 7751177..7009cf9 100644 --- a/lustre/nodemap/nodemap_internal.h +++ b/lustre/ptlrpc/nodemap_internal.h @@ -43,6 +43,8 @@ struct lprocfs_static_vars; extern struct proc_dir_entry *proc_lustre_nodemap_root; /* flag if nodemap is active */ extern bool nodemap_active; +/* lock for range interval tree, used in nodemap_lproc.c */ +extern rwlock_t nm_range_tree_lock; struct lu_nid_range { /* unique id set my mgs */ @@ -90,6 +92,13 @@ struct lu_idmap *idmap_search(struct lu_nodemap *nodemap, enum nodemap_id_type id_type, __u32 id); int nodemap_cleanup_nodemaps(void); +int nm_member_init_hash(struct lu_nodemap *nodemap); +int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp); +void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp); +void nm_member_delete_hash(struct lu_nodemap *nodemap); +void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap); +void nm_member_revoke_locks(struct lu_nodemap *nodemap); +void nm_member_revoke_all(void); struct rb_node *nm_rb_next_postorder(const struct rb_node *node); struct rb_node *nm_rb_first_postorder(const struct rb_root *root); diff --git a/lustre/ptlrpc/nodemap_lproc.c b/lustre/ptlrpc/nodemap_lproc.c new file mode 100644 index 0000000..f18d1b4 --- /dev/null +++ b/lustre/ptlrpc/nodemap_lproc.c @@ -0,0 +1,1080 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (C) 2013, Trustees of Indiana University + * Author: Joshua Walgenbach + */ + +#define NODEMAP_LPROC_ID_LEN 16 +#define NODEMAP_LPROC_FLAG_LEN 2 + +#include +#include +#include +#include +#include +#include "nodemap_internal.h" + +/* Turn on proc debug interface to allow OSS and + * MDS nodes to configure nodemap independently of + * MGS (since the nodemap distribution is not written + * yet */ +#define NODEMAP_PROC_DEBUG 1 + +/** + * Reads and prints the idmap for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_idmap_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + struct lu_idmap *idmap; + struct rb_node *node; + bool cont = 0; + + seq_printf(m, "[\n"); + read_lock(&nodemap->nm_idmap_lock); + for (node = rb_first(&nodemap->nm_client_to_fs_uidmap); node; + node = rb_next(node)) { + if (cont) + seq_printf(m, ",\n"); + cont = 1; + idmap = rb_entry(node, struct lu_idmap, id_client_to_fs); + if (idmap != NULL) + seq_printf(m, " { idtype: uid, client_id: %u, " + "fs_id: %u }", idmap->id_client, + idmap->id_fs); + } + for (node = rb_first(&nodemap->nm_client_to_fs_gidmap); + node; node = rb_next(node)) { + if (cont) + seq_printf(m, ",\n"); + idmap = rb_entry(node, struct lu_idmap, id_client_to_fs); + if (idmap != NULL) + seq_printf(m, " { idtype: gid, client_id: %u, " + "fs_id: %u }", idmap->id_client, + idmap->id_fs); + } + read_unlock(&nodemap->nm_idmap_lock); + seq_printf(m, "\n"); + seq_printf(m, "]\n"); + + return 0; +} + +/** + * Attaches nodemap_idmap_show to proc file. + * + * \param inode inode of seq file in proc fs + * \param file seq file + * \retval 0 success + */ +static int nodemap_idmap_open(struct inode *inode, struct file *file) +{ + struct lu_nodemap *nodemap = PDE_DATA(inode); + + return single_open(file, nodemap_idmap_show, nodemap); +} + +/** + * Reads and prints the NID ranges for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_ranges_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + struct lu_nid_range *range; + struct interval_node_extent ext; + bool cont = false; + + seq_printf(m, "[\n"); + read_lock(&nm_range_tree_lock); + list_for_each_entry(range, &nodemap->nm_ranges, rn_list) { + if (cont) + seq_printf(m, ",\n"); + cont = 1; + ext = range->rn_node.in_extent; + seq_printf(m, " { id: %u, start_nid: %s, " + "end_nid: %s }", + range->rn_id, libcfs_nid2str(ext.start), + libcfs_nid2str(ext.end)); + } + read_unlock(&nm_range_tree_lock); + seq_printf(m, "\n"); + seq_printf(m, "]\n"); + + return 0; +} + +/** + * Connects nodemap_idmap_show to proc file. + * + * \param inode inode of seq file in proc fs + * \param file seq file + * \retval 0 success + */ +static int nodemap_ranges_open(struct inode *inode, struct file *file) +{ + struct lu_nodemap *nodemap = PDE_DATA(inode); + + return single_open(file, nodemap_ranges_show, nodemap); +} + +/** + * Hash callback, reads and prints the exports attached to this nodemap. + * + * \param hs nodemap member hash + * \param bd unused + * \param hnode current member in hash + * \param data seq_file to print to + * \retval 0 success + */ +static int nodemap_exports_show_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd, + struct hlist_node *hnode, void *data) +{ + struct seq_file *m = data; + struct obd_export *exp; + char *key; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + key = cfs_hash_key(hs, hnode); + seq_printf(m, " { nid: %s, uuid: %s },", + obd_export_nid2str(exp), exp->exp_client_uuid.uuid); + + return 0; +} + +/** + * Reads and prints the exports attached to the given nodemap via hash + * foreach callback. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_exports_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + seq_printf(m, "[\n"); + + cfs_hash_for_each(nodemap->nm_member_hash, nodemap_exports_show_cb, m); + + seq_printf(m, "\n"); + seq_printf(m, "]\n"); + + return 0; +} + +/** + * Attaches nodemap_idmap_show to proc file. + * + * \param inode inode of seq file in proc fs + * \param file seq file + * \retval 0 success + */ +static int nodemap_exports_open(struct inode *inode, struct file *file) +{ + struct proc_dir_entry *dir = PDE(inode); + struct lu_nodemap *nodemap = dir->data; + + return single_open(file, nodemap_exports_show, nodemap); +} + +/** + * Reads and prints the active flag for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_active_seq_show(struct seq_file *m, void *data) +{ + return seq_printf(m, "%u\n", (unsigned int)nodemap_active); +} + +/** + * Activate/deactivate nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, "1" or "0" to activate/deactivate nodemap + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +nodemap_active_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + char active_string[NODEMAP_LPROC_FLAG_LEN + 1]; + long unsigned int active; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(active_string)) + return -EINVAL; + + if (copy_from_user(active_string, buffer, count)) + return -EFAULT; + + active_string[count] = '\0'; + rc = kstrtoul(active_string, 10, &active); + if (rc != 0) + return -EINVAL; + + nodemap_active = active; + + return count; +} +LPROC_SEQ_FOPS(nodemap_active); + +/** + * Reads and prints the nodemap ID for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_id_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + return seq_printf(m, "%u\n", nodemap->nm_id); +} +LPROC_SEQ_FOPS_RO(nodemap_id); + +/** + * Reads and prints the root squash UID for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_squash_uid_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + return seq_printf(m, "%u\n", nodemap->nm_squash_uid); +} + +/** + * Reads and prints the root squash GID for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_squash_gid_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + return seq_printf(m, "%u\n", nodemap->nm_squash_gid); +} + +/** + * Reads and prints the trusted flag for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_trusted_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + return seq_printf(m, "%d\n", (int)nodemap->nmf_trust_client_ids); +} + +/** + * Reads and prints the admin flag for the given nodemap. + * + * \param m seq file in proc fs + * \param data unused + * \retval 0 success + */ +static int nodemap_admin_seq_show(struct seq_file *m, void *data) +{ + struct lu_nodemap *nodemap = m->private; + + return seq_printf(m, "%d\n", (int)nodemap->nmf_allow_root_access); +} + +#ifdef NODEMAP_PROC_DEBUG +/** + * Helper functions to set nodemap flags. + * + * \param[in] buffer string, which is "1" or "0" to set/unset flag + * \param[in] count \a buffer length + * \param[out] flag_p where to store flag value + * \retval \a count on success + * \retval negative number on error + */ +static int nodemap_proc_read_flag(const char __user *buffer, + unsigned long count, unsigned int *flag_p) +{ + char scratch[NODEMAP_LPROC_FLAG_LEN + 1]; + long unsigned int flag_buf; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(scratch)) + return -EINVAL; + + if (copy_from_user(scratch, buffer, count)) + return -EFAULT; + + scratch[count] = '\0'; + rc = kstrtoul(scratch, 10, &flag_buf); + if (rc != 0) + return -EINVAL; + + *flag_p = flag_buf; + + return count; +} + +/** + * Set the squash UID. + * + * \param[in] file proc file + * \param[in] buffer string representing squash UID to set + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +nodemap_squash_uid_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + char squash[NODEMAP_LPROC_ID_LEN + 1]; + struct seq_file *m = file->private_data; + struct lu_nodemap *nodemap = m->private; + long unsigned int squash_uid; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(squash)) + return -EINVAL; + + if (copy_from_user(squash, buffer, count)) + return -EFAULT; + + squash[count] = '\0'; + rc = kstrtoul(squash, 10, &squash_uid); + if (rc != 0) + return -EINVAL; + + nodemap->nm_squash_uid = squash_uid; + + return count; +} + +/** + * Set the squash GID. + * + * \param[in] file proc file + * \param[in] buffer string representing squash GID to set + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +nodemap_squash_gid_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + char squash[NODEMAP_LPROC_ID_LEN + 1]; + struct seq_file *m = file->private_data; + struct lu_nodemap *nodemap = m->private; + long unsigned int squash_gid; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(squash)) + return -EINVAL; + + if (copy_from_user(squash, buffer, count)) + return -EFAULT; + + squash[count] = '\0'; + rc = kstrtoul(squash, 10, &squash_gid); + if (rc != 0) + return -EINVAL; + + nodemap->nm_squash_gid = squash_gid; + + return count; +} + +/** + * Set/unset the trusted flag. + * + * \param[in] file proc file + * \param[in] buffer string, "1" or "0" + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +nodemap_trusted_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + struct seq_file *m = file->private_data; + struct lu_nodemap *nodemap = m->private; + int flags; + int rc; + + rc = nodemap_proc_read_flag(buffer, count, &flags); + if (rc >= 0) { + nodemap->nmf_trust_client_ids = !!flags; + nm_member_revoke_locks(nodemap); + } + + return rc; +} + +/** + * Set/unset the admin flag. + * + * \param[in] file proc file + * \param[in] buffer string, "1" or "0" + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +nodemap_admin_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + struct seq_file *m = file->private_data; + struct lu_nodemap *nodemap = m->private; + int flags; + int rc; + + rc = nodemap_proc_read_flag(buffer, count, &flags); + if (rc >= 0) { + nodemap->nmf_allow_root_access = !!flags; + nm_member_revoke_locks(nodemap); + } + + return rc; +} + +/** + * Add a nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, name of the nodemap to add + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_add_nodemap_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + char nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; + char *cpybuf = NULL; + char *pos; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(nodemap_name)) + return -EINVAL; + + if (copy_from_user(nodemap_name, buffer, count)) + return -EFAULT; + + nodemap_name[count] = '\0'; + + cpybuf = nodemap_name; + pos = strsep(&cpybuf, " \n"); + if (pos == NULL) + return -EINVAL; + + rc = nodemap_add(nodemap_name); + if (rc == 0) + rc = count; + + return rc; +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap); + +/** + * Delete a nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, name of the nodemap to delete + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_del_nodemap_seq_write(struct file *file, const char __user *buffer, + size_t count, loff_t *off) +{ + char nodemap_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; + char *cpybuf = NULL; + char *pos; + int rc = count; + + if (count == 0) + return 0; + + if (count >= sizeof(nodemap_name)) + return -EINVAL; + + if (copy_from_user(nodemap_name, buffer, count)) + return -EFAULT; + + nodemap_name[count] = '\0'; + + cpybuf = nodemap_name; + pos = strsep(&cpybuf, " \n"); + if (pos == NULL) + return -EINVAL; + + rc = nodemap_del(nodemap_name); + if (rc == 0) + rc = count; + + return rc; + +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap); + +/** + * Helper function to parse a NID string. + * + * \param[in] rangestr string representation of NIDs, see libcfs_str2nid() + * \param[out] nids array of two nids + * \retval 0 on success + * \retval negative number on error + */ +static int parse_nids(char *rangestr, lnet_nid_t nids[2]) +{ + struct list_head nidlist; + char nidstr[2][LNET_NIDSTR_SIZE]; + char nidrange_str[2 * LNET_NIDSTR_SIZE + 2]; + int rc = 0; + + INIT_LIST_HEAD(&nidlist); + + if (cfs_parse_nidlist(rangestr, strlen(rangestr), + &nidlist) <= 0) + return -EINVAL; + + if (!cfs_nidrange_is_contiguous(&nidlist)) + return -EINVAL; + + cfs_nidrange_find_min_max(&nidlist, nidstr[0], nidstr[1], + LNET_NIDSTR_SIZE); + snprintf(nidrange_str, sizeof(nidrange_str), "%s:%s", + nidstr[0], nidstr[1]); + + rc = nodemap_parse_range(nidrange_str, nids); + if (rc != 0) + return -EINVAL; + + cfs_free_nidlist(&nidlist); + + return 0; +} + +/** + * Add a NID range to nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, " " + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_add_nodemap_range_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + char name_range[LUSTRE_NODEMAP_NAME_LENGTH + + LNET_NIDSTR_SIZE * 2 + 2]; + char *cpybuf = NULL; + char *name; + char *rangestr = NULL; + lnet_nid_t nids[2]; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(name_range)) + GOTO(out, rc = -EINVAL); + + if (copy_from_user(name_range, buffer, count)) + GOTO(out, rc = -EFAULT); + + name_range[count] = '\0'; + + cpybuf = name_range; + name = strsep(&cpybuf, " "); + if (name == NULL) + GOTO(out, rc = -EINVAL); + + rangestr = strsep(&cpybuf, " \n"); + if (rangestr == NULL) + GOTO(out, rc = -EINVAL); + + rc = parse_nids(rangestr, nids); + if (rc != 0) + GOTO(out, rc = rc); + + rc = nodemap_add_range(name, nids); + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (rc == 0) + rc = count; + +out: + return rc; +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_range); + +/** + * Delete a NID range from nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, " " + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_del_nodemap_range_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + char name_range[LUSTRE_NODEMAP_NAME_LENGTH + + LNET_NIDSTR_SIZE * 2 + 2]; + char *cpybuf = NULL; + char *name; + char *rangestr = NULL; + lnet_nid_t nids[2]; + int rc; + + if (count == 0) + return 0; + + if (count >= sizeof(name_range)) + GOTO(out, rc = -EINVAL); + + if (copy_from_user(name_range, buffer, count)) + GOTO(out, rc = -EFAULT); + + name_range[count] = '\0'; + + cpybuf = name_range; + name = strsep(&cpybuf, " "); + if (name == NULL) + GOTO(out, rc = -EINVAL); + + rangestr = strsep(&cpybuf, " \n"); + if (rangestr == NULL) + GOTO(out, rc = -EINVAL); + + rc = parse_nids(rangestr, nids); + if (rc != 0) + GOTO(out, rc = rc); + + rc = nodemap_del_range(name, nids); + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (rc == 0) + rc = count; + +out: + return rc; +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_range); + +/** + * Add an idmap to nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, " " + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_add_nodemap_idmap_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + char name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16]; + char *cpybuf = NULL; + char *name; + char *idtypestr = NULL; + char *idmapstr = NULL; + __u32 idmap[2]; + int rc = count; + + if (count == 0) + return 0; + + if (count >= sizeof(name_idmapstr)) + GOTO(out, rc = -EINVAL); + + if (copy_from_user(name_idmapstr, buffer, count)) + GOTO(out, rc = -EFAULT); + + name_idmapstr[count] = '\0'; + + cpybuf = name_idmapstr; + name = strsep(&cpybuf, " "); + if (name == NULL) + GOTO(out, rc = -EINVAL); + + idtypestr = strsep(&cpybuf, " "); + if (idtypestr == NULL) + GOTO(out, rc = -EINVAL); + + idmapstr = strsep(&cpybuf, " \n"); + if (idmapstr == NULL) + GOTO(out, rc = -EINVAL); + + rc = nodemap_parse_idmap(idmapstr, idmap); + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (strcmp(idtypestr, "uid") == 0) + rc = nodemap_add_idmap(name, NODEMAP_UID, idmap); + else if (strcmp(idtypestr, "gid") == 0) + rc = nodemap_add_idmap(name, NODEMAP_GID, idmap); + else + GOTO(out, rc = -EINVAL); + + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (rc == 0) + rc = count; + +out: + return rc; +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, add_nodemap_idmap); + +/** + * Delete an idmap from nodemap. + * + * \param[in] file proc file + * \param[in] buffer string, " " + * \param[in] count \a buffer length + * \param[in] off unused + * \retval \a count on success + * \retval negative number on error + */ +static ssize_t +lprocfs_del_nodemap_idmap_seq_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *off) +{ + char name_idmapstr[LUSTRE_NODEMAP_NAME_LENGTH + 16]; + char *cpybuf = NULL; + char *name; + char *idtypestr = NULL; + char *idmapstr = NULL; + __u32 idmap[2]; + int rc = count; + + if (count == 0) + return 0; + + if (count >= sizeof(name_idmapstr)) + GOTO(out, rc = -EINVAL); + + if (copy_from_user(name_idmapstr, buffer, count)) + GOTO(out, rc = -EFAULT); + + name_idmapstr[count] = '\0'; + + cpybuf = name_idmapstr; + name = strsep(&cpybuf, " "); + if (name == NULL) + GOTO(out, rc = -EINVAL); + + idtypestr = strsep(&cpybuf, " "); + if (idtypestr == NULL) + GOTO(out, rc = -EINVAL); + + idmapstr = strsep(&cpybuf, " \n"); + if (idmapstr == NULL) + GOTO(out, rc = -EINVAL); + + rc = nodemap_parse_idmap(idmapstr, idmap); + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (strcmp(idtypestr, "uid") == 0) + rc = nodemap_del_idmap(name, NODEMAP_UID, idmap); + else if (strcmp(idtypestr, "gid") == 0) + rc = nodemap_del_idmap(name, NODEMAP_GID, idmap); + else + GOTO(out, rc = -EINVAL); + + if (rc != 0) + GOTO(out, rc = -EINVAL); + + if (rc == 0) + rc = count; + +out: + return rc; +} +LPROC_SEQ_FOPS_WO_TYPE(nodemap, del_nodemap_idmap); +#endif /* NODEMAP_PROC_DEBUG */ + +static struct lprocfs_seq_vars lprocfs_nm_module_vars[] = { + { + .name = "active", + .fops = &nodemap_active_fops, + }, +#ifdef NODEMAP_PROC_DEBUG + { + .name = "add_nodemap", + .fops = &nodemap_add_nodemap_fops, + }, + { + .name = "remove_nodemap", + .fops = &nodemap_del_nodemap_fops, + }, + { + .name = "add_nodemap_range", + .fops = &nodemap_add_nodemap_range_fops, + }, + { + .name = "del_nodemap_range", + .fops = &nodemap_del_nodemap_range_fops, + }, + { + .name = "add_nodemap_idmap", + .fops = &nodemap_add_nodemap_idmap_fops, + }, + { + .name = "del_nodemap_idmap", + .fops = &nodemap_del_nodemap_idmap_fops, + }, +#endif /* NODEMAP_PROC_DEBUG */ + { + NULL + } +}; + +#ifdef NODEMAP_PROC_DEBUG +LPROC_SEQ_FOPS(nodemap_trusted); +LPROC_SEQ_FOPS(nodemap_admin); +LPROC_SEQ_FOPS(nodemap_squash_uid); +LPROC_SEQ_FOPS(nodemap_squash_gid); +#else +LPROC_SEQ_FOPS_RO(nodemap_trusted); +LPROC_SEQ_FOPS_RO(nodemap_admin); +LPROC_SEQ_FOPS_RO(nodemap_squash_uid); +LPROC_SEQ_FOPS_RO(nodemap_squash_gid); +#endif + +const struct file_operations nodemap_ranges_fops = { + .open = nodemap_ranges_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +const struct file_operations nodemap_idmap_fops = { + .open = nodemap_idmap_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +const struct file_operations nodemap_exports_fops = { + .open = nodemap_exports_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release +}; + +static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = { + { + .name = "id", + .fops = &nodemap_id_fops, + }, + { + .name = "trusted_nodemap", + .fops = &nodemap_trusted_fops, + }, + { + .name = "admin_nodemap", + .fops = &nodemap_admin_fops, + }, + { + .name = "squash_uid", + .fops = &nodemap_squash_uid_fops, + }, + { + .name = "squash_gid", + .fops = &nodemap_squash_gid_fops, + }, + { + .name = "ranges", + .fops = &nodemap_ranges_fops, + }, + { + .name = "exports", + .fops = &nodemap_exports_fops, + }, + { + .name = "idmap", + .fops = &nodemap_idmap_fops, + }, + { + NULL + } +}; + +static struct lprocfs_seq_vars lprocfs_default_nodemap_vars[] = { + { + .name = "id", + .fops = &nodemap_id_fops, + }, + { + .name = "trusted_nodemap", + .fops = &nodemap_trusted_fops, + }, + { + .name = "admin_nodemap", + .fops = &nodemap_admin_fops, + }, + { + .name = "squash_uid", + .fops = &nodemap_squash_uid_fops, + }, + { + .name = "squash_gid", + .fops = &nodemap_squash_gid_fops, + }, + { + .name = "exports", + .fops = &nodemap_exports_fops, + }, + { + NULL + } +}; + +/** + * Initialize the nodemap procfs directory. + * + * \retval 0 success + */ +int nodemap_procfs_init(void) +{ + int rc = 0; + + proc_lustre_nodemap_root = lprocfs_seq_register(LUSTRE_NODEMAP_NAME, + proc_lustre_root, + lprocfs_nm_module_vars, + NULL); + + if (IS_ERR(proc_lustre_nodemap_root)) { + rc = PTR_ERR(proc_lustre_nodemap_root); + CERROR("cannot create 'nodemap' directory: rc = %d\n", + rc); + proc_lustre_nodemap_root = NULL; + } + + return rc; +} + +/** + * Register the proc directory for a nodemap + * + * \param name name of nodemap + * \param is_default: 1 if default nodemap + * \retval 0 success + */ +int lprocfs_nodemap_register(const char *name, + bool is_default, + struct lu_nodemap *nodemap) +{ + struct proc_dir_entry *nodemap_proc_entry; + int rc = 0; + + if (is_default) + nodemap_proc_entry = + lprocfs_seq_register(name, + proc_lustre_nodemap_root, + lprocfs_default_nodemap_vars, + nodemap); + else + nodemap_proc_entry = + lprocfs_seq_register(name, + proc_lustre_nodemap_root, + lprocfs_nodemap_vars, + nodemap); + + if (IS_ERR(nodemap_proc_entry)) { + rc = PTR_ERR(nodemap_proc_entry); + CERROR("cannot create 'nodemap/%s': rc = %d\n", name, rc); + nodemap_proc_entry = NULL; + } + + nodemap->nm_proc_entry = nodemap_proc_entry; + + return rc; +} diff --git a/lustre/ptlrpc/nodemap_member.c b/lustre/ptlrpc/nodemap_member.c new file mode 100644 index 0000000..08b269b --- /dev/null +++ b/lustre/ptlrpc/nodemap_member.c @@ -0,0 +1,309 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (C) 2013, Trustees of Indiana University + * Author: Joshua Walgenbach + */ +#include +#include +#include +#include "nodemap_internal.h" + +#define HASH_NODEMAP_MEMBER_BKT_BITS 3 +#define HASH_NODEMAP_MEMBER_CUR_BITS 3 +#define HASH_NODEMAP_MEMBER_MAX_BITS 7 + +/** + * member hash functions + * + * The purpose of this hash is to maintain the list of + * exports that are connected and associated with a + * particular nodemap + */ +static void nm_member_getref(struct obd_export *exp) +{ +} + +void nm_member_putref(struct obd_export *exp) +{ +} + +static __u32 nm_member_hashfn(cfs_hash_t *hash_body, + const void *key, unsigned mask) +{ + return cfs_hash_djb2_hash(key, strlen(key), mask); +} + +static void *nm_member_hs_key(struct hlist_node *hnode) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + + return exp; +} + +static int nm_member_hs_keycmp(const void *key, struct hlist_node *hnode) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + + return key == exp; +} + +static void *nm_member_hs_hashobject(struct hlist_node *hnode) +{ + return hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); +} + +static void nm_member_hs_get(cfs_hash_t *hs, struct hlist_node *hnode) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + nm_member_getref(exp); +} + +static void nm_member_hs_put_locked(cfs_hash_t *hs, + struct hlist_node *hnode) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + nm_member_putref(exp); +} + +/** + * Delete a member from a member hash + * + * \param nodemap nodemap containing hash + * \paraa nid nid of member to delete + */ +void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp) +{ + + exp->exp_target_data.ted_nodemap = NULL; + exp = cfs_hash_del_key(nodemap->nm_member_hash, exp); + if (exp == NULL) + return; + + class_export_put(exp); +} + +static cfs_hash_ops_t nm_member_hash_operations = { + .hs_hash = nm_member_hashfn, + .hs_key = nm_member_hs_key, + .hs_keycmp = nm_member_hs_keycmp, + .hs_object = nm_member_hs_hashobject, + .hs_get = nm_member_hs_get, + .hs_put_locked = nm_member_hs_put_locked, +}; + +/** + * Init a member hash of a nodemap + * + * \param nodemap nodemap containing the member hash + */ +int nm_member_init_hash(struct lu_nodemap *nodemap) +{ + char nodemap_hashname[LUSTRE_NODEMAP_NAME_LENGTH + 3]; + + + snprintf(nodemap_hashname, sizeof(nodemap_hashname), + "nm-%s", nodemap->nm_name); + nodemap->nm_member_hash = cfs_hash_create(nodemap_hashname, + HASH_NODEMAP_MEMBER_CUR_BITS, + HASH_NODEMAP_MEMBER_MAX_BITS, + HASH_NODEMAP_MEMBER_BKT_BITS, 0, + CFS_HASH_MIN_THETA, + CFS_HASH_MAX_THETA, + &nm_member_hash_operations, + CFS_HASH_DEFAULT); + if (nodemap->nm_member_hash == NULL) + return -ENOMEM; + + return 0; +} + +/** + * Callback from deleting a hash member + */ +static int nm_member_delete_hash_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd, + struct hlist_node *hnode, void *data) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + + exp->exp_target_data.ted_nodemap = NULL; + cfs_hash_bd_del_locked(hs, bd, hnode); + class_export_put(exp); + + return 0; +} + +/** + * Delete a member hash from a nodemap + * + * \param nodemap nodemap to remove the hash from + */ +void nm_member_delete_hash(struct lu_nodemap *nodemap) +{ + cfs_hash_for_each_safe(nodemap->nm_member_hash, + nm_member_delete_hash_cb, + nodemap); + cfs_hash_putref(nodemap->nm_member_hash); +} + +/** + * Add a member export to a nodemap + * + * \param nodemap nodemap to search + * \param exp obd_export to search + * \retval -EEXIST export is already hashed to a different nodemap + * \retval -EINVAL export is NULL + */ +int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp) +{ + int rc = 0; + + if (exp == NULL) { + CWARN("attempted to add null export to nodemap %s\n", + nodemap->nm_name); + return -EINVAL; + } + + if (hlist_unhashed(&exp->exp_target_data.ted_nodemap_member) == 0) { + /* export is already member of nodemap */ + if (exp->exp_target_data.ted_nodemap == nodemap) + return 0; + + /* possibly reconnecting while about to be reclassified */ + CWARN("export %p %s already hashed, failed to add to " + "nodemap %s already member of %s\n", exp, + exp->exp_client_uuid.uuid, + nodemap->nm_name, + (exp->exp_target_data.ted_nodemap == NULL) ? "unknown" : + exp->exp_target_data.ted_nodemap->nm_name); + return -EEXIST; + } + + exp->exp_target_data.ted_nodemap = nodemap; + + rc = cfs_hash_add_unique(nodemap->nm_member_hash, exp, + &exp->exp_target_data.ted_nodemap_member); + + if (rc == 0 ) + class_export_get(exp); + /* else -EALREADY - exp already in nodemap hash */ + + return rc; +} + +/** + * Revokes the locks on an export if it is attached to an MDT and not in + * recovery. As a performance enhancement, the lock revoking process could + * revoke only the locks that cover files affected by the nodemap change. + */ +static void nm_member_exp_revoke(struct obd_export *exp) +{ + struct obd_type *type = exp->exp_obd->obd_type; + if (strcmp(type->typ_name, LUSTRE_MDT_NAME) != 0) + return; + if (exp->exp_obd->obd_recovering) + return; + + ldlm_revoke_export_locks(exp); +} + +static int nm_member_reclassify_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd, + struct hlist_node *hnode, void *data) +{ + struct obd_export *exp; + + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + if (exp == NULL) + goto out; + + /* Call member add before del so exp->nodemap is never NULL. Must use + * bd_del_locked inside a cfs_hash callback. For those reasons, can't + * use member_del. + */ + nodemap_add_member(exp->exp_connection->c_peer.nid, exp); + cfs_hash_bd_del_locked(hs, bd, hnode); + class_export_put(exp); + + nm_member_exp_revoke(exp); +out: + return 0; +} + +/** + * Reclassify the members of a nodemap after range changes or activation, + * based on the member export's NID and the nodemap's new NID ranges. Exports + * that are no longer classified as being part of this nodemap are moved to the + * nodemap whose NID ranges contain the export's NID, and their locks are + * revoked. + * + * \param nodemap nodemap with members to reclassify + */ +void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap) +{ + cfs_hash_for_each_safe(nodemap->nm_member_hash, + nm_member_reclassify_cb, + NULL); +} + +static int nm_member_revoke_locks_cb(cfs_hash_t *hs, cfs_hash_bd_t *bd, + struct hlist_node *hnode, void *data) +{ + struct obd_export *exp; + exp = hlist_entry(hnode, struct obd_export, + exp_target_data.ted_nodemap_member); + if (exp == NULL) + return 0; + + nm_member_exp_revoke(exp); + return 0; +} + +/** + * Revoke the locks for member exports. Changing the idmap is + * akin to deleting the security context. If the locks are not + * canceled, the client could cache permissions that are no + * longer correct with the map. + * + * \param nodemap nodemap that has been altered + */ +void nm_member_revoke_locks(struct lu_nodemap *nodemap) +{ + cfs_hash_for_each(nodemap->nm_member_hash, nm_member_revoke_locks_cb, + NULL); +} diff --git a/lustre/nodemap/nodemap_range.c b/lustre/ptlrpc/nodemap_range.c similarity index 97% rename from lustre/nodemap/nodemap_range.c rename to lustre/ptlrpc/nodemap_range.c index 1f9881d..59371b1 100644 --- a/lustre/nodemap/nodemap_range.c +++ b/lustre/ptlrpc/nodemap_range.c @@ -36,7 +36,8 @@ * classified into their nodemaps, and the lu_nodemap structure will be * set in the export structure for the connecting client. Pointers to * the lu_nid_range nodes will be added to linked links within the - * lu_nodemap structure for reporting purposes.A + * lu_nodemap structure for reporting purposes. Access to range tree should be + * controlled to prevent read access during update operations. */ static struct interval_node *range_interval_root; diff --git a/lustre/nodemap/nodemap_rbtree.c b/lustre/ptlrpc/nodemap_rbtree.c similarity index 100% rename from lustre/nodemap/nodemap_rbtree.c rename to lustre/ptlrpc/nodemap_rbtree.c diff --git a/lustre/ptlrpc/ptlrpc_internal.h b/lustre/ptlrpc/ptlrpc_internal.h index 76382c9..09f7b47 100644 --- a/lustre/ptlrpc/ptlrpc_internal.h +++ b/lustre/ptlrpc/ptlrpc_internal.h @@ -296,6 +296,8 @@ static inline int ll_rpc_recoverable_error(int rc) #ifdef HAVE_SERVER_SUPPORT int tgt_mod_init(void); void tgt_mod_exit(void); +int nodemap_mod_init(void); +void nodemap_mod_exit(void); #else /* HAVE_SERVER_SUPPORT */ static inline int tgt_mod_init(void) { @@ -306,6 +308,16 @@ static inline void tgt_mod_exit(void) { return; } + +static inline int nodemap_mod_init(void) +{ + return 0; +} + +static inline void nodemap_mod_exit(void) +{ + return; +} #endif /* !HAVE_SERVER_SUPPORT */ static inline void ptlrpc_reqset_put(struct ptlrpc_request_set *set) diff --git a/lustre/ptlrpc/ptlrpc_module.c b/lustre/ptlrpc/ptlrpc_module.c index 7931e5d..10e6717 100644 --- a/lustre/ptlrpc/ptlrpc_module.c +++ b/lustre/ptlrpc/ptlrpc_module.c @@ -109,7 +109,13 @@ __init int ptlrpc_init(void) if (rc) GOTO(err_sptlrpc, rc); + rc = nodemap_mod_init(); + if (rc) + GOTO(err_nrs, rc); + RETURN(0); +err_nrs: + ptlrpc_nrs_fini(); err_sptlrpc: sptlrpc_fini(); err_ldlm: @@ -133,6 +139,7 @@ err_layout: static void __exit ptlrpc_exit(void) { + nodemap_mod_exit(); ptlrpc_nrs_fini(); sptlrpc_fini(); ldlm_exit(); diff --git a/lustre/target/tgt_handler.c b/lustre/target/tgt_handler.c index 57ec2e5..41ce2c1 100644 --- a/lustre/target/tgt_handler.c +++ b/lustre/target/tgt_handler.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "tgt_internal.h" @@ -242,6 +243,7 @@ static int tgt_ost_body_unpack(struct tgt_session_info *tsi, __u32 flags) struct ost_body *body; struct req_capsule *pill = tsi->tsi_pill; struct lustre_capa *capa; + struct lu_nodemap *nodemap; int rc; ENTRY; @@ -254,6 +256,15 @@ static int tgt_ost_body_unpack(struct tgt_session_info *tsi, __u32 flags) if (rc) RETURN(rc); + nodemap = tsi->tsi_exp->exp_target_data.ted_nodemap; + + body->oa.o_uid = nodemap_map_id(nodemap, NODEMAP_UID, + NODEMAP_CLIENT_TO_FS, + body->oa.o_uid); + body->oa.o_gid = nodemap_map_id(nodemap, NODEMAP_GID, + NODEMAP_CLIENT_TO_FS, + body->oa.o_gid); + if (body->oa.o_valid & OBD_MD_FLOSSCAPA) { capa = req_capsule_client_get(pill, &RMF_CAPA1); if (capa == NULL) { diff --git a/lustre/tests/sanity-sec.sh b/lustre/tests/sanity-sec.sh index 8d7c39b..eb005ff 100644 --- a/lustre/tests/sanity-sec.sh +++ b/lustre/tests/sanity-sec.sh @@ -732,6 +732,10 @@ squash_id() { fi } +# ensure that the squash defaults are the expected defaults +squash_id default 99 0 +squash_id default 99 1 + test_nid() { local cmd @@ -1194,11 +1198,14 @@ run_test 15 "test id mapping" log "cleanup: ======================================================" sec_unsetup() { - for num in `seq $MDSCOUNT`; do + ## nodemap deactivated + do_facet mgs lctl nodemap_activate 0 + + for num in $(seq $MDSCOUNT); do if [ "${identity_old[$num]}" = 1 ]; then - switch_identity $num false || identity_old[$num]=$? + switch_identity $num false || identity_old[$num]=$? fi - done + done $RUNAS -u $ID0 ls $DIR $RUNAS -u $ID1 ls $DIR diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index 40239de..1d3b155 100755 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -520,7 +520,6 @@ load_modules_local() { load_module ../ldiskfs/ldiskfs load_module osd-ldiskfs/osd_ldiskfs fi - load_module nodemap/nodemap load_module mgs/mgs load_module mdd/mdd load_module mdt/mdt diff --git a/lustre/utils/obd.c b/lustre/utils/obd.c index 76fba40..4acdf7f 100644 --- a/lustre/utils/obd.c +++ b/lustre/utils/obd.c @@ -3740,8 +3740,10 @@ int jt_nodemap_modify(int argc, char **argv) } if (nodemap_name == NULL || param == NULL || value == NULL) { - fprintf(stderr, "usage: nodemap_modify --name " - "--property --value \n"); + fprintf(stderr, "usage: nodemap_modify --name " + "--property --value \n"); + fprintf(stderr, "valid properties: admin trusted " + "squash_uid squash_gid\n"); return -1; } @@ -3908,7 +3910,7 @@ int jt_nodemap_del_idmap(int argc, char **argv) rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, idmap, NULL); if (rc != 0) { errno = -rc; - fprintf(stderr, "cannot add %smap '%s' to nodemap '%s'" + fprintf(stderr, "cannot delete %smap '%s' from nodemap '%s'" ": rc = %d\n", idtype, idmap, nodemap_name, rc); }