int cfs_print_nidlist(char *buffer, int count,
struct list_head *list);
int cfs_match_nid(lnet_nid_t nid, struct list_head *list);
+bool cfs_nidrange_is_contiguous(struct list_head *nidlist);
+void cfs_nidrange_find_min_max(struct list_head *nidlist,
+ char *min_nid, char *max_nid,
+ int nidstr_length);
/** \addtogroup lnet_addr
* @{ */
#endif
#endif
+#define IPSTRING_LENGTH 16
+
/* CAVEAT VENDITOR! Keep the canonical string representation of nets/nids
* consistent in all conversion functions. Some code fragments are copied
* around for the sake of clarity...
static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
static void libcfs_ip_addr2str(__u32 addr, char *str);
static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
+static bool cfs_ip_is_contiguous(struct list_head *nidlist);
+static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
static void libcfs_decnum_addr2str(__u32 addr, char *str);
static void libcfs_hexnum_addr2str(__u32 addr, char *str);
static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
struct list_head *list);
static int libcfs_ip_addr_range_print(char *buffer, int count,
struct list_head *list);
+static bool cfs_num_is_contiguous(struct list_head *nidlist);
+static void cfs_num_min_max(struct list_head *nidlist, __u32 *min, __u32 *max);
struct netstrfns {
int nf_type;
int (*nf_print_addrlist)(char *buffer, int count,
struct list_head *list);
int (*nf_match_addr)(__u32 addr, struct list_head *list);
+ bool (*nf_is_contiguous)(struct list_head *nidlist);
+ void (*nf_min_max)(struct list_head *nidlist, __u32 *min_nid,
+ __u32 *max_nid);
};
static struct netstrfns libcfs_netstrfns[] = {
/* .nf_str2addr */ libcfs_lo_str2addr,
/* .nf_parse_addr*/ libcfs_num_parse,
/* .nf_print_addrlist*/ libcfs_num_addr_range_print,
- /* .nf_match_addr*/ libcfs_num_match},
+ /* .nf_match_addr*/ libcfs_num_match,
+ /* .nf_is_contiguous */ cfs_num_is_contiguous,
+ /* .nf_min_max */ cfs_num_min_max},
{/* .nf_type */ SOCKLND,
/* .nf_name */ "tcp",
/* .nf_modname */ "ksocklnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ O2IBLND,
/* .nf_name */ "o2ib",
/* .nf_modname */ "ko2iblnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ CIBLND,
/* .nf_name */ "cib",
/* .nf_modname */ "kciblnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ OPENIBLND,
/* .nf_name */ "openib",
/* .nf_modname */ "kopeniblnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ IIBLND,
/* .nf_name */ "iib",
/* .nf_modname */ "kiiblnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ VIBLND,
/* .nf_name */ "vib",
/* .nf_modname */ "kviblnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
{/* .nf_type */ RALND,
/* .nf_name */ "ra",
/* .nf_modname */ "kralnd",
/* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
- {/* .nf_type */ QSWLND,
- /* .nf_name */ "elan",
- /* .nf_modname */ "kqswlnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
+ {/* .nf_type */ QSWLND,
+ /* .nf_name */ "elan",
+ /* .nf_modname */ "kqswlnd",
+ /* .nf_addr2str */ libcfs_decnum_addr2str,
+ /* .nf_str2addr */ libcfs_num_str2addr,
+ /* .nf_parse_addrlist*/ libcfs_num_parse,
/* .nf_print_addrlist*/ libcfs_num_addr_range_print,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ GMLND,
- /* .nf_name */ "gm",
- /* .nf_modname */ "kgmlnd",
- /* .nf_addr2str */ libcfs_hexnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
+ /* .nf_match_addr*/ libcfs_num_match,
+ /* .nf_is_contiguous */ cfs_num_is_contiguous,
+ /* .nf_min_max */ cfs_num_min_max},
+ {/* .nf_type */ GMLND,
+ /* .nf_name */ "gm",
+ /* .nf_modname */ "kgmlnd",
+ /* .nf_addr2str */ libcfs_hexnum_addr2str,
+ /* .nf_str2addr */ libcfs_num_str2addr,
+ /* .nf_parse_addrlist*/ libcfs_num_parse,
/* .nf_print_addrlist*/ libcfs_num_addr_range_print,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ MXLND,
- /* .nf_name */ "mx",
- /* .nf_modname */ "kmxlnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
+ /* .nf_match_addr*/ libcfs_num_match,
+ /* .nf_is_contiguous */ cfs_num_is_contiguous,
+ /* .nf_min_max */ cfs_num_min_max},
+ {/* .nf_type */ MXLND,
+ /* .nf_name */ "mx",
+ /* .nf_modname */ "kmxlnd",
+ /* .nf_addr2str */ libcfs_ip_addr2str,
+ /* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
- {/* .nf_type */ PTLLND,
- /* .nf_name */ "ptl",
- /* .nf_modname */ "kptllnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
+ {/* .nf_type */ PTLLND,
+ /* .nf_name */ "ptl",
+ /* .nf_modname */ "kptllnd",
+ /* .nf_addr2str */ libcfs_decnum_addr2str,
+ /* .nf_str2addr */ libcfs_num_str2addr,
+ /* .nf_parse_addrlist*/ libcfs_num_parse,
/* .nf_print_addrlist*/ libcfs_num_addr_range_print,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ GNILND,
- /* .nf_name */ "gni",
- /* .nf_modname */ "kgnilnd",
- /* .nf_addr2str */ libcfs_decnum_addr2str,
- /* .nf_str2addr */ libcfs_num_str2addr,
- /* .nf_parse_addrlist*/ libcfs_num_parse,
+ /* .nf_match_addr*/ libcfs_num_match,
+ /* .nf_is_contiguous */ cfs_num_is_contiguous,
+ /* .nf_min_max */ cfs_num_min_max},
+ {/* .nf_type */ GNILND,
+ /* .nf_name */ "gni",
+ /* .nf_modname */ "kgnilnd",
+ /* .nf_addr2str */ libcfs_decnum_addr2str,
+ /* .nf_str2addr */ libcfs_num_str2addr,
+ /* .nf_parse_addrlist*/ libcfs_num_parse,
/* .nf_print_addrlist*/ libcfs_num_addr_range_print,
- /* .nf_match_addr*/ libcfs_num_match},
- {/* .nf_type */ GNIIPLND,
- /* .nf_name */ "gip",
- /* .nf_modname */ "kgnilnd",
- /* .nf_addr2str */ libcfs_ip_addr2str,
- /* .nf_str2addr */ libcfs_ip_str2addr,
+ /* .nf_match_addr*/ libcfs_num_match,
+ /* .nf_is_contiguous */ cfs_num_is_contiguous,
+ /* .nf_min_max */ cfs_num_min_max},
+ {/* .nf_type */ GNIIPLND,
+ /* .nf_name */ "gip",
+ /* .nf_modname */ "kgnilnd",
+ /* .nf_addr2str */ libcfs_ip_addr2str,
+ /* .nf_str2addr */ libcfs_ip_str2addr,
/* .nf_parse_addrlist*/ cfs_ip_addr_parse,
/* .nf_print_addrlist*/ libcfs_ip_addr_range_print,
- /* .nf_match_addr*/ cfs_ip_addr_match},
- /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
- {/* .nf_type */ -1},
+ /* .nf_match_addr*/ cfs_ip_addr_match,
+ /* .nf_is_contiguous */ cfs_ip_is_contiguous,
+ /* .nf_min_max */ cfs_ip_min_max},
+ /* placeholder for net0 alias. It MUST BE THE LAST ENTRY */
+ {/* .nf_type */ -1},
};
const int libcfs_nnetstrfns = sizeof(libcfs_netstrfns)/sizeof(libcfs_netstrfns[0]);
RETURN(i);
}
+/**
+ * Determines minimum and maximum addresses for a single
+ * numeric address range
+ *
+ * \param ar
+ * \param min_nid
+ * \param max_nid
+ */
+static void cfs_ip_ar_min_max(struct addrrange *ar, __u32 *min_nid,
+ __u32 *max_nid)
+{
+ struct cfs_expr_list *el;
+ struct cfs_range_expr *re;
+ __u32 tmp_ip_addr = 0;
+ unsigned int min_ip[4] = {0};
+ unsigned int max_ip[4] = {0};
+ int re_count = 0;
+
+ list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
+ list_for_each_entry(re, &el->el_exprs, re_link) {
+ min_ip[re_count] = re->re_lo;
+ max_ip[re_count] = re->re_hi;
+ re_count++;
+ }
+ }
+
+ tmp_ip_addr = ((min_ip[0] << 24) | (min_ip[1] << 16) |
+ (min_ip[2] << 8) | min_ip[3]);
+
+ if (min_nid != NULL)
+ *min_nid = tmp_ip_addr;
+
+ tmp_ip_addr = ((max_ip[0] << 24) | (max_ip[1] << 16) |
+ (max_ip[2] << 8) | max_ip[3]);
+
+ if (max_nid != NULL)
+ *max_nid = tmp_ip_addr;
+}
+
+/**
+ * Determines minimum and maximum addresses for a single
+ * numeric address range
+ *
+ * \param ar
+ * \param min_nid
+ * \param max_nid
+ */
+static void cfs_num_ar_min_max(struct addrrange *ar, __u32 *min_nid,
+ __u32 *max_nid)
+{
+ struct cfs_expr_list *el;
+ struct cfs_range_expr *re;
+ unsigned int min_addr = 0;
+ unsigned int max_addr = 0;
+
+ list_for_each_entry(el, &ar->ar_numaddr_ranges, el_link) {
+ list_for_each_entry(re, &el->el_exprs, re_link) {
+ if (re->re_lo < min_addr || min_addr == 0)
+ min_addr = re->re_lo;
+ if (re->re_hi > max_addr)
+ max_addr = re->re_hi;
+ }
+ }
+
+ if (min_nid != NULL)
+ *min_nid = min_addr;
+ if (max_nid != NULL)
+ *max_nid = max_addr;
+}
+
+/**
+ * Determines whether an expression list in an nidrange contains exactly
+ * one contiguous address range. Calls the correct netstrfns for the LND
+ *
+ * \param *nidlist
+ *
+ * \retval true if contiguous
+ * \retval false if not contiguous
+ */
+bool cfs_nidrange_is_contiguous(struct list_head *nidlist)
+{
+ struct nidrange *nr;
+ struct netstrfns *nf = NULL;
+ char *lndname = NULL;
+ int netnum = -1;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ nf = nr->nr_netstrfns;
+ if (lndname == NULL)
+ lndname = nf->nf_name;
+ if (netnum == -1)
+ netnum = nr->nr_netnum;
+
+ if (strcmp(lndname, nf->nf_name) != 0 ||
+ netnum != nr->nr_netnum)
+ return false;
+ }
+
+ if (nf == NULL)
+ return false;
+
+ if (!nf->nf_is_contiguous(nidlist))
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL(cfs_nidrange_is_contiguous);
+
+/**
+ * Determines whether an expression list in an num nidrange contains exactly
+ * one contiguous address range.
+ *
+ * \param *nidlist
+ *
+ * \retval true if contiguous
+ * \retval false if not contiguous
+ */
+static bool cfs_num_is_contiguous(struct list_head *nidlist)
+{
+ struct nidrange *nr;
+ struct addrrange *ar;
+ struct cfs_expr_list *el;
+ struct cfs_range_expr *re;
+ int last_hi = 0;
+ __u32 last_end_nid = 0;
+ __u32 current_start_nid = 0;
+ __u32 current_end_nid = 0;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
+ cfs_num_ar_min_max(ar, ¤t_start_nid,
+ ¤t_end_nid);
+ if (last_end_nid != 0 &&
+ (current_start_nid - last_end_nid != 1))
+ return false;
+ last_end_nid = current_end_nid;
+ list_for_each_entry(el, &ar->ar_numaddr_ranges,
+ el_link) {
+ list_for_each_entry(re, &el->el_exprs,
+ re_link) {
+ if (re->re_stride > 1)
+ return false;
+ else if (last_hi != 0 &&
+ re->re_hi - last_hi != 1)
+ return false;
+ last_hi = re->re_hi;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Determines whether an expression list in an ip nidrange contains exactly
+ * one contiguous address range.
+ *
+ * \param *nidlist
+ *
+ * \retval true if contiguous
+ * \retval false if not contiguous
+ */
+static bool cfs_ip_is_contiguous(struct list_head *nidlist)
+{
+ struct nidrange *nr;
+ struct addrrange *ar;
+ struct cfs_expr_list *el;
+ struct cfs_range_expr *re;
+ int expr_count;
+ int last_hi = 255;
+ int last_diff = 0;
+ __u32 last_end_nid = 0;
+ __u32 current_start_nid = 0;
+ __u32 current_end_nid = 0;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
+ last_hi = 255;
+ last_diff = 0;
+ cfs_ip_ar_min_max(ar, ¤t_start_nid,
+ ¤t_end_nid);
+ if (last_end_nid != 0 &&
+ (current_start_nid - last_end_nid != 1))
+ return false;
+ last_end_nid = current_end_nid;
+ list_for_each_entry(el,
+ &ar->ar_numaddr_ranges,
+ el_link) {
+ expr_count = 0;
+ list_for_each_entry(re, &el->el_exprs,
+ re_link) {
+ expr_count++;
+ if (re->re_stride > 1 ||
+ (last_diff > 0 && last_hi != 255) ||
+ (last_diff > 0 && last_hi == 255 &&
+ re->re_lo > 0))
+ return false;
+ last_hi = re->re_hi;
+ last_diff = re->re_hi - re->re_lo;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Takes a linked list of nidrange expressions, determines the minimum
+ * and maximum nid and creates appropriate nid structures
+ *
+ * \param *nidlist
+ * \param *min_nid
+ * \param *max_nid
+ */
+void cfs_nidrange_find_min_max(struct list_head *nidlist, char *min_nid,
+ char *max_nid, int nidstr_length)
+{
+ struct nidrange *nr;
+ struct netstrfns *nf = NULL;
+ int netnum = -1;
+ __u32 min_addr;
+ __u32 max_addr;
+ char *lndname = NULL;
+ char min_addr_str[IPSTRING_LENGTH];
+ char max_addr_str[IPSTRING_LENGTH];
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ nf = nr->nr_netstrfns;
+ lndname = nf->nf_name;
+ if (netnum == -1)
+ netnum = nr->nr_netnum;
+
+ nf->nf_min_max(nidlist, &min_addr, &max_addr);
+ }
+ nf->nf_addr2str(min_addr, min_addr_str);
+ nf->nf_addr2str(max_addr, max_addr_str);
+
+ snprintf(min_nid, nidstr_length, "%s@%s%d", min_addr_str, lndname,
+ netnum);
+ snprintf(max_nid, nidstr_length, "%s@%s%d", max_addr_str, lndname,
+ netnum);
+}
+EXPORT_SYMBOL(cfs_nidrange_find_min_max);
+
+/**
+ * Determines the min and max NID values for num LNDs
+ *
+ * \param *nidlist
+ * \param *min_nid
+ * \param *max_nid
+ */
+static void cfs_num_min_max(struct list_head *nidlist, __u32 *min_nid,
+ __u32 *max_nid)
+{
+ struct nidrange *nr;
+ struct addrrange *ar;
+ unsigned int tmp_min_addr = 0;
+ unsigned int tmp_max_addr = 0;
+ unsigned int min_addr = 0;
+ unsigned int max_addr = 0;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
+ cfs_num_ar_min_max(ar, &tmp_min_addr,
+ &tmp_max_addr);
+ if (tmp_min_addr < min_addr || min_addr == 0)
+ min_addr = tmp_min_addr;
+ if (tmp_max_addr > max_addr)
+ max_addr = tmp_min_addr;
+ }
+ }
+ *max_nid = max_addr;
+ *min_nid = min_addr;
+}
+
+/**
+ * Takes an nidlist and determines the minimum and maximum
+ * ip addresses.
+ *
+ * \param *nidlist
+ * \param *min_nid
+ * \param *max_nid
+ */
+static void cfs_ip_min_max(struct list_head *nidlist, __u32 *min_nid,
+ __u32 *max_nid)
+{
+ struct nidrange *nr;
+ struct addrrange *ar;
+ __u32 tmp_min_ip_addr = 0;
+ __u32 tmp_max_ip_addr = 0;
+ __u32 min_ip_addr = 0;
+ __u32 max_ip_addr = 0;
+
+ list_for_each_entry(nr, nidlist, nr_link) {
+ list_for_each_entry(ar, &nr->nr_addrranges, ar_link) {
+ cfs_ip_ar_min_max(ar, &tmp_min_ip_addr,
+ &tmp_max_ip_addr);
+ if (tmp_min_ip_addr < min_ip_addr || min_ip_addr == 0)
+ min_ip_addr = tmp_min_ip_addr;
+ if (tmp_max_ip_addr > max_ip_addr)
+ max_ip_addr = tmp_max_ip_addr;
+ }
+ }
+
+ if (min_nid != NULL)
+ *min_nid = min_ip_addr;
+ if (max_nid != NULL)
+ *max_nid = max_ip_addr;
+}
+
#ifdef __KERNEL__
EXPORT_SYMBOL(libcfs_isknown_lnd);
subdir-m += ptlrpc
subdir-m += obdecho
subdir-m += mgc
-subdir-m += nodemap
@SERVER_TRUE@subdir-m += ost mgs mdt mdd ofd quota osp lod lfsck nodemap
@CLIENT_TRUE@subdir-m += lov osc mdc lmv llite fld
LCFG_NODEMAP_SQUASH_GID = 0x00ce052, /**< default map gid */
LCFG_NODEMAP_ADD_SHKEY = 0x00ce053, /**< add shared key to cluster */
LCFG_NODEMAP_DEL_SHKEY = 0x00ce054, /**< delete shared key from cluster */
+ LCFG_NODEMAP_TEST_NID = 0x00ce055, /**< test for nodemap membership */
};
struct lustre_cfg_bufs {
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_parse_range(const char *range_string, lnet_nid_t range[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);
#endif
struct mgs_device *mgs,
struct obd_ioctl_data *data)
{
- struct lustre_cfg *lcfg = NULL;
- const char *nodemap_name;
- char *param = NULL;
- __u32 cmd;
- int rc = 0;
+ struct lustre_cfg *lcfg = NULL;
+ struct lu_nodemap *nodemap;
+ lnet_nid_t nid;
+ const char *nodemap_name = NULL;
+ const char *nidstr = NULL;
+ char *param = NULL;
+ int rc = 0;
+ __u32 cmd;
+
ENTRY;
if (data->ioc_type != LUSTRE_CFG_TYPE) {
if (copy_from_user(lcfg, data->ioc_pbuf1, data->ioc_plen1))
GOTO(out_lcfg, rc = -EFAULT);
- nodemap_name = lustre_cfg_string(lcfg, 1);
cmd = lcfg->lcfg_command;
switch (cmd) {
case LCFG_NODEMAP_DEL:
if (lcfg->lcfg_bufcount != 2)
GOTO(out_lcfg, rc = -EINVAL);
+ nodemap_name = lustre_cfg_string(lcfg, 1);
rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
break;
+ case LCFG_NODEMAP_TEST_NID:
+ if (lcfg->lcfg_bufcount != 2)
+ GOTO(out_lcfg, rc = -EINVAL);
+ nidstr = lustre_cfg_string(lcfg, 1);
+ nid = libcfs_str2nid(nidstr);
+ nodemap = nodemap_classify_nid(nid);
+ memset(data->ioc_pbuf1, 0, data->ioc_plen1);
+ if (copy_to_user(data->ioc_pbuf1, nodemap->nm_name,
+ strlen(nodemap->nm_name)) != 0)
+ GOTO(out_lcfg, rc = -EFAULT);
+ break;
+ case LCFG_NODEMAP_ADD_RANGE:
+ case LCFG_NODEMAP_DEL_RANGE:
+ if (lcfg->lcfg_bufcount != 3)
+ GOTO(out_lcfg, rc = -EINVAL);
+ nodemap_name = lustre_cfg_string(lcfg, 1);
+ param = lustre_cfg_string(lcfg, 2);
+ rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
+ break;
+ case LCFG_NODEMAP_ADMIN:
+ case LCFG_NODEMAP_TRUSTED:
+ case LCFG_NODEMAP_SQUASH_UID:
+ case LCFG_NODEMAP_SQUASH_GID:
+ if (lcfg->lcfg_bufcount != 4)
+ GOTO(out_lcfg, rc = -EINVAL);
+ nodemap_name = lustre_cfg_string(lcfg, 1);
+ param = lustre_cfg_string(lcfg, 3);
+ rc = mgs_nodemap_cmd(env, mgs, cmd, nodemap_name, param);
+ break;
+
default:
rc = -ENOTTY;
}
enum lcfg_command_type cmd, const char *nodemap_name,
const char *param)
{
- int rc = 0;
+ lnet_nid_t nid[2];
+ bool bool_switch;
+ __u32 int_id;
+ int rc = 0;
ENTRY;
switch (cmd) {
case LCFG_NODEMAP_DEL:
rc = nodemap_del(nodemap_name);
break;
+ case LCFG_NODEMAP_ADD_RANGE:
+ rc = nodemap_parse_range(param, nid);
+ if (rc != 0)
+ break;
+ rc = nodemap_add_range(nodemap_name, nid);
+ break;
+ case LCFG_NODEMAP_DEL_RANGE:
+ rc = nodemap_parse_range(param, nid);
+ if (rc != 0)
+ break;
+ rc = nodemap_del_range(nodemap_name, nid);
+ break;
+ case LCFG_NODEMAP_ADMIN:
+ bool_switch = simple_strtoul(param, NULL, 10);
+ rc = nodemap_set_allow_root(nodemap_name, bool_switch);
+ break;
+ case LCFG_NODEMAP_TRUSTED:
+ bool_switch = simple_strtoul(param, NULL, 10);
+ rc = nodemap_set_trust_client_ids(nodemap_name, bool_switch);
+ break;
+ case LCFG_NODEMAP_SQUASH_UID:
+ int_id = simple_strtoul(param, NULL, 10);
+ rc = nodemap_set_squash_uid(nodemap_name, int_id);
+ break;
+ case LCFG_NODEMAP_SQUASH_GID:
+ int_id = simple_strtoul(param, NULL, 10);
+ rc = nodemap_set_squash_gid(nodemap_name, int_id);
+ break;
default:
rc = -EINVAL;
}
MODULES := nodemap
-nodemap-objs := nodemap_handler.o nodemap_lproc.o
+nodemap-objs := nodemap_handler.o nodemap_lproc.o nodemap_range.o
@INCLUDE_RULES@
*/
static void nodemap_destroy(struct lu_nodemap *nodemap)
{
- lprocfs_remove(&(nodemap->nm_proc_entry));
+ struct lu_nid_range *range;
+ struct lu_nid_range *temp;
+
+ list_for_each_entry_safe(range, temp, &nodemap->nm_ranges,
+ rn_list) {
+ range_delete(range);
+ }
+
+ lprocfs_remove(&nodemap->nm_proc_entry);
OBD_FREE_PTR(nodemap);
}
struct lu_nodemap *nodemap;
nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+
return nodemap->nm_name;
}
struct lu_nodemap *nodemap;
nodemap = nodemap_hs_key(compared_hnode);
+
return !strcmp(key, nodemap->nm_name);
}
*/
static bool nodemap_name_is_valid(const char *name)
{
+ if (strlen(name) > LUSTRE_NODEMAP_NAME_LENGTH ||
+ strlen(name) == 0)
+ return false;
+
for (; *name != '\0'; name++) {
if (!isalnum(*name) && *name != '_')
return false;
* Look nodemap up in the nodemap hash
*
* \param name name of nodemap
- * \paramA nodemap found nodemap or NULL
+ * \param nodemap found nodemap or NULL
* \retval lu_nodemap named nodemap
* \retval NULL nodemap doesn't exist
*/
{
int rc = 0;
+ *nodemap = NULL;
+
if (!nodemap_name_is_valid(name))
GOTO(out, rc = -EINVAL);
*nodemap = cfs_hash_lookup(nodemap_hash, name);
+ if (*nodemap == NULL)
+ rc = -ENOENT;
+
+out:
+ return rc;
+}
+
+/**
+ * classify the nid into the proper nodemap
+ *
+ * \param nid nid to classify
+ * \retval nodemap nodemap containing the nid
+ * \retval default_nodemap default nodemap
+ */
+struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
+{
+ struct lu_nid_range *range;
+
+ range = range_search(nid);
+ if (range != NULL)
+ return range->rn_nodemap;
+ return default_nodemap;
+}
+EXPORT_SYMBOL(nodemap_classify_nid);
+
+/*
+ * simple check for default nodemap
+ */
+static bool is_default_nodemap(const struct lu_nodemap *nodemap)
+{
+ return nodemap->nm_id == 0;
+}
+
+/*
+ * parse a nodemap range string into two nids
+ *
+ * \param range_str string to parse
+ * \param range[2] array of two nids
+ * \reyval 0 on success
+ */
+int nodemap_parse_range(const char *range_str, lnet_nid_t range[2])
+{
+ char buf[LNET_NIDSTR_SIZE * 2 + 2];
+ char *ptr = NULL;
+ char *start_nidstr;
+ char *end_nidstr;
+ int rc = 0;
+
+ snprintf(buf, sizeof(buf), "%s", range_str);
+ ptr = buf;
+ start_nidstr = strsep(&ptr, ":");
+ end_nidstr = strsep(&ptr, ":");
+
+ if (start_nidstr == NULL || end_nidstr == NULL)
+ GOTO(out, rc = -EINVAL);
+
+ range[0] = libcfs_str2nid(start_nidstr);
+ range[1] = libcfs_str2nid(end_nidstr);
+
+out:
+ return rc;
+
+}
+EXPORT_SYMBOL(nodemap_parse_range);
+
+/*
+ * add nid range to nodemap
+ * \param name nodemap name
+ * \param range_st string containing nid range
+ * \retval 0 on success
+ *
+ * add an range to the global range tree and attached the
+ * range to the named nodemap.
+ */
+int nodemap_add_range(const char *name, const lnet_nid_t nid[2])
+{
+ struct lu_nodemap *nodemap = NULL;
+ struct lu_nid_range *range;
+ int rc;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL || is_default_nodemap(nodemap))
+ GOTO(out, rc = -EINVAL);
+
+ range = range_create(nid[0], nid[1], nodemap);
+ if (range == NULL)
+ GOTO(out_putref, rc = -ENOMEM);
+
+ rc = range_insert(range);
+ if (rc != 0) {
+ CERROR("cannot insert nodemap range into '%s': rc = %d\n",
+ nodemap->nm_name, rc);
+ list_del(&range->rn_list);
+ range_destroy(range);
+ GOTO(out_putref, rc = -ENOMEM);
+ }
+
+ list_add(&range->rn_list, &nodemap->nm_ranges);
+
+out_putref:
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_add_range);
+
+/**
+ * delete a range
+ * \param name nodemap name
+ * \param range_str string containing range
+ * \retval 0 on success
+ *
+ * Delete range from global range tree, and remove it
+ * from the list in the associated nodemap.
+ */
+int nodemap_del_range(const char *name, const lnet_nid_t nid[2])
+{
+ struct lu_nodemap *nodemap;
+ struct lu_nid_range *range;
+ int rc = 0;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL || is_default_nodemap(nodemap))
+ GOTO(out, rc = -EINVAL);
+
+ range = range_find(nid[0], nid[1]);
+ if (range == NULL)
+ GOTO(out_putref, rc = -EINVAL);
+
+ range_delete(range);
+
+out_putref:
+ nodemap_putref(nodemap);
out:
return rc;
}
+EXPORT_SYMBOL(nodemap_del_range);
/**
* Nodemap constructor
int rc = 0;
rc = nodemap_lookup(name, &nodemap);
- if (rc < 0)
+ if (rc == -EINVAL)
goto out;
- if (nodemap != NULL) {
+ if (rc != -ENOENT) {
nodemap_putref(nodemap);
GOTO(out, rc = -EEXIST);
}
-
OBD_ALLOC_PTR(nodemap);
if (nodemap == NULL) {
return rc;
}
+/*
+ * update flag to turn on or off nodemap functions
+ * \param name nodemap name
+ * \param admin_string string containing updated value
+ * \retval 0 on success
+ *
+ * Update admin flag to turn on or off nodemap functions.
+ */
+int nodemap_set_allow_root(const char *name, bool allow_root)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc = 0;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL)
+ GOTO(out, rc = -ENOENT);
+
+ nodemap->nmf_allow_root_access = allow_root;
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_allow_root);
+
+/**
+ * updated trust_client_ids flag for nodemap
+ *
+ * \param name nodemap name
+ * \param trust_string new value for trust flag
+ * \retval 0 on success
+ *
+ * Update the trust_client_ids flag for a nodemap.
+ */
+int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc = 0;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL)
+ GOTO(out, rc = -ENOENT);
+
+ nodemap->nmf_trust_client_ids = trust_client_ids;
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_trust_client_ids);
+
+/**
+ * update the squash_uid for a nodemap
+ *
+ * \param name nodemap name
+ * \param uid_string string containing new squash_uid value
+ * \retval 0 on success
+ *
+ * Update the squash_uid for a nodemap. The squash_uid is the uid
+ * that the all client uids are mapped to if nodemap is active,
+ * the trust_client_ids flag is not set, and the uid is not in
+ * the idmap tree.
+ */
+int nodemap_set_squash_uid(const char *name, uid_t uid)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc = 0;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL)
+ GOTO(out, rc = -ENOENT);
+
+ nodemap->nm_squash_uid = uid;
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_squash_uid);
+
+/**
+ * update the squash_gid for a nodemap
+ *
+ * \param name nodemap name
+ * \param gid_string string containing new squash_gid value
+ * \retval 0 on success
+ *
+ * Update the squash_gid for a nodemap. The squash_uid is the gid
+ * that the all client gids are mapped to if nodemap is active,
+ * the trust_client_ids flag is not set, and the gid is not in
+ * the idmap tree.
+ */
+int nodemap_set_squash_gid(const char *name, gid_t gid)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc = 0;
+
+ rc = nodemap_lookup(name, &nodemap);
+ if (nodemap == NULL)
+ GOTO(out, rc = -ENOENT);
+
+ nodemap->nm_squash_gid = gid;
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_squash_gid);
+
/**
* Add a nodemap
*
#define _NODEMAP_INTERNAL_H
#include <lustre_nodemap.h>
+#include <interval_tree.h>
#define MODULE_STRING "nodemap"
/* flag if nodemap is active */
extern bool nodemap_idmap_active;
+struct lu_nid_range {
+ /* unique id set my mgs */
+ unsigned int rn_id;
+ /* lu_nodemap containing this range */
+ struct lu_nodemap *rn_nodemap;
+ /* list for nodemap */
+ struct list_head rn_list;
+ /* nid interval tree */
+ struct interval_node rn_node;
+};
+
int nodemap_procfs_init(void);
int lprocfs_nodemap_register(const char *name, bool is_default_nodemap,
struct lu_nodemap *nodemap);
+struct lu_nid_range *range_create(lnet_nid_t min, lnet_nid_t max,
+ struct lu_nodemap *nodemap);
+void range_destroy(struct lu_nid_range *range);
+int range_insert(struct lu_nid_range *data);
+void range_delete(struct lu_nid_range *data);
+struct lu_nid_range *range_search(lnet_nid_t nid);
+struct lu_nid_range *range_find(lnet_nid_t start_nid, lnet_nid_t end_nid);
+int range_parse_nidstring(char *range_string, lnet_nid_t *start_nid,
+ lnet_nid_t *end_nid);
+void range_init_tree(void);
int nodemap_cleanup_nodemaps(void);
#endif /* _NODEMAP_INTERNAL_H */
#define NODEMAP_LPROC_ID_LEN 16
#define NODEMAP_LPROC_FLAG_LEN 2
-#define NODEMAP_PROC_DEBUG 1
-
#include <lprocfs_status.h>
#include <lustre_net.h>
+#include <interval_tree.h>
#include "nodemap_internal.h"
+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;
+
+
+ list_for_each_entry(range, &nodemap->nm_ranges, rn_list) {
+ ext = range->rn_node.in_extent;
+ seq_printf(m, "id: %u: { start_nid: %s, "
+ "end_nid: %s }\n",
+ range->rn_id, libcfs_nid2str(ext.start),
+ libcfs_nid2str(ext.end));
+ }
+
+ return 0;
+}
+
+static int nodemap_ranges_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *dir;
+ struct lu_nodemap *nodemap;
+
+ dir = PDE(inode);
+ nodemap = dir->data;
+
+ 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_idmap_active);
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
+};
+
static struct lprocfs_seq_vars lprocfs_nodemap_vars[] = {
{
.name = "id",
.fops = &nodemap_squash_gid_fops,
},
{
+ .name = "ranges",
+ .fops = &nodemap_ranges_fops,
+ },
+ {
NULL
}
};
--- /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 <interval_tree.h>
+#include <lustre_net.h>
+#include "nodemap_internal.h"
+
+/*
+ * Range trees
+ *
+ * To classify clients when they connect, build a global range tree
+ * containing all admin defined ranges. Incoming clients can then be
+ * 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
+ */
+
+static struct interval_node *range_interval_root;
+static atomic_t range_highest_id;
+
+void range_init_tree(void)
+{
+ range_interval_root = NULL;
+}
+
+/*
+ * callback for interating over the interval tree
+ *
+ * \param n interval_node matched
+ * \param data void pointer for return
+ *
+ * This dunction stops after a single match. There should be
+ * no intervals containing multiple ranges
+ */
+static enum interval_iter range_cb(struct interval_node *n, void *data)
+{
+ struct lu_nid_range *range = container_of(n, struct lu_nid_range,
+ rn_node);
+ struct lu_nid_range **ret;
+
+ ret = data;
+ *ret = range;
+
+ return INTERVAL_ITER_STOP;
+}
+
+/*
+ * range constructor
+ *
+ * \param min starting nid of the range
+ * \param max ending nid of the range
+ * \param nodemap nodemap that contains this range
+ * \retval lu_nid_range on success, NULL on failure
+ */
+struct lu_nid_range *range_create(lnet_nid_t start_nid, lnet_nid_t end_nid,
+ struct lu_nodemap *nodemap)
+{
+ struct lu_nid_range *range;
+
+ if (LNET_NIDNET(start_nid) != LNET_NIDNET(end_nid) ||
+ LNET_NIDADDR(start_nid) > LNET_NIDADDR(end_nid))
+ return NULL;
+
+ OBD_ALLOC_PTR(range);
+ if (range == NULL) {
+ CERROR("cannot allocate lu_nid_range of size %zu bytes\n",
+ sizeof(*range));
+ return NULL;
+ }
+
+ range->rn_id = atomic_inc_return(&range_highest_id);
+ range->rn_nodemap = nodemap;
+ interval_set(&range->rn_node, start_nid, end_nid);
+ INIT_LIST_HEAD(&range->rn_list);
+
+ return range;
+}
+
+/*
+ * find the exact range
+ *
+ * \param start_nid starting nid
+ * \param end_nid ending nid
+ * \retval matching range or NULL
+ */
+struct lu_nid_range *range_find(lnet_nid_t start_nid, lnet_nid_t end_nid)
+{
+ struct lu_nid_range *range = NULL;
+ struct interval_node *interval = NULL;
+ struct interval_node_extent ext = {
+ .start = start_nid,
+ .end = end_nid
+ };
+
+ interval = interval_find(range_interval_root, &ext);
+
+ if (interval != NULL)
+ range = container_of(interval, struct lu_nid_range,
+ rn_node);
+
+ return range;
+}
+
+/*
+ * range destructor
+ */
+void range_destroy(struct lu_nid_range *range)
+{
+ LASSERT(list_empty(&range->rn_list) == 0);
+ LASSERT(interval_is_intree(&range->rn_node) == 0);
+
+ OBD_FREE_PTR(range);
+}
+
+/*
+ * insert an nid range into the interval tree
+ *
+ * \param range range to insetr
+ * \retval 0 on success
+ *
+ * This function checks that the given nid range
+ * does not overlap so that each nid can belong
+ * to exactly one range
+ */
+int range_insert(struct lu_nid_range *range)
+{
+ struct interval_node_extent ext =
+ range->rn_node.in_extent;
+
+ if (interval_is_overlapped(range_interval_root, &ext) != 0)
+ return -EEXIST;
+
+ interval_insert(&range->rn_node, &range_interval_root);
+
+ return 0;
+}
+
+/*
+ * delete a range from the interval tree and any
+ * associated nodemap references
+ *
+ * \param range range to remove
+ */
+void range_delete(struct lu_nid_range *range)
+{
+ if (range == NULL || interval_is_intree(&range->rn_node) == 0)
+ return;
+ list_del(&range->rn_list);
+ interval_erase(&range->rn_node, &range_interval_root);
+ range_destroy(range);
+}
+
+/*
+ * search the interval tree for an nid within a range
+ *
+ * \param nid nid to search for
+ */
+struct lu_nid_range *range_search(lnet_nid_t nid)
+{
+ struct lu_nid_range *ret = NULL;
+ struct interval_node_extent ext = {
+ .start = nid,
+ .end = nid
+ };
+
+ interval_search(range_interval_root, &ext, range_cb, &ret);
+
+ return ret;
+}
PERM_CONF=$CONFDIR/perm.conf
FAIL_ON_ERROR=false
-HN=$(hostname | sum | awk '{ print $1 }')
+HOSTNAME_CHECKSUM=$(hostname | sum | awk '{ print $1 }')
+SUBNET_CHECKSUM=$(expr $HOSTNAME_CHECKSUM % 250 + 1)
NODEMAP_COUNT=10
NODEMAP_RANGE_COUNT=3
NODEMAP_IPADDR_COUNT=30
local rc
for (( i = 0; i < NODEMAP_COUNT; i++ )); do
- if ! do_facet mgs $LCTL nodemap_add ${HN}_${i}; then
+ if ! do_facet mgs $LCTL nodemap_add \
+ ${HOSTNAME_CHECKSUM}_${i}; then
return 1
fi
- out=$(do_facet mgs $LCTL get_param nodemap.${HN}_${i}.id)
+ out=$(do_facet mgs $LCTL get_param \
+ nodemap.${HOSTNAME_CHECKSUM}_${i}.id)
## This needs to return zero if the following statement is 1
- rc=$(echo $out | grep -c ${HN}_${i})
+ rc=$(echo $out | grep -c ${HOSTNAME_CHECKSUM}_${i})
[[ $rc == 0 ]] && return 1
done
return 0
local rc
for ((i = 0; i < NODEMAP_COUNT; i++)); do
- if ! do_facet mgs $LCTL nodemap_del ${HN}_${i}; then
- error "nodemap_del ${HN}_${i} failed with $rc"
+ if ! do_facet mgs $LCTL nodemap_del \
+ ${HOSTNAME_CHECKSUM}_${i}; then
+ error "nodemap_del ${HOSTNAME_CHECKSUM}_${i} \
+ failed with $rc"
return 3
fi
- out=$(do_facet mgs $LCTL get_param nodemap.${HN}_${i}.id)
- rc=$(echo $out | grep -c ${HN}_${i})
+ out=$(do_facet mgs $LCTL get_param \
+ nodemap.${HOSTNAME_CHECKSUM}_${i}.id)
+ rc=$(echo $out | grep -c ${HOSTNAME_CHECKSUM}_${i})
[[ $rc != 0 ]] && return 1
done
return 0
}
+add_range() {
+ local i
+ local j
+ local cmd="$LCTL nodemap_add_range"
+ local range
+ local rc=0
+
+ for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+ range="$SUBNET_CHECKSUM.${2}.${j}.[1-253]@tcp"
+ if ! do_facet mgs $cmd --name $1 \
+ --range $range; then
+ rc=$(($rc + 1))
+ fi
+ done
+ return $rc
+}
+
+del_range() {
+ local i
+ local j
+ local cmd="$LCTL nodemap_del_range"
+ local range
+ local rc=0
+
+ for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+ range="$SUBNET_CHECKSUM.${2}.${j}.[1-253]@tcp"
+ if ! do_facet mgs $cmd --name $1 \
+ --range $range; then
+ rc=$(($rc + 1))
+ fi
+ done
+ return $rc
+}
+
+modify_flags() {
+ local i
+ local proc
+ local option
+ local cmd="$LCTL nodemap_modify"
+ local rc=0
+
+ proc[0]="admin_nodemap"
+ proc[1]="trusted_nodemap"
+ option[0]="admin"
+ option[1]="trusted"
+
+ for ((idx = 0; idx < 2; idx++)); do
+ if ! do_facet mgs $cmd --name $1 \
+ --property ${option[$idx]} \
+ --value 1; then
+ rc=$((rc + 1))
+ fi
+
+ if ! do_facet mgs $cmd --name $1 \
+ --property ${option[$idx]} \
+ --value 0; then
+ rc=$((rc + 1))
+ fi
+ done
+
+ return $rc
+}
+
+squash_id() {
+ local cmd
+
+ cmd[0]="$LCTL nodemap_modify --property squash_uid"
+ cmd[1]="$LCTL nodemap_modify --property squash_gid"
+
+ if ! do_facet mgs ${cmd[$3]} --name $1 --value $2; then
+ return 1
+ fi
+}
+
+test_nid() {
+ local cmd
+
+ cmd="$LCTL nodemap_test_nid"
+
+ nid=$(do_facet mgs $cmd $1)
+
+ if [ $nid == $2 ]; then
+ return 0
+ fi
+
+ return 1
+}
+
test_7() {
local rc
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
create_nodemaps
rc=$?
[[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
test_8() {
local rc
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
# Set up nodemaps
create_nodemaps
}
run_test 8 "nodemap reject duplicates"
+test_9() {
+ local i
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_add_range failed with $rc" && return 2
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! del_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_del_range failed with $rc" && return 4
+
+ rc=0
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 4
+
+ return 0
+}
+run_test 9 "nodemap range add"
+
+test_10() {
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_add_range failed with $rc" && return 2
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc == 0 ]] && error "nodemap_add_range duplicate add with $rc" &&
+ return 2
+
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! del_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_del_range failed with $rc" && return 4
+
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 5
+
+ return 0
+}
+run_test 10 "nodemap reject duplicate ranges"
+
+test_11() {
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! modify_flags ${HOSTNAME_CHECKSUM}_${i}; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_modify with $rc" && return 2
+
+ rc=0
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_del failed with $rc" && return 3
+
+ return 0
+}
+run_test 11 "nodemap modify"
+
+test_12() {
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! squash_id ${HOSTNAME_CHECKSUM}_${i} 88 0; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap squash_uid with $rc" && return 2
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! squash_id ${HOSTNAME_CHECKSUM}_${i} 88 1; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap squash_gid with $rc" && return 3
+
+ rc=0
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_del failed with $rc" && return 4
+
+ return 0
+}
+run_test 12 "nodemap set squash ids"
+
+test_13() {
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ if ! add_range ${HOSTNAME_CHECKSUM}_${i} $i; then
+ rc=$((rc + 1))
+ fi
+ done
+ [[ $rc != 0 ]] && error "nodemap_add_range failed with $rc" && return 2
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+ for ((k = 1; k < 253; k++)); do
+ if ! test_nid $SUBNET_CHECKSUM.$i.$j.$k \
+ ${HOSTNAME_CHECKSUM}_${i}; then
+ rc=$((rc + 1))
+ fi
+ done
+ done
+ done
+ [[ $rc != 0 ]] && error "nodemap_test_nid failed with $rc" && return 3
+
+ rc=0
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_del failed with $rc" && return 4
+
+ return 0
+}
+run_test 13 "test nids"
+
+test_14() {
+ local rc
+
+ remote_mgs_nodsh && skip "remote MGS with nodsh" && return
+ [ $(lustre_version_code $SINGLEMGS) -lt $(version_code 2.5.53) ] &&
+ skip "No nodemap on $(get_lustre_version) MGS, need 2.5.53+" &&
+ return
+
+ rc=0
+ create_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_add failed with $rc" && return 1
+
+ rc=0
+ for ((i = 0; i < NODEMAP_COUNT; i++)); do
+ for ((j = 0; j < NODEMAP_RANGE_COUNT; j++)); do
+ for ((k = 1; k < 253; k++)); do
+ if ! test_nid $SUBNET_CHECKSUM.$i.$j.$k \
+ default; then
+ rc=$((rc + 1))
+ fi
+ done
+ done
+ done
+ [[ $rc != 0 ]] && error "nodemap_test_nid failed with $rc" && return 3
+
+ rc=0
+ delete_nodemaps
+ rc=$?
+ [[ $rc != 0 ]] && error "nodemap_del failed with $rc" && return 4
+
+ return 0
+}
+run_test 14 "test default nodemap nid lookup"
+
+
log "cleanup: ======================================================"
sec_unsetup() {
{"nodemap_del", jt_nodemap_del, 0,
"remove a nodemap\n"
"usage: nodemap_del <nodemap_name>"},
+ {"nodemap_add_range", jt_nodemap_add_range, 0,
+ "add a range to a nodemap\n"
+ "usage: nodemap_add_range <NID range>"},
+ {"nodemap_del_range", jt_nodemap_del_range, 0,
+ "add a range to a nodemap\n"
+ "usage: nodemap_del_range <NID range>"},
+ {"nodemap_modify", jt_nodemap_modify, 0,
+ "modify a nodemap parameters"
+ "usage: nodemap_modify nodemap_name param value"},
+ {"nodemap_test_nid", jt_nodemap_test_nid, 0,
+ "usage: nodemap_test_nid <nid>"},
/* Changelog commands */
{"=== Changelogs ==", jt_noop, 0, "changelog user management"},
#define MAX_THREADS 4096
#define MAX_BASE_ID 0xffffffff
+#define NIDSTRING_LENGTH 64
struct shared_data {
l_mutex_t mutex;
l_cond_t cond;
return rc;
}
-static int nodemap_cmd(enum lcfg_command_type cmd, int num_args, ...)
+/**
+ * Format and send the ioctl to the MGS.
+ *
+ * \param cmd IOCTL to send
+ * \param ret_data void pointer to return anything from
+ * ioctl
+ * \param num_args number of arguments to pack into the
+ * ioctl buffer
+ * \param argv[] variable number of string arguments
+ *
+ * \retval 0 on success
+ */
+static int nodemap_cmd(enum lcfg_command_type cmd, void *ret_data,
+ unsigned int ret_size, ...)
{
- va_list arguments;
- int i;
- const char *args;
- char *arg;
- struct lustre_cfg_bufs bufs;
- struct obd_ioctl_data data;
- struct lustre_cfg *lcfg;
- char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
- int rc = 0;
+ va_list ap;
+ char *arg;
+ int i = 0;
+ struct lustre_cfg_bufs bufs;
+ struct obd_ioctl_data data;
+ struct lustre_cfg *lcfg;
+ char rawbuf[MAX_IOC_BUFLEN];
+ char *buf = rawbuf;
+ int rc = 0;
lustre_cfg_bufs_reset(&bufs, NULL);
- va_start(arguments, num_args);
-
- for (i = 0; i < num_args; i++) {
- args = va_arg(arguments, char *);
- arg = (char *)args;
+ va_start(ap, ret_size);
+ arg = va_arg(ap, char *);
+ while (arg != NULL) {
lustre_cfg_bufs_set_string(&bufs, i, arg);
+ i++;
+ arg = va_arg(ap, char *);
}
-
- va_end(arguments);
+ va_end(ap);
lcfg = lustre_cfg_new(cmd, &bufs);
memset(buf, 0, sizeof(rawbuf));
rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
- if (rc) {
- fprintf(stderr, "error: invalid ioctl\n");
- return rc;
+ if (rc != 0) {
+ fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
+ "rc=%d\n", cmd, errno, rc);
+ goto out;
}
+
rc = l_ioctl(OBD_DEV_ID, OBD_IOC_NODEMAP, buf);
-out:
- if (rc)
- rc = -errno;
+ if (rc != 0) {
+ fprintf(stderr, "error: invalid ioctl: %08x errno: %d with "
+ "rc=%d\n", cmd, errno, rc);
+ goto out;
+ }
+ if (ret_data != NULL) {
+ rc = obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
+ if (rc != 0)
+ goto out;
+
+ memcpy(ret_data, data.ioc_pbuf1, data.ioc_plen1);
+ if (ret_data == NULL || sizeof(ret_data) != ret_size)
+ rc = -errno;
+ }
+out:
lustre_cfg_free(lcfg);
+
return rc;
}
+/**
+ * activate nodemap functions
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] 1 for activate or 0 for deactivate
+ *
+ * \retval 0 on success
+ */
int jt_nodemap_activate(int argc, char **argv)
{
- enum lcfg_command_type cmd;
- int rc = 0;
+ int rc;
- cmd = LCFG_NODEMAP_ACTIVATE;
- rc = nodemap_cmd(cmd, 1, argv[0]);
+ rc = nodemap_cmd(LCFG_NODEMAP_ACTIVATE, NULL, 0, argv[0], NULL);
if (rc != 0) {
errno = -rc;
return rc;
}
+/**
+ * add a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] nodemap name
+ *
+ * \retval 0 on success
+ */
int jt_nodemap_add(int argc, char **argv)
{
- enum lcfg_command_type cmd;
- int rc = 0;
+ int rc;
- cmd = LCFG_NODEMAP_ADD;
rc = llapi_nodemap_exists(argv[1]);
if (rc == 0) {
fprintf(stderr, "error: %s existing nodemap name\n", argv[1]);
return 1;
}
- rc = nodemap_cmd(cmd, 2, argv[0], argv[1]);
+ rc = nodemap_cmd(LCFG_NODEMAP_ADD, NULL, 0, argv[0], argv[1], NULL);
if (rc != 0) {
errno = -rc;
return rc;
}
+/**
+ * delete a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] nodemap name
+ *
+ * \retval 0 on success
+ */
int jt_nodemap_del(int argc, char **argv)
{
- enum lcfg_command_type cmd;
- int rc = 0;
+ int rc;
- cmd = LCFG_NODEMAP_DEL;
rc = llapi_nodemap_exists(argv[1]);
-
if (rc != 0) {
fprintf(stderr, "error: %s not existing nodemap name\n",
argv[1]);
return rc;
}
- rc = nodemap_cmd(cmd, 2, argv[0], argv[1]);
+ rc = nodemap_cmd(LCFG_NODEMAP_DEL, NULL, 0, argv[0], argv[1], NULL);
if (rc != 0) {
errno = -rc;
return rc;
}
+/**
+ * test a nid for nodemap membership
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * argv[0] properly formatted nid
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_test_nid(int argc, char **argv)
+{
+
+ char rawbuf[MAX_IOC_BUFLEN];
+ int rc;
+
+ rc = nodemap_cmd(LCFG_NODEMAP_TEST_NID, &rawbuf, sizeof(rawbuf),
+ argv[0], argv[1], NULL);
+ if (rc == 0)
+ printf("%s\n", (char *)rawbuf);
+
+ return rc;
+}
+
+/**
+ * add an nid range to a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --range properly formatted nid range
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_add_range(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *nodemap_range = NULL;
+ struct list_head nidlist;
+ char min_nid[LNET_NIDSTR_SIZE + 1];
+ char max_nid[LNET_NIDSTR_SIZE + 1];
+ char nid_range[2 * LNET_NIDSTR_SIZE + 2];
+ int rc = 0;
+ int c;
+
+ static struct option long_options[] = {
+ {
+ .name = "name",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'n',
+ },
+ {
+ .name = "range",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'r',
+ },
+ {
+ NULL
+ }
+ };
+
+ INIT_LIST_HEAD(&nidlist);
+
+ while ((c = getopt_long(argc, argv, "n:r:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'r':
+ nodemap_range = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || nodemap_range == NULL) {
+ fprintf(stderr, "usage: nodemap_add_range --name <name> "
+ "--range <range>\n");
+ return -1;
+ }
+
+ if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+ &nidlist) <= 0) {
+ fprintf(stderr, "error: %s: can't parse nid range: %s\n",
+ jt_cmdname(argv[0]), nodemap_range);
+ return -1;
+ }
+
+ if (!cfs_nidrange_is_contiguous(&nidlist)) {
+ fprintf(stderr, "error: %s: nodemap ranges must be "
+ "contiguous\n", jt_cmdname(argv[0]));
+ return -1;
+ }
+
+ cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
+ LNET_NIDSTR_SIZE);
+ snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
+
+ rc = nodemap_cmd(LCFG_NODEMAP_ADD_RANGE, NULL, 0, argv[0],
+ nodemap_name, nid_range, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot add range '%s' to nodemap "
+ "'%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * delete an nid range to a nodemap
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --range properly formatted nid range
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_del_range(int argc, char **argv)
+{
+ char *nodemap_name = NULL;
+ char *nodemap_range = NULL;
+ struct list_head nidlist;
+ char min_nid[LNET_NIDSTR_SIZE + 1];
+ char max_nid[LNET_NIDSTR_SIZE + 1];
+ char nid_range[2 * LNET_NIDSTR_SIZE + 2];
+ int rc = 0;
+ int c;
+
+ static struct option long_options[] = {
+ {
+ .name = "name",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'n',
+ },
+ {
+ .name = "range",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'r',
+ },
+ {
+ NULL
+ }
+ };
+
+ INIT_LIST_HEAD(&nidlist);
+
+ while ((c = getopt_long(argc, argv, "n:r:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'r':
+ nodemap_range = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || nodemap_range == NULL) {
+ fprintf(stderr, "usage: nodemap_del_range --name <name> "
+ "--range <range>\n");
+ return -1;
+ }
+
+ if (cfs_parse_nidlist(nodemap_range, strlen(nodemap_range),
+ &nidlist) <= 0) {
+ fprintf(stderr, "error: %s: can't parse nid range: %s\n",
+ jt_cmdname(argv[0]), nodemap_range);
+ return -1;
+ }
+
+ if (!cfs_nidrange_is_contiguous(&nidlist)) {
+ fprintf(stderr, "error: %s: nodemap ranges must be "
+ "contiguous\n", jt_cmdname(argv[0]));
+ return -1;
+ }
+
+ cfs_nidrange_find_min_max(&nidlist, &min_nid[0], &max_nid[0],
+ LNET_NIDSTR_SIZE);
+ snprintf(nid_range, sizeof(nid_range), "%s:%s", min_nid, max_nid);
+
+ rc = nodemap_cmd(LCFG_NODEMAP_DEL_RANGE, NULL, 0, argv[0],
+ nodemap_name, nid_range, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot delete range '%s' to "
+ "nodemap '%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_range, nodemap_name, rc);
+ }
+
+ return rc;
+}
+
+/**
+ * modify a nodemap's behavior
+ *
+ * \param argc number of args
+ * \param argv[] variable string arguments
+ *
+ * --name nodemap name
+ * --property nodemap property to change
+ * admin, trusted, squash_uid, squash_gid)
+ * --value value to set property
+ *
+ * \retval 0 on success
+ */
+int jt_nodemap_modify(int argc, char **argv)
+{
+ int c;
+ int rc = 0;
+ enum lcfg_command_type cmd = 0;
+ char *nodemap_name = NULL, *param = NULL, *value = NULL;
+
+ static struct option long_options[] = {
+ {
+ .name = "name",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'n',
+ },
+ {
+ .name = "property",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'p',
+ },
+ {
+ .name = "value",
+ .has_arg = required_argument,
+ .flag = 0,
+ .val = 'v',
+ },
+ {
+ NULL
+ }
+ };
+
+ while ((c = getopt_long(argc, argv, "n:p:v:",
+ long_options, NULL)) != -1) {
+ switch (c) {
+ case 'n':
+ nodemap_name = optarg;
+ break;
+ case 'p':
+ param = optarg;
+ break;
+ case 'v':
+ value = optarg;
+ break;
+ }
+ }
+
+ if (nodemap_name == NULL || param == NULL || value == NULL) {
+ fprintf(stderr, "usage: nodemap_modify --name <name> "
+ "--property <range> --value <value>\n");
+ return -1;
+ }
+
+ if (strcmp("admin", param) == 0) {
+ cmd = LCFG_NODEMAP_ADMIN;
+ } else if (strcmp("trusted", param) == 0) {
+ cmd = LCFG_NODEMAP_TRUSTED;
+ } else if (strcmp("squash_uid", param) == 0) {
+ cmd = LCFG_NODEMAP_SQUASH_UID;
+ } else if (strcmp("squash_gid", param) == 0) {
+ cmd = LCFG_NODEMAP_SQUASH_GID;
+ } else {
+ fprintf(stderr, "error: %s: nodemap_modify invalid "
+ "subcommand: %s\n",
+ jt_cmdname(argv[0]), param);
+ return -1;
+ }
+
+ rc = nodemap_cmd(cmd, NULL, 0, argv[0], nodemap_name, param,
+ value, NULL);
+ if (rc != 0) {
+ errno = -rc;
+ fprintf(stderr, "error: %s: cannot modify nodemap '%s' "
+ "to param '%s': value '%s': rc = %d\n",
+ jt_cmdname(argv[0]), nodemap_name, param, value, rc);
+ }
+
+ return rc;
+}
+
/*
* this function tranforms a rule [start-end/step] into an array
* of matching numbers
int jt_nodemap_activate(int argc, char **argv);
int jt_nodemap_add(int argc, char **argv);
int jt_nodemap_del(int argc, char **argv);
+int jt_nodemap_modify(int argc, char **argv);
+int jt_nodemap_add_range(int argc, char **argv);
+int jt_nodemap_test_nid(int argc, char **argv);
+int jt_nodemap_del_range(int argc, char **argv);
int jt_changelog_register(int argc, char **argv);
int jt_changelog_deregister(int argc, char **argv);