From 874f67c06da8304a194df5fc0dd5a2c61937076c Mon Sep 17 00:00:00 2001 From: Gregoire Pichon Date: Wed, 4 Dec 2013 14:57:10 +0100 Subject: [PATCH 1/1] LU-1778 libcfs: add a service that prints a nidlist The libcfs already provides services to parse a string into a nidlist and to match a nid into a nidlist. This patch implements a service that prints a nidlist into a buffer. This is required for instance to print the nosquash_nids parameter of the MDT procfs component. Additionally, this patch fixes a bug in return code of parse_addrange() routine, so that parsing of nids including a * character works fine ('*@elan' for instance). Signed-off-by: Gregoire Pichon Change-Id: I5dbc405e02b8f0f90d45e1a7e44589d5972cc384 Reviewed-on: http://review.whamcloud.com/8479 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Liang Zhen Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- libcfs/include/libcfs/libcfs_private.h | 2 + libcfs/include/libcfs/libcfs_string.h | 3 +- libcfs/libcfs/libcfs_string.c | 83 +++++++++++++++++---- libcfs/libcfs/nidstrings.c | 132 ++++++++++++++++++++++++++++++++- 4 files changed, 201 insertions(+), 19 deletions(-) diff --git a/libcfs/include/libcfs/libcfs_private.h b/libcfs/include/libcfs/libcfs_private.h index a906d9c..7557c62 100644 --- a/libcfs/include/libcfs/libcfs_private.h +++ b/libcfs/include/libcfs/libcfs_private.h @@ -549,6 +549,8 @@ int libcfs_str2anynid(lnet_nid_t *nid, const char *str); char *libcfs_id2str(lnet_process_id_t id); void cfs_free_nidlist(struct list_head *list); int cfs_parse_nidlist(char *str, int len, struct list_head *list); +int cfs_print_nidlist(char *buffer, int count, + struct list_head *list); int cfs_match_nid(lnet_nid_t nid, struct list_head *list); /** \addtogroup lnet_addr diff --git a/libcfs/include/libcfs/libcfs_string.h b/libcfs/include/libcfs/libcfs_string.h index 82c5c27..5afaec7 100644 --- a/libcfs/include/libcfs/libcfs_string.h +++ b/libcfs/include/libcfs/libcfs_string.h @@ -113,6 +113,8 @@ int cfs_str2num_check(char *str, int nob, unsigned *num, int cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max, int single_tok, struct cfs_range_expr **expr); int cfs_expr_list_match(__u32 value, struct cfs_expr_list *expr_list); +int cfs_expr_list_print(char *buffer, int count, + struct cfs_expr_list *expr_list); int cfs_expr_list_values(struct cfs_expr_list *expr_list, int max, __u32 **values); static inline void @@ -125,7 +127,6 @@ cfs_expr_list_values_free(__u32 *values, int num) } void cfs_expr_list_free(struct cfs_expr_list *expr_list); -void cfs_expr_list_print(struct cfs_expr_list *expr_list); int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max, struct cfs_expr_list **elpp); void cfs_expr_list_free_list(struct list_head *list); diff --git a/libcfs/libcfs/libcfs_string.c b/libcfs/libcfs/libcfs_string.c index 1d7a941..ae6a9e3 100644 --- a/libcfs/libcfs/libcfs_string.c +++ b/libcfs/libcfs/libcfs_string.c @@ -419,6 +419,73 @@ cfs_range_expr_parse(struct cfs_lstr *src, unsigned min, unsigned max, EXPORT_SYMBOL(cfs_range_expr_parse); /** + * Print the range expression \a re into specified \a buffer. + * If \a bracketed is true, expression does not need additional + * brackets. + * + * \retval number of characters written + */ +static int +cfs_range_expr_print(char *buffer, int count, struct cfs_range_expr *expr, + bool bracketed) +{ + int i; + char s[] = "["; + char e[] = "]"; + + if (bracketed) + s[0] = e[0] = '\0'; + + if (expr->re_lo == expr->re_hi) + i = cfs_snprintf(buffer, count, "%u", expr->re_lo); + else if (expr->re_stride == 1) + i = cfs_snprintf(buffer, count, "%s%u-%u%s", + s, expr->re_lo, expr->re_hi, e); + else + i = cfs_snprintf(buffer, count, "%s%u-%u/%u%s", + s, expr->re_lo, expr->re_hi, + expr->re_stride, e); + return i; +} + +/** + * Print a list of range expressions (\a expr_list) into specified \a buffer. + * If the list contains several expressions, separate them with comma + * and surround the list with brackets. + * + * \retval number of characters written + */ +int +cfs_expr_list_print(char *buffer, int count, struct cfs_expr_list *expr_list) +{ + struct cfs_range_expr *expr; + int i = 0, j = 0; + int numexprs = 0; + + if (count <= 0) + return 0; + + list_for_each_entry(expr, &expr_list->el_exprs, re_link) + numexprs++; + + if (numexprs > 1) + i += cfs_snprintf(buffer + i, count - i, "["); + + list_for_each_entry(expr, &expr_list->el_exprs, re_link) { + if (j++ != 0) + i += cfs_snprintf(buffer + i, count - i, ","); + i += cfs_range_expr_print(buffer + i, count - i, expr, + numexprs > 1); + } + + if (numexprs > 1) + i += cfs_snprintf(buffer + i, count - i, "]"); + + return i; +} +EXPORT_SYMBOL(cfs_expr_list_print); + +/** * Matches value (\a value) against ranges expression list \a expr_list. * * \retval 1 if \a value matches @@ -508,23 +575,11 @@ cfs_expr_list_free(struct cfs_expr_list *expr_list) } EXPORT_SYMBOL(cfs_expr_list_free); -void -cfs_expr_list_print(struct cfs_expr_list *expr_list) -{ - struct cfs_range_expr *expr; - - list_for_each_entry(expr, &expr_list->el_exprs, re_link) { - CDEBUG(D_WARNING, "%d-%d/%d\n", - expr->re_lo, expr->re_hi, expr->re_stride); - } -} -EXPORT_SYMBOL(cfs_expr_list_print); - /** * Parses \ token of the syntax. * - * \retval 1 if \a str parses to \ | \ - * \retval 0 otherwise + * \retval 0 if \a str parses to \ | \ + * \retval -errno otherwise */ int cfs_expr_list_parse(char *str, int len, unsigned min, unsigned max, diff --git a/libcfs/libcfs/nidstrings.c b/libcfs/libcfs/nidstrings.c index 7606d73..c413636 100644 --- a/libcfs/libcfs/nidstrings.c +++ b/libcfs/libcfs/nidstrings.c @@ -103,6 +103,10 @@ static void libcfs_hexnum_addr2str(__u32 addr, char *str); static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr); static int libcfs_num_parse(char *str, int len, struct list_head *list); static int libcfs_num_match(__u32 addr, struct list_head *list); +static int libcfs_num_addr_range_print(char *buffer, int count, + struct list_head *list); +static int libcfs_ip_addr_range_print(char *buffer, int count, + struct list_head *list); struct netstrfns { int nf_type; @@ -112,6 +116,8 @@ struct netstrfns { int (*nf_str2addr)(const char *str, int nob, __u32 *addr); int (*nf_parse_addrlist)(char *str, int len, struct list_head *list); + int (*nf_print_addrlist)(char *buffer, int count, + struct list_head *list); int (*nf_match_addr)(__u32 addr, struct list_head *list); }; @@ -122,6 +128,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .nf_addr2str */ libcfs_decnum_addr2str, /* .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_type */ SOCKLND, /* .nf_name */ "tcp", @@ -129,6 +136,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ O2IBLND, /* .nf_name */ "o2ib", @@ -136,6 +144,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ CIBLND, /* .nf_name */ "cib", @@ -143,6 +152,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ OPENIBLND, /* .nf_name */ "openib", @@ -150,6 +160,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ IIBLND, /* .nf_name */ "iib", @@ -157,6 +168,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ VIBLND, /* .nf_name */ "vib", @@ -164,6 +176,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ RALND, /* .nf_name */ "ra", @@ -171,6 +184,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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 */ QSWLND, /* .nf_name */ "elan", @@ -178,6 +192,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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", @@ -185,6 +200,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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", @@ -192,6 +208,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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", @@ -199,6 +216,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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", @@ -206,6 +224,7 @@ static struct netstrfns libcfs_netstrfns[] = { /* .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", @@ -658,8 +677,8 @@ libcfs_num_parse(char *str, int len, struct list_head *list) * Allocates struct addrrange and links to \a nidrange via * (nidrange::nr_addrranges) * - * \retval 1 if \a src parses to '*' | \ | \ - * \retval 0 otherwise + * \retval 0 if \a src parses to '*' | \ | \ + * \retval -errno otherwise */ static int parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange) @@ -668,12 +687,12 @@ parse_addrange(const struct cfs_lstr *src, struct nidrange *nidrange) if (src->ls_len == 1 && src->ls_str[0] == '*') { nidrange->nr_all = 1; - return 1; + return 0; } LIBCFS_ALLOC(addrrange, sizeof(struct addrrange)); if (addrrange == NULL) - return 0; + return -ENOMEM; list_add_tail(&addrrange->ar_link, &nidrange->nr_addrranges); INIT_LIST_HEAD(&addrrange->ar_numaddr_ranges); @@ -903,6 +922,110 @@ int cfs_match_nid(lnet_nid_t nid, struct list_head *nidlist) RETURN(0); } +static int +libcfs_num_addr_range_print(char *buffer, int count, struct list_head *list) +{ + int i = 0, j = 0; + struct cfs_expr_list *el; + + list_for_each_entry(el, list, el_link) { + LASSERT(j++ < 1); + i += cfs_expr_list_print(buffer + i, count - i, el); + } + return i; +} + +static int +libcfs_ip_addr_range_print(char *buffer, int count, struct list_head *list) +{ + int i = 0, j = 0; + struct cfs_expr_list *el; + + list_for_each_entry(el, list, el_link) { + LASSERT(j++ < 4); + if (i != 0) + i += cfs_snprintf(buffer + i, count - i, "."); + i += cfs_expr_list_print(buffer + i, count - i, el); + } + return i; +} + + +/** + * Print the network part of the nidrange \a nr into the specified \a buffer. + * + * \retval number of characters written + */ +static int +cfs_print_network(char *buffer, int count, struct nidrange *nr) +{ + struct netstrfns *nf = nr->nr_netstrfns; + + if (nr->nr_netnum == 0) + return cfs_snprintf(buffer, count, "@%s", nf->nf_name); + else + return cfs_snprintf(buffer, count, "@%s%u", + nf->nf_name, nr->nr_netnum); +} + + +/** + * Print a list of addrrange (\a addrranges) into the specified \a buffer. + * At max \a count characters can be printed into \a buffer. + * + * \retval number of characters written + */ +static int +cfs_print_addrranges(char *buffer, int count, struct list_head *addrranges, + struct nidrange *nr) +{ + int i = 0; + struct addrrange *ar; + struct netstrfns *nf = nr->nr_netstrfns; + + list_for_each_entry(ar, addrranges, ar_link) { + if (i != 0) + i += cfs_snprintf(buffer + i, count - i, " "); + i += nf->nf_print_addrlist(buffer + i, count - i, + &ar->ar_numaddr_ranges); + i += cfs_print_network(buffer + i, count - i, nr); + } + return i; +} + + +/** + * Print a list of nidranges (\a nidlist) into the specified \a buffer. + * At max \a count characters can be printed into \a buffer. + * Nidranges are separated by a space character. + * + * \retval number of characters written + */ +int cfs_print_nidlist(char *buffer, int count, struct list_head *nidlist) +{ + int i = 0; + struct nidrange *nr; + ENTRY; + + if (count <= 0) + RETURN(0); + + list_for_each_entry(nr, nidlist, nr_link) { + if (i != 0) + i += cfs_snprintf(buffer + i, count - i, " "); + + if (nr->nr_all != 0) { + LASSERT(list_empty(&nr->nr_addrranges)); + i += cfs_snprintf(buffer + i, count - i, "*"); + i += cfs_print_network(buffer + i, count - i, nr); + } else { + i += cfs_print_addrranges(buffer + i, count - i, + &nr->nr_addrranges, nr); + } + } + RETURN(i); +} + #ifdef __KERNEL__ EXPORT_SYMBOL(libcfs_isknown_lnd); @@ -917,6 +1040,7 @@ EXPORT_SYMBOL(libcfs_id2str); EXPORT_SYMBOL(libcfs_str2anynid); EXPORT_SYMBOL(cfs_free_nidlist); EXPORT_SYMBOL(cfs_parse_nidlist); +EXPORT_SYMBOL(cfs_print_nidlist); EXPORT_SYMBOL(cfs_match_nid); #endif -- 1.8.3.1