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
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
lustre/lfsck/autoMakefile
lustre/mdt/Makefile
lustre/mdt/autoMakefile
-lustre/nodemap/Makefile
-lustre/nodemap/autoMakefile
lustre/mdd/Makefile
lustre/mdd/autoMakefile
lustre/fld/Makefile
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;
};
/**
struct mgs_export_data eu_mgs_data;
} u;
- struct nodemap *exp_nodemap;
struct adaptive_timeout exp_bl_lock_at;
};
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 */
/* 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;
};
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,
__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 */
#include <lustre_param.h>
#include <lustre_quota.h>
#include <lustre_lfsck.h>
+#include <lustre_nodemap.h>
mdl_mode_t mdt_mdl_lock_modes[] = {
[LCK_MINMODE] = MDL_MINMODE,
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;
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;
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.*/
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;
+ }
}
}
}
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);
/* 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);
}
}
+ 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));
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)
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);
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)
{
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;
};
#include "mdt_internal.h"
#include <lnet/nidstr.h>
+#include <lustre_nodemap.h>
typedef enum ucred_init_type {
NONE_INIT = 0,
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;
}
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);
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);
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));
(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;
#define DEBUG_SUBSYSTEM S_MDS
#include <linux/xattr.h>
+#include <obd_class.h>
+#include <lustre_nodemap.h>
#include <lustre_acl.h>
#include "mdt_internal.h"
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));
} 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;
* 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);
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;
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,
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];
+++ /dev/null
-MODULES = nodemap
-nodemap-objs = nodemap_handler.o nodemap_lproc.o nodemap_range.o
-nodemap-objs += nodemap_idmap.o nodemap_rbtree.o
-
-@INCLUDE_RULES@
+++ /dev/null
-#
-# 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
+++ /dev/null
-/*
- * 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 <jjw@iu.edu>
- */
-
-#define NODEMAP_LPROC_ID_LEN 16
-#define NODEMAP_LPROC_FLAG_LEN 2
-
-#include <lprocfs_status.h>
-#include <lustre_net.h>
-#include <interval_tree.h>
-#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;
-}
#include <obd_class.h>
#include <lprocfs_status.h>
#include <lustre/lustre_idl.h>
+#include <lustre_nodemap.h>
#if defined(LPROCFS)
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;
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);
}
#include <lustre/lustre_idl.h>
#include <lustre_dlm.h>
#include <lustre_quota.h>
+#include <lustre_nodemap.h>
#include "ofd_internal.h"
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;
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);
}
#include <lustre_ioctl.h>
#include <lustre_quota.h>
#include <lustre_lfsck.h>
+#include <lustre_nodemap.h>
/**
* Initialize OFD per-export statistics.
* \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;
*/
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;
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);
}
struct ofd_device *ofd;
struct lustre_handle conn = { 0 };
int rc;
+ lnet_nid_t *client_nid;
ENTRY;
if (_exp == NULL || obd == NULL || cluuid == NULL)
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;
out:
if (rc != 0) {
+ nodemap_del_member(exp);
class_disconnect(exp);
*_exp = NULL;
} else {
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);
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
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
$(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
* Author: Joshua Walgenbach <jjw@iu.edu>
*/
#include <linux/module.h>
+#include <linux/sort.h>
#include <lnet/nidstr.h>
#include <lustre_net.h>
+#include <lustre_acl.h>
+#include <lustre_eacl.h>
+#include <obd_class.h>
#include "nodemap_internal.h"
#define HASH_NODEMAP_BKT_BITS 3
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
*/
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);
}
*/
static void nodemap_getref(struct lu_nodemap *nodemap)
{
- CDEBUG(D_INFO, "nodemap %p\n", nodemap);
atomic_inc(&nodemap->nm_refcount);
}
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)
if (!isalnum(*name) && *name != '_')
return false;
}
+
return true;
}
* \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
*
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);
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);
*
* 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.
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;
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)
}
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
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);
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);
*/
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),
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;
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);
GOTO(out, rc = -ENOENT);
nodemap->nmf_allow_root_access = allow_root;
+ nm_member_revoke_locks(nodemap);
nodemap_putref(nodemap);
out:
return rc;
GOTO(out, rc = -ENOENT);
nodemap->nmf_trust_client_ids = trust_client_ids;
+ nm_member_revoke_locks(nodemap);
nodemap_putref(nodemap);
out:
return rc;
GOTO(out, rc = -ENOENT);
nodemap->nm_squash_uid = uid;
+ nm_member_revoke_locks(nodemap);
nodemap_putref(nodemap);
out:
return rc;
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
GOTO(out, rc = -ENOENT);
nodemap->nm_squash_gid = gid;
+ nm_member_revoke_locks(nodemap);
nodemap_putref(nodemap);
out:
return rc;
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
* \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);
* \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;
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);
/**
* Initialize the nodemap module
*/
-static int __init nodemap_mod_init(void)
+int nodemap_mod_init(void)
{
int rc = 0;
if (rc != 0)
goto cleanup;
+ rwlock_init(&nm_range_tree_lock);
nodemap_procfs_init();
rc = nodemap_create(DEFAULT_NODEMAP, 1);
return rc;
}
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Lustre Client Nodemap Management Module");
-MODULE_AUTHOR("Joshua Walgenbach <jjw@iu.edu>");
+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);
#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
}
/**
- * insert idmap into the proper trees
+ * Insert idmap into the proper trees
*
* \param node_type 0 for UID
* 1 for GID
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;
replace = true;
break;
}
-
}
if (!replace) {
replace = true;
break;
}
-
}
}
}
/**
- * delete idmap from the correct nodemap tree
+ * Delete idmap from the correct nodemap tree
*
* \param node_type 0 for UID
* 1 for GID
}
/**
- * 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
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 */
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);
--- /dev/null
+/*
+ * 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 <jjw@iu.edu>
+ */
+
+#define NODEMAP_LPROC_ID_LEN 16
+#define NODEMAP_LPROC_FLAG_LEN 2
+
+#include <lprocfs_status.h>
+#include <lustre_net.h>
+#include <lustre_export.h>
+#include <obd_class.h>
+#include <interval_tree.h>
+#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, "<nodemap name> <nid range>"
+ * \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, "<nodemap name> <nid range>"
+ * \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, "<nodemap name> <uid|gid> <idmap>"
+ * \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, "<nodemap name> <uid|gid> <idmap>"
+ * \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;
+}
--- /dev/null
+/*
+ * 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 <jjw@iu.edu>
+ */
+#include <linux/module.h>
+#include <lustre_net.h>
+#include <obd_class.h>
+#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);
+}
* 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;
#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)
{
{
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)
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:
static void __exit ptlrpc_exit(void)
{
+ nodemap_mod_exit();
ptlrpc_nrs_fini();
sptlrpc_fini();
ldlm_exit();
#include <obd_cksum.h>
#include <md_object.h>
#include <lustre_lfsck.h>
+#include <lustre_nodemap.h>
#include "tgt_internal.h"
struct ost_body *body;
struct req_capsule *pill = tsi->tsi_pill;
struct lustre_capa *capa;
+ struct lu_nodemap *nodemap;
int rc;
ENTRY;
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) {
fi
}
+# ensure that the squash defaults are the expected defaults
+squash_id default 99 0
+squash_id default 99 1
+
test_nid() {
local cmd
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
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
}
if (nodemap_name == NULL || param == NULL || value == NULL) {
- fprintf(stderr, "usage: nodemap_modify --name <name> "
- "--property <range> --value <value>\n");
+ fprintf(stderr, "usage: nodemap_modify --name <nodemap_name> "
+ "--property <property_name> --value <value>\n");
+ fprintf(stderr, "valid properties: admin trusted "
+ "squash_uid squash_gid\n");
return -1;
}
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);
}