From jsimmons at infradead.org Mon Oct 1 02:06:17 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 1 Oct 2018 03:06:17 +0100 (BST) Subject: [lustre-devel] [PATCH 00/34] lustre: remainder of multi-rail series. In-Reply-To: <153783752960.32103.8394391715843917125.stgit@noble> References: <153783752960.32103.8394391715843917125.stgit@noble> Message-ID: > Hi, > following is the remainder of the Multi-Rail series, ported > to drivers/staging. > The previous series was only the first patch from upstream. > This series is mostly the individual patches from upstream, > though I did split some up a bit, and merged at least one bugfix back > to where the bug was introduced. > > Comments, review, and explanations of bits I didn't understand, are > most welcome. I confess that I haven't looked at the code very > closely, just a superficially scan for things that look odd (there > weren't many). Found another bug in the router setup code. I'm tracking it down. > Thanks, > NeilBrown > > --- > > Amir Shehata (22): > LU-7734 lnet: Multi-Rail peer split > LU-7734 lnet: Multi-Rail local_ni/peer_ni selection > LU-7734 lnet: configure peers from DLC > LU-7734 lnet: configure local NI from DLC > LU-7734 lnet: NUMA support > LU-7734 lnet: Primary NID and traffic distribution > LU-7734 lnet: handle non-MR peers > LU-7734 lnet: handle N NIs to 1 LND peer > LU-7734 lnet: rename LND peer to peer_ni > LU-7734 lnet: peer/peer_ni handling adjustments > LU-7734 lnet: proper cpt locking > LU-7734 lnet: protect peer_ni credits > LU-7734 lnet: simplify and fix lnet_select_pathway() > LU-7734 lnet: configuration fixes > LU-7734 lnet: fix lnet_select_pathway() > LU-7734 lnet: Routing fixes part 1 > LU-7734 lnet: Routing fixes part 2 > LU-7734 lnet: fix routing selection > LU-7734 lnet: Fix crash in router_proc.c > LU-7734 lnet: fix NULL access in lnet_peer_aliveness_enabled > LU-7734 lnet: rename peer key_nid to prim_nid > LU-7734 lnet: cpt locking > > Doug Oucharek (1): > LU-7734 lnet: Add peer_ni and NI stats for DLC > > NeilBrown (8): > lnet: replace all lp_ fields with lpni_ > lnet: change struct lnet_peer to struct lnet_peer_ni > lnet: Change lpni_refcount to atomic_t > lnet: change some function names - add 'ni'. > lnet: make lnet_nid_cpt_hash non-static. > lnet: introduce lnet_find_peer_ni_locked() > lnet: lnet_peer_tables_cleanup: use an exclusive lock. > lnet: use BIT() macro for LNET_MD_* flags > > Olaf Weber (3): > LU-7734 lnet: fix lnet_peer_table_cleanup_locked() > LU-7734 lnet: double free in lnet_add_net_common() > LU-7734 lnet: set primary NID in ptlrpc_connection_get() > > > .../lustre/include/linux/libcfs/libcfs_string.h | 12 > drivers/staging/lustre/include/linux/lnet/api.h | 1 > .../staging/lustre/include/linux/lnet/lib-lnet.h | 151 ++- > .../staging/lustre/include/linux/lnet/lib-types.h | 157 ++- > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 11 > .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 104 ++ > .../lustre/include/uapi/linux/lnet/lnet-types.h | 34 - > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 237 ++-- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 118 +- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 516 ++++----- > .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 678 ++++++------ > .../staging/lustre/lnet/klnds/socklnd/socklnd.h | 66 + > .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 207 ++-- > .../lustre/lnet/klnds/socklnd/socklnd_lib.c | 4 > .../lustre/lnet/klnds/socklnd/socklnd_proto.c | 14 > drivers/staging/lustre/lnet/lnet/api-ni.c | 650 ++++++++++- > drivers/staging/lustre/lnet/lnet/config.c | 107 +- > drivers/staging/lustre/lnet/lnet/lib-md.c | 31 + > drivers/staging/lustre/lnet/lnet/lib-move.c | 957 +++++++++++++--- > drivers/staging/lustre/lnet/lnet/lib-msg.c | 18 > drivers/staging/lustre/lnet/lnet/lib-ptl.c | 3 > drivers/staging/lustre/lnet/lnet/module.c | 70 + > drivers/staging/lustre/lnet/lnet/peer.c | 1169 +++++++++++++++++--- > drivers/staging/lustre/lnet/lnet/router.c | 341 +++--- > drivers/staging/lustre/lnet/lnet/router_proc.c | 66 + > drivers/staging/lustre/lustre/include/lustre_net.h | 2 > drivers/staging/lustre/lustre/ptlrpc/connection.c | 1 > drivers/staging/lustre/lustre/ptlrpc/events.c | 5 > drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 40 - > drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 2 > drivers/staging/lustre/lustre/ptlrpc/service.c | 4 > 31 files changed, 4056 insertions(+), 1720 deletions(-) > > -- > Signature > > From neilb at suse.com Tue Oct 2 02:25:47 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 12:25:47 +1000 Subject: [lustre-devel] [PATCH 07/34] lnet: lnet_peer_tables_cleanup: use an exclusive lock. In-Reply-To: References: <153783752960.32103.8394391715843917125.stgit@noble> <153783763511.32103.5073326313518943569.stgit@noble> Message-ID: <87pnwtrsno.fsf@notabene.neil.brown.name> On Sat, Sep 29 2018, James Simmons wrote: >> Why?? surely this will deadlock. >> >> This is part of >> Commit: 58091af960fe ("LU-7734 lnet: Multi-Rail peer split") >> from upstream lustre, where it is marked: >> Signed-off-by: Amir Shehata >> WC-bug-id: https://jira.whamcloud.com/browse/LU-7734 >> Reviewed-on: http://review.whamcloud.com/18293 >> Reviewed-by: Olaf Weber >> Reviewed-by: Doug Oucharek > > The code is right but the commit message needs a update. > Olaf, Doug, or Amir can you fill in the gaps. > > Reviewed-by: James Simmons thanks > > P.S > Its strange that git is not sending message to the people in the > Reviewed-by:. Maybe git can't handle the indent? I wasn't asking it to - I was just sending it the list and Oleg, Andreas, Doug, and you. Maybe I should ... Thanks, NeilBrown > >> Signed-off-by: NeilBrown >> --- >> drivers/staging/lustre/lnet/lnet/peer.c | 12 ++++++------ >> 1 file changed, 6 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c >> index 53b0ca0a2021..376e3459fa92 100644 >> --- a/drivers/staging/lustre/lnet/lnet/peer.c >> +++ b/drivers/staging/lustre/lnet/lnet/peer.c >> @@ -185,9 +185,9 @@ lnet_peer_tables_cleanup(struct lnet_ni *ni) >> * peers are gateways for. >> */ >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> - lnet_net_lock(i); >> + lnet_net_lock(LNET_LOCK_EX); >> lnet_peer_table_del_rtrs_locked(ni, ptable, i); >> - lnet_net_unlock(i); >> + lnet_net_unlock(LNET_LOCK_EX); >> } >> >> /* >> @@ -195,17 +195,17 @@ lnet_peer_tables_cleanup(struct lnet_ni *ni) >> * deathrow. >> */ >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> - lnet_net_lock(i); >> + lnet_net_lock(LNET_LOCK_EX); >> lnet_peer_table_cleanup_locked(ni, ptable); >> - lnet_net_unlock(i); >> + lnet_net_unlock(LNET_LOCK_EX); >> } >> >> /* Cleanup all entries on deathrow. */ >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> - lnet_net_lock(i); >> + lnet_net_lock(LNET_LOCK_EX); >> lnet_peer_table_deathrow_wait_locked(ptable, i); >> list_splice_init(&ptable->pt_deathrow, &deathrow); >> - lnet_net_unlock(i); >> + lnet_net_unlock(LNET_LOCK_EX); >> } >> >> while (!list_empty(&deathrow)) { >> >> >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 03:10:25 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 13:10:25 +1000 Subject: [lustre-devel] [PATCH 08/34] LU-7734 lnet: Multi-Rail peer split In-Reply-To: References: <153783752960.32103.8394391715843917125.stgit@noble> <153783763514.32103.5823547209878409504.stgit@noble> Message-ID: <87murxrqla.fsf@notabene.neil.brown.name> On Sun, Sep 30 2018, James Simmons wrote: > On Tue, 25 Sep 2018, NeilBrown wrote: > >> From: Amir Shehata >> >> [[Note, the preceding few patches are part of this >> in the upstream lustre code - they were split >> for easier merging into linux. >> ]] >> >> Split the peer structure into peer/peer_net/peer_ni, as >> described in the Multi-Rail HLD. >> >> Removed deathrow list in peers, instead peers are immediately >> deleted. deathrow complicates memory management for peers to >> little gain. >> >> Moved to LNET_LOCK_EX for any operations which will modify the >> peer tables. And CPT locks for any operatios which read the peer >> tables. Therefore there is no need to use lnet_cpt_of_nid() to >> calculate the CPT of the peer NID, instead we use lnet_nid_cpt_hash() >> to distribute peers across multiple CPTs. >> >> It is no longe true that peers and NIs would exist on >> the same CPT. In the new design peers and NIs don't have a 1-1 >> relationship. You can send to the same peer from several NIs, which >> can exist on separate CPTs >> >> Signed-off-by: Amir Shehata >> Change-Id: Ida41d830d38d0ab2bb551476e4a8866d52a25fe2 >> Reviewed-on: http://review.whamcloud.com/18293 >> Reviewed-by: Olaf Weber >> Reviewed-by: Doug Oucharek >> Signed-off-by: NeilBrown > > The patch is fine but the commit message needs to be properly formatted. > While patches to OpenSFS tree are titled with "LU-7743 lnet:" for the > linux client we changed that to be more inline with what the kernel does. > > LU-7734 lnet: Multi-Rail peer split --->>> lustre: lnet: Multi-Rail peer split > > To the outsider reviewer LU-7734 doesn't mean much. Also please replace > Change-Id: to the URL link for the work which in turn explains LU-7734. > > WC-bug-id: https://jira.whamcloud.com/browse/LU-7734 > > Same for the other patches this series. Seem reasonable? If I can automate it, it is probably reasonable. However, when Greg kicked us out of mainline, one of the things he said was it would mean we don't have to stick to kernel rules anymore, and that this might be good thing. A lot of the kernel rules (one patch = one change, good comment messages, ...) benefit us whether we are in the kernel or not so it makes sense to keep them. However I don't think that being picky about exactly where the LU number appears in the commit message actually helps us. Do you think it does? Thanks, NeilBrown > >> --- >> .../staging/lustre/include/linux/lnet/lib-lnet.h | 2 >> .../staging/lustre/include/linux/lnet/lib-types.h | 29 ++ >> drivers/staging/lustre/lnet/lnet/api-ni.c | 1 >> drivers/staging/lustre/lnet/lnet/peer.c | 260 ++++++++++++-------- >> drivers/staging/lustre/lnet/lnet/router_proc.c | 3 >> 5 files changed, 191 insertions(+), 104 deletions(-) >> >> diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> index 656177b64336..bf076298de71 100644 >> --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> @@ -637,8 +637,6 @@ bool lnet_net_unique(__u32 net_id, struct list_head *nilist, >> bool lnet_ni_unique_net(struct list_head *nilist, char *iface); >> >> int lnet_nid2peerni_locked(struct lnet_peer_ni **lpp, lnet_nid_t nid, int cpt); >> -struct lnet_peer_ni *lnet_find_peer_locked(struct lnet_peer_table *ptable, >> - lnet_nid_t nid); >> struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid, int cpt); >> void lnet_peer_tables_cleanup(struct lnet_ni *ni); >> void lnet_peer_tables_destroy(void); >> diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h >> index 9a2cf319dba9..9f70c094cc4c 100644 >> --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h >> +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h >> @@ -384,6 +384,7 @@ struct lnet_rc_data { >> }; >> >> struct lnet_peer_ni { >> + struct list_head lpni_on_peer_net_list; >> /* chain on peer hash */ >> struct list_head lpni_hashlist; >> /* messages blocking for tx credits */ >> @@ -394,6 +395,7 @@ struct lnet_peer_ni { >> struct list_head lpni_rtr_list; >> /* # tx credits available */ >> int lpni_txcredits; >> + struct lnet_peer_net *lpni_peer_net; >> /* low water mark */ >> int lpni_mintxcredits; >> /* # router credits */ >> @@ -442,6 +444,31 @@ struct lnet_peer_ni { >> struct lnet_rc_data *lpni_rcd; >> }; >> >> +struct lnet_peer { >> + /* chain on global peer list */ >> + struct list_head lp_on_lnet_peer_list; >> + >> + /* list of peer nets */ >> + struct list_head lp_peer_nets; >> + >> + /* primary NID of the peer */ >> + lnet_nid_t lp_primary_nid; >> +}; >> + >> +struct lnet_peer_net { >> + /* chain on peer block */ >> + struct list_head lpn_on_peer_list; >> + >> + /* list of peer_nis on this network */ >> + struct list_head lpn_peer_nis; >> + >> + /* pointer to the peer I'm part of */ >> + struct lnet_peer *lpn_peer; >> + >> + /* Net ID */ >> + __u32 lpn_net_id; >> +}; >> + >> /* peer hash size */ >> #define LNET_PEER_HASH_BITS 9 >> #define LNET_PEER_HASH_SIZE (1 << LNET_PEER_HASH_BITS) >> @@ -686,6 +713,8 @@ struct lnet { >> struct lnet_msg_container **ln_msg_containers; >> struct lnet_counters **ln_counters; >> struct lnet_peer_table **ln_peer_tables; >> + /* list of configured or discovered peers */ >> + struct list_head ln_peers; >> /* failure simulation */ >> struct list_head ln_test_peers; >> struct list_head ln_drop_rules; >> diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c >> index 20fa3fea04b9..821b030f9621 100644 >> --- a/drivers/staging/lustre/lnet/lnet/api-ni.c >> +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c >> @@ -542,6 +542,7 @@ lnet_prepare(lnet_pid_t requested_pid) >> the_lnet.ln_pid = requested_pid; >> >> INIT_LIST_HEAD(&the_lnet.ln_test_peers); >> + INIT_LIST_HEAD(&the_lnet.ln_peers); >> INIT_LIST_HEAD(&the_lnet.ln_nets); >> INIT_LIST_HEAD(&the_lnet.ln_routers); >> INIT_LIST_HEAD(&the_lnet.ln_drop_rules); >> diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c >> index 376e3459fa92..97ee1f5cfd2f 100644 >> --- a/drivers/staging/lustre/lnet/lnet/peer.c >> +++ b/drivers/staging/lustre/lnet/lnet/peer.c >> @@ -54,8 +54,6 @@ lnet_peer_tables_create(void) >> } >> >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> - INIT_LIST_HEAD(&ptable->pt_deathrow); >> - >> hash = kvmalloc_cpt(LNET_PEER_HASH_SIZE * sizeof(*hash), >> GFP_KERNEL, i); >> if (!hash) { >> @@ -88,8 +86,6 @@ lnet_peer_tables_destroy(void) >> if (!hash) /* not initialized */ >> break; >> >> - LASSERT(list_empty(&ptable->pt_deathrow)); >> - >> ptable->pt_hash = NULL; >> for (j = 0; j < LNET_PEER_HASH_SIZE; j++) >> LASSERT(list_empty(&hash[j])); >> @@ -123,7 +119,7 @@ lnet_peer_table_cleanup_locked(struct lnet_ni *ni, >> } >> >> static void >> -lnet_peer_table_deathrow_wait_locked(struct lnet_peer_table *ptable, >> +lnet_peer_table_finalize_wait_locked(struct lnet_peer_table *ptable, >> int cpt_locked) >> { >> int i; >> @@ -173,12 +169,8 @@ void >> lnet_peer_tables_cleanup(struct lnet_ni *ni) >> { >> struct lnet_peer_table *ptable; >> - struct list_head deathrow; >> - struct lnet_peer_ni *lp; >> int i; >> >> - INIT_LIST_HEAD(&deathrow); >> - >> LASSERT(the_lnet.ln_shutdown || ni); >> /* >> * If just deleting the peers for a NI, get rid of any routes these >> @@ -191,8 +183,7 @@ lnet_peer_tables_cleanup(struct lnet_ni *ni) >> } >> >> /* >> - * Start the process of moving the applicable peers to >> - * deathrow. >> + * Start the cleanup process >> */ >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> lnet_net_lock(LNET_LOCK_EX); >> @@ -200,20 +191,12 @@ lnet_peer_tables_cleanup(struct lnet_ni *ni) >> lnet_net_unlock(LNET_LOCK_EX); >> } >> >> - /* Cleanup all entries on deathrow. */ >> + /* Wait until all peers have been destroyed. */ >> cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) { >> lnet_net_lock(LNET_LOCK_EX); >> - lnet_peer_table_deathrow_wait_locked(ptable, i); >> - list_splice_init(&ptable->pt_deathrow, &deathrow); >> + lnet_peer_table_finalize_wait_locked(ptable, i); >> lnet_net_unlock(LNET_LOCK_EX); >> } >> - >> - while (!list_empty(&deathrow)) { >> - lp = list_entry(deathrow.next, struct lnet_peer_ni, >> - lpni_hashlist); >> - list_del(&lp->lpni_hashlist); >> - kfree(lp); >> - } >> } >> >> static struct lnet_peer_ni * >> @@ -247,74 +230,143 @@ lnet_find_peer_ni_locked(lnet_nid_t nid, int cpt) >> return lpni; >> } >> >> -void >> -lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lp) >> +static void >> +lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) >> { >> - struct lnet_peer_table *ptable; >> + struct lnet_peer_net *peer_net; >> + struct lnet_peer *peer; >> >> - LASSERT(atomic_read(&lp->lpni_refcount) == 0); >> - LASSERT(!lp->lpni_rtr_refcount); >> - LASSERT(list_empty(&lp->lpni_txq)); >> - LASSERT(list_empty(&lp->lpni_hashlist)); >> - LASSERT(!lp->lpni_txqnob); >> + /* TODO: could the below situation happen? accessing an already >> + * destroyed peer? >> + */ >> + if (!lpni->lpni_peer_net || >> + !lpni->lpni_peer_net->lpn_peer) >> + return; >> >> - ptable = the_lnet.ln_peer_tables[lp->lpni_cpt]; >> - LASSERT(ptable->pt_number > 0); >> - ptable->pt_number--; >> + peer_net = lpni->lpni_peer_net; >> + peer = lpni->lpni_peer_net->lpn_peer; >> >> - lp->lpni_net = NULL; >> + list_del_init(&lpni->lpni_on_peer_net_list); >> + lpni->lpni_peer_net = NULL; >> >> - list_add(&lp->lpni_hashlist, &ptable->pt_deathrow); >> - LASSERT(ptable->pt_zombies > 0); >> - ptable->pt_zombies--; >> + /* if peer_net is empty, then remove it from the peer */ >> + if (list_empty(&peer_net->lpn_peer_nis)) { >> + list_del_init(&peer_net->lpn_on_peer_list); >> + peer_net->lpn_peer = NULL; >> + kfree(peer_net); >> + >> + /* If the peer is empty then remove it from the >> + * the_lnet.ln_peers >> + */ >> + if (list_empty(&peer->lp_peer_nets)) { >> + list_del_init(&peer->lp_on_lnet_peer_list); >> + kfree(peer); >> + } >> + } >> } >> >> -struct lnet_peer_ni * >> -lnet_find_peer_locked(struct lnet_peer_table *ptable, lnet_nid_t nid) >> +static int >> +lnet_build_peer_hierarchy(struct lnet_peer_ni *lpni) >> { >> - struct list_head *peers; >> - struct lnet_peer_ni *lp; >> + struct lnet_peer *peer; >> + struct lnet_peer_net *peer_net; >> + __u32 lpni_net = LNET_NIDNET(lpni->lpni_nid); >> >> - LASSERT(!the_lnet.ln_shutdown); >> + peer = NULL; >> + peer_net = NULL; >> >> - peers = &ptable->pt_hash[lnet_nid2peerhash(nid)]; >> - list_for_each_entry(lp, peers, lpni_hashlist) { >> - if (lp->lpni_nid == nid) { >> - lnet_peer_ni_addref_locked(lp); >> - return lp; >> - } >> + peer = kzalloc(sizeof(*peer), GFP_KERNEL); >> + if (!peer) >> + return -ENOMEM; >> + >> + peer_net = kzalloc(sizeof(*peer_net), GFP_KERNEL); >> + if (!peer_net) { >> + kfree(peer); >> + return -ENOMEM; >> } >> >> - return NULL; >> + INIT_LIST_HEAD(&peer->lp_on_lnet_peer_list); >> + INIT_LIST_HEAD(&peer->lp_peer_nets); >> + INIT_LIST_HEAD(&peer_net->lpn_on_peer_list); >> + INIT_LIST_HEAD(&peer_net->lpn_peer_nis); >> + >> + /* build the hierarchy */ >> + peer_net->lpn_net_id = lpni_net; >> + peer_net->lpn_peer = peer; >> + lpni->lpni_peer_net = peer_net; >> + peer->lp_primary_nid = lpni->lpni_nid; >> + list_add_tail(&peer_net->lpn_on_peer_list, &peer->lp_peer_nets); >> + list_add_tail(&lpni->lpni_on_peer_net_list, &peer_net->lpn_peer_nis); >> + list_add_tail(&peer->lp_on_lnet_peer_list, &the_lnet.ln_peers); >> + >> + return 0; >> +} >> + >> +void >> +lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) >> +{ >> + struct lnet_peer_table *ptable; >> + >> + LASSERT(atomic_read(&lpni->lpni_refcount) == 0); >> + LASSERT(lpni->lpni_rtr_refcount == 0); >> + LASSERT(list_empty(&lpni->lpni_txq)); >> + LASSERT(list_empty(&lpni->lpni_hashlist)); >> + LASSERT(lpni->lpni_txqnob == 0); >> + LASSERT(lpni->lpni_peer_net); >> + LASSERT(lpni->lpni_peer_net->lpn_peer); >> + >> + ptable = the_lnet.ln_peer_tables[lpni->lpni_cpt]; >> + LASSERT(ptable->pt_number > 0); >> + ptable->pt_number--; >> + >> + lpni->lpni_net = NULL; >> + >> + lnet_try_destroy_peer_hierarchy_locked(lpni); >> + >> + kfree(lpni); >> + >> + LASSERT(ptable->pt_zombies > 0); >> + ptable->pt_zombies--; >> } >> >> int >> -lnet_nid2peerni_locked(struct lnet_peer_ni **lpp, lnet_nid_t nid, int cpt) >> +lnet_nid2peerni_locked(struct lnet_peer_ni **lpnip, lnet_nid_t nid, int cpt) >> { >> struct lnet_peer_table *ptable; >> - struct lnet_peer_ni *lp = NULL; >> - struct lnet_peer_ni *lp2; >> + struct lnet_peer_ni *lpni = NULL; >> + struct lnet_peer_ni *lpni2; >> int cpt2; >> int rc = 0; >> >> - *lpp = NULL; >> + *lpnip = NULL; >> if (the_lnet.ln_shutdown) /* it's shutting down */ >> return -ESHUTDOWN; >> >> - /* cpt can be LNET_LOCK_EX if it's called from router functions */ >> - cpt2 = cpt != LNET_LOCK_EX ? cpt : lnet_cpt_of_nid_locked(nid, NULL); >> + /* >> + * calculate cpt2 with the standard hash function >> + * This cpt2 becomes the slot where we'll find or create the peer. >> + */ >> + cpt2 = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); >> >> - ptable = the_lnet.ln_peer_tables[cpt2]; >> - lp = lnet_find_peer_locked(ptable, nid); >> - if (lp) { >> - *lpp = lp; >> - return 0; >> + /* >> + * Any changes to the peer tables happen under exclusive write >> + * lock. Any reads to the peer tables can be done via a standard >> + * CPT read lock. >> + */ >> + if (cpt != LNET_LOCK_EX) { >> + lnet_net_unlock(cpt); >> + lnet_net_lock(LNET_LOCK_EX); >> } >> >> - if (!list_empty(&ptable->pt_deathrow)) { >> - lp = list_entry(ptable->pt_deathrow.next, >> - struct lnet_peer_ni, lpni_hashlist); >> - list_del(&lp->lpni_hashlist); >> + ptable = the_lnet.ln_peer_tables[cpt2]; >> + lpni = lnet_get_peer_ni_locked(ptable, nid); >> + if (lpni) { >> + *lpnip = lpni; >> + if (cpt != LNET_LOCK_EX) { >> + lnet_net_unlock(LNET_LOCK_EX); >> + lnet_net_lock(cpt); >> + } >> + return 0; >> } >> >> /* >> @@ -322,68 +374,72 @@ lnet_nid2peerni_locked(struct lnet_peer_ni **lpp, lnet_nid_t nid, int cpt) >> * and destroyed locks and peer-table before I finish the allocation >> */ >> ptable->pt_number++; >> - lnet_net_unlock(cpt); >> + lnet_net_unlock(LNET_LOCK_EX); >> >> - if (lp) >> - memset(lp, 0, sizeof(*lp)); >> - else >> - lp = kzalloc_cpt(sizeof(*lp), GFP_NOFS, cpt2); >> - >> - if (!lp) { >> + lpni = kzalloc_cpt(sizeof(*lpni), GFP_KERNEL, cpt2); >> + if (!lpni) { >> rc = -ENOMEM; >> lnet_net_lock(cpt); >> goto out; >> } >> >> - INIT_LIST_HEAD(&lp->lpni_txq); >> - INIT_LIST_HEAD(&lp->lpni_rtrq); >> - INIT_LIST_HEAD(&lp->lpni_routes); >> - >> - lp->lpni_notify = 0; >> - lp->lpni_notifylnd = 0; >> - lp->lpni_notifying = 0; >> - lp->lpni_alive_count = 0; >> - lp->lpni_timestamp = 0; >> - lp->lpni_alive = !lnet_peers_start_down(); /* 1 bit!! */ >> - lp->lpni_last_alive = ktime_get_seconds(); /* assumes alive */ >> - lp->lpni_last_query = 0; /* haven't asked NI yet */ >> - lp->lpni_ping_timestamp = 0; >> - lp->lpni_ping_feats = LNET_PING_FEAT_INVAL; >> - lp->lpni_nid = nid; >> - lp->lpni_cpt = cpt2; >> - atomic_set(&lp->lpni_refcount, 2); /* 1 for caller; 1 for hash */ >> - lp->lpni_rtr_refcount = 0; >> + INIT_LIST_HEAD(&lpni->lpni_txq); >> + INIT_LIST_HEAD(&lpni->lpni_rtrq); >> + INIT_LIST_HEAD(&lpni->lpni_routes); >> >> - lnet_net_lock(cpt); >> + lpni->lpni_alive = !lnet_peers_start_down(); /* 1 bit!! */ >> + lpni->lpni_last_alive = ktime_get_seconds(); /* assumes alive */ >> + lpni->lpni_ping_feats = LNET_PING_FEAT_INVAL; >> + lpni->lpni_nid = nid; >> + lpni->lpni_cpt = cpt2; >> + atomic_set(&lpni->lpni_refcount, 2); /* 1 for caller; 1 for hash */ >> + >> + rc = lnet_build_peer_hierarchy(lpni); >> + if (rc != 0) >> + goto out; >> + >> + lnet_net_lock(LNET_LOCK_EX); >> >> if (the_lnet.ln_shutdown) { >> rc = -ESHUTDOWN; >> goto out; >> } >> >> - lp2 = lnet_find_peer_locked(ptable, nid); >> - if (lp2) { >> - *lpp = lp2; >> + lpni2 = lnet_get_peer_ni_locked(ptable, nid); >> + if (lpni2) { >> + *lpnip = lpni2; >> goto out; >> } >> >> - lp->lpni_net = lnet_get_net_locked(LNET_NIDNET(lp->lpni_nid)); >> - lp->lpni_txcredits = >> - lp->lpni_mintxcredits = >> - lp->lpni_net->net_tunables.lct_peer_tx_credits; >> - lp->lpni_rtrcredits = >> - lp->lpni_minrtrcredits = lnet_peer_buffer_credits(lp->lpni_net); >> + lpni->lpni_net = lnet_get_net_locked(LNET_NIDNET(lpni->lpni_nid)); >> + lpni->lpni_txcredits = >> + lpni->lpni_mintxcredits = >> + lpni->lpni_net->net_tunables.lct_peer_tx_credits; >> + lpni->lpni_rtrcredits = >> + lpni->lpni_minrtrcredits = >> + lnet_peer_buffer_credits(lpni->lpni_net); >> >> - list_add_tail(&lp->lpni_hashlist, >> + list_add_tail(&lpni->lpni_hashlist, >> &ptable->pt_hash[lnet_nid2peerhash(nid)]); >> ptable->pt_version++; >> - *lpp = lp; >> + *lpnip = lpni; >> + >> + if (cpt != LNET_LOCK_EX) { >> + lnet_net_unlock(LNET_LOCK_EX); >> + lnet_net_lock(cpt); >> + } >> >> return 0; >> out: >> - if (lp) >> - list_add(&lp->lpni_hashlist, &ptable->pt_deathrow); >> + if (lpni) { >> + lnet_try_destroy_peer_hierarchy_locked(lpni); >> + kfree(lpni); >> + } >> ptable->pt_number--; >> + if (cpt != LNET_LOCK_EX) { >> + lnet_net_unlock(LNET_LOCK_EX); >> + lnet_net_lock(cpt); >> + } >> return rc; >> } >> >> diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c >> index 12a4b1708d3c..977a937f261c 100644 >> --- a/drivers/staging/lustre/lnet/lnet/router_proc.c >> +++ b/drivers/staging/lustre/lnet/lnet/router_proc.c >> @@ -385,6 +385,9 @@ static int proc_lnet_routers(struct ctl_table *table, int write, >> return rc; >> } >> >> +/* TODO: there should be no direct access to ptable. We should add a set >> + * of APIs that give access to the ptable and its members >> + */ >> static int proc_lnet_peers(struct ctl_table *table, int write, >> void __user *buffer, size_t *lenp, loff_t *ppos) >> { >> >> >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 03:19:36 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 13:19:36 +1000 Subject: [lustre-devel] [PATCH 11/34] LU-7734 lnet: configure local NI from DLC In-Reply-To: References: <153783752960.32103.8394391715843917125.stgit@noble> <153783763527.32103.6166409833321456335.stgit@noble> Message-ID: <87k1n1rq5z.fsf@notabene.neil.brown.name> On Sat, Sep 29 2018, James Simmons wrote: >> From: Amir Shehata >> >> This patch adds the ability to configure multiple network interfaces >> on the same network. This can be done via the lnetctl CLI interface >> or through a YAML configuration. Refer to the multi-rail HLD for >> more details on the syntax. >> >> It also deprecates ip2nets kernel parsing. All string parsing and >> network maching now happens in the DLC userspace library. >> >> New IOCTLs are added for adding/deleting local NIs, to keep backwards >> compatibility with older version of the DLC and lnetctl. >> >> The changes also include parsing and matching ip2nets syntax at the >> user level and then passing down the network interfaces down to the >> kernel to be configured. > > Nak. This patch introduces a regression in lnet_ioctl() found in > module.c > >> Signed-off-by: Amir Shehata >> Change-Id: I19ee7dc76514beb6f34de6517d19654d6468bcec >> Reviewed-on: http://review.whamcloud.com/18886 >> Tested-by: Maloo >> Signed-off-by: NeilBrown >> --- >> .../lustre/include/linux/libcfs/libcfs_string.h | 12 - >> .../staging/lustre/include/linux/lnet/lib-lnet.h | 13 - >> .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 6 >> .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 57 ++ >> .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 3 >> drivers/staging/lustre/lnet/lnet/api-ni.c | 479 +++++++++++++++++--- >> drivers/staging/lustre/lnet/lnet/config.c | 107 +++- >> drivers/staging/lustre/lnet/lnet/module.c | 70 ++- >> drivers/staging/lustre/lnet/lnet/peer.c | 21 + >> drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 2 >> drivers/staging/lustre/lustre/ptlrpc/service.c | 4 >> 11 files changed, 650 insertions(+), 124 deletions(-) > > ..... > >> diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c >> index 9d06664f0c17..c82d27592391 100644 >> --- a/drivers/staging/lustre/lnet/lnet/module.c >> +++ b/drivers/staging/lustre/lnet/lnet/module.c >> @@ -92,7 +92,7 @@ lnet_unconfigure(void) >> } >> >> static int >> -lnet_dyn_configure(struct libcfs_ioctl_hdr *hdr) >> +lnet_dyn_configure_net(struct libcfs_ioctl_hdr *hdr) >> { >> struct lnet_ioctl_config_data *conf = >> (struct lnet_ioctl_config_data *)hdr; >> @@ -102,19 +102,17 @@ lnet_dyn_configure(struct libcfs_ioctl_hdr *hdr) >> return -EINVAL; >> >> mutex_lock(&lnet_config_mutex); >> - if (!the_lnet.ln_niinit_self) { >> + if (the_lnet.ln_niinit_self) >> + rc = lnet_dyn_add_net(conf); >> + else >> rc = -EINVAL; >> - goto out_unlock; >> - } >> - rc = lnet_dyn_add_ni(LNET_PID_LUSTRE, conf); >> -out_unlock: >> mutex_unlock(&lnet_config_mutex); >> >> return rc; >> } >> >> static int >> -lnet_dyn_unconfigure(struct libcfs_ioctl_hdr *hdr) >> +lnet_dyn_unconfigure_net(struct libcfs_ioctl_hdr *hdr) >> { >> struct lnet_ioctl_config_data *conf = >> (struct lnet_ioctl_config_data *)hdr; >> @@ -124,12 +122,50 @@ lnet_dyn_unconfigure(struct libcfs_ioctl_hdr *hdr) >> return -EINVAL; >> >> mutex_lock(&lnet_config_mutex); >> - if (!the_lnet.ln_niinit_self) { >> + if (the_lnet.ln_niinit_self) >> + rc = lnet_dyn_del_net(conf->cfg_net); >> + else >> + rc = -EINVAL; >> + mutex_unlock(&lnet_config_mutex); >> + >> + return rc; >> +} >> + >> +static int >> +lnet_dyn_configure_ni(struct libcfs_ioctl_hdr *hdr) >> +{ >> + struct lnet_ioctl_config_ni *conf = >> + (struct lnet_ioctl_config_ni *)hdr; >> + int rc; >> + >> + if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf)) >> + return -EINVAL; >> + >> + mutex_lock(&lnet_config_mutex); >> + if (the_lnet.ln_niinit_self) >> + rc = lnet_dyn_add_ni(conf); >> + else >> + rc = -EINVAL; >> + mutex_unlock(&lnet_config_mutex); >> + >> + return rc; >> +} >> + >> +static int >> +lnet_dyn_unconfigure_ni(struct libcfs_ioctl_hdr *hdr) >> +{ >> + struct lnet_ioctl_config_ni *conf = >> + (struct lnet_ioctl_config_ni *)hdr; >> + int rc; >> + >> + if (conf->lic_cfg_hdr.ioc_len < sizeof(*conf)) >> + return -EINVAL; >> + >> + mutex_lock(&lnet_config_mutex); >> + if (the_lnet.ln_niinit_self) >> + rc = lnet_dyn_del_ni(conf); >> + else >> rc = -EINVAL; >> - goto out_unlock; >> - } >> - rc = lnet_dyn_del_ni(conf->cfg_net); >> -out_unlock: >> mutex_unlock(&lnet_config_mutex); >> >> return rc; >> @@ -161,11 +197,17 @@ lnet_ioctl(struct notifier_block *nb, >> break; >> >> case IOC_LIBCFS_ADD_NET: >> - rc = lnet_dyn_configure(hdr); >> + rc = lnet_dyn_configure_net(hdr); >> break; >> >> case IOC_LIBCFS_DEL_NET: >> - rc = lnet_dyn_unconfigure(hdr); >> + rc = lnet_dyn_unconfigure_net(hdr); >> + >> + case IOC_LIBCFS_ADD_LOCAL_NI: >> + return lnet_dyn_configure_ni(hdr); >> + >> + case IOC_LIBCFS_DEL_LOCAL_NI: >> + return lnet_dyn_unconfigure_ni(hdr); >> break; >> >> default: > > While the above is mostly correct for the OpenSFS branch that is > not the case for the linux client version. The above code assumes > we are using libc_register_ioctl() but that was replace by the > block_notifier handling for ioctls instead. What we want instead is > > case IOC_LIBCFS_DEL_NET: > rc = lnet_dyn_unconfigure_net(hdr); > break; > > case IOC_LIBCFS_ADD_LOCAL_NI: > rc = lnet_dyn_configure_ni(hdr); > break; > > case IOC_LIBCFS_DEL_LOCAL_NI: > rc = lnet_dyn_unconfigure_ni(hdr); > break; > > that way the return value is generated by notifier_from_ioctl_errno(rc). > This resolves the last bug in see in this patch set with my testing. Darn - I should have noticed that ! I've fixed it now. Thanks a lot, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 03:31:59 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 13:31:59 +1000 Subject: [lustre-devel] [PATCH 33/34] lnet: use BIT() macro for LNET_MD_* flags In-Reply-To: References: <153783752960.32103.8394391715843917125.stgit@noble> <153783763611.32103.14845537928418369718.stgit@noble> Message-ID: <87h8i5rplc.fsf@notabene.neil.brown.name> On Fri, Sep 28 2018, James Simmons wrote: >> As these are bit flags, it aids clarity to use the BIT() >> macro. > > Nak. BIT is not for UAPI headers. Including this will break building > userland applications. Apparently not everyone knows this: $ git grep '[^A-Z_]BIT(' include/uapi/ | wc -l 11 However, it makes sense - thanks. I've removed all the BITs that I added. NeilBrown > >> Signed-off-by: NeilBrown >> --- >> .../lustre/include/uapi/linux/lnet/lnet-types.h | 18 +++++++++--------- >> 1 file changed, 9 insertions(+), 9 deletions(-) >> >> diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h >> index e80ef4182e5d..62f062c0d1bf 100644 >> --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h >> +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h >> @@ -483,22 +483,22 @@ struct lnet_md { >> /** >> * Options for the MD structure. See lnet_md::options. >> */ >> -#define LNET_MD_OP_PUT (1 << 0) >> +#define LNET_MD_OP_PUT BIT(0) >> /** See lnet_md::options. */ >> -#define LNET_MD_OP_GET (1 << 1) >> +#define LNET_MD_OP_GET BIT(1) >> /** See lnet_md::options. */ >> -#define LNET_MD_MANAGE_REMOTE (1 << 2) >> -/* unused (1 << 3) */ >> +#define LNET_MD_MANAGE_REMOTE BIT(2) >> +/* unused BIT(3) */ >> /** See lnet_md::options. */ >> -#define LNET_MD_TRUNCATE (1 << 4) >> +#define LNET_MD_TRUNCATE BIT(4) >> /** See lnet_md::options. */ >> -#define LNET_MD_ACK_DISABLE (1 << 5) >> +#define LNET_MD_ACK_DISABLE BIT(5) >> /** See lnet_md::options. */ >> -#define LNET_MD_IOVEC (1 << 6) >> +#define LNET_MD_IOVEC BIT(6) >> /** See lnet_md::options. */ >> -#define LNET_MD_MAX_SIZE (1 << 7) >> +#define LNET_MD_MAX_SIZE BIT(7) >> /** See lnet_md::options. */ >> -#define LNET_MD_KIOV (1 << 8) >> +#define LNET_MD_KIOV BIT(8) >> >> /* For compatibility with Cray Portals */ >> #define LNET_MD_PHYS 0 >> >> >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 03:41:26 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 13:41:26 +1000 Subject: [lustre-devel] [PATCH 00/34] lustre: remainder of multi-rail series. In-Reply-To: References: <153783752960.32103.8394391715843917125.stgit@noble> Message-ID: <87efd9rp5l.fsf@notabene.neil.brown.name> On Sun, Sep 30 2018, James Simmons wrote: >> Hi, >> following is the remainder of the Multi-Rail series, ported >> to drivers/staging. >> The previous series was only the first patch from upstream. >> This series is mostly the individual patches from upstream, >> though I did split some up a bit, and merged at least one bugfix back >> to where the bug was introduced. >> >> Comments, review, and explanations of bits I didn't understand, are >> most welcome. I confess that I haven't looked at the code very >> closely, just a superficially scan for things that look odd (there >> weren't many). > > Thanks for doing this. It makes my life easier. With the patches: > > lustre: lnet: copy the correct amount of cpts to lnet_cpts > lustre: lnd: resolve IP query code in LND drivers I've moved these two to the top of the series. > > and the fixup in patch 11 it runs flawless in my testing. I do recommend > land the two above patches first so no git bisect will end up blowing up > someones nodes :-) > > Just have a bunch of commit recommendations. I noticed some MR patches > landed to the main lustre branch. Perhaps those should be fixed as well. > The only reason I ask is that I worry about kernel developers might not > like that style of commit messages. In the past Greg pointed such things > out to me. Thanks for hearing me out about that concern. While I hope that this will eventually get merged by Linus pulling my tree, complete with history, that might not work out. New clean patches might be required. But if pulling my tree is an option, Greg (at least) cannot in good faith complain about the commit messages or patch breakdown as he explicitly said that we would be freed from that requirement by working out-of-tree. So I'm inclined not to put much effort into things that don't benefit us now. > > I will poke Doug about looking at some of the commit messages you had > concern about. Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 04:24:36 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 14:24:36 +1000 Subject: [lustre-devel] [PATCH 01/25] lustre: lnet: remove ni from lnet_finalize In-Reply-To: References: <1537930097-11624-1-git-send-email-jsimmons@infradead.org> <1537930097-11624-2-git-send-email-jsimmons@infradead.org> <875zyrizgr.fsf@notabene.neil.brown.name> Message-ID: <875zylrn5n.fsf@notabene.neil.brown.name> On Sun, Sep 30 2018, James Simmons wrote: >> On Tue, Sep 25 2018, James Simmons wrote: >> >> > From: Sergey Cheremencev >> > >> > Remove ni from lnet_finalize and kiblnd_txlist_done >> > input arguments. Also small code cleanup by introducing >> > ibprm_cookie to avoid checkpatch issues. >> >> What checkpatch issues are avoided ?? > > more than 80 character. The LND drivers tend to be bad at that. Ahh, OK. I don't normally add new variables to avoid long lines, but in this case I think it worked quite well. Thanks, NeilBrown > >> Thanks, >> NeilBrown >> >> > >> > Signed-off-by: Sergey Cheremencev >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-9094 >> > Seagate-bug-id: MRP-4056 >> > Reviewed-on: https://review.whamcloud.com/25375 >> > Reviewed-by: Doug Oucharek >> > Reviewed-by: Amir Shehata >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > .../staging/lustre/include/linux/lnet/lib-lnet.h | 2 +- >> > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 +- >> > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 3 +- >> > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 65 ++++++++++------------ >> > .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 3 +- >> > .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 4 +- >> > drivers/staging/lustre/lnet/lnet/lib-move.c | 20 +++---- >> > drivers/staging/lustre/lnet/lnet/lib-msg.c | 2 +- >> > drivers/staging/lustre/lnet/lnet/lo.c | 4 +- >> > drivers/staging/lustre/lnet/lnet/net_fault.c | 2 +- >> > 10 files changed, 50 insertions(+), 57 deletions(-) >> > >> > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> > index aedc88c..53cbf6d 100644 >> > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> > @@ -537,7 +537,7 @@ struct lnet_msg *lnet_create_reply_msg(struct lnet_ni *ni, >> > void lnet_set_reply_msg_len(struct lnet_ni *ni, struct lnet_msg *msg, >> > unsigned int len); >> > >> > -void lnet_finalize(struct lnet_ni *ni, struct lnet_msg *msg, int rc); >> > +void lnet_finalize(struct lnet_msg *msg, int rc); >> > >> > void lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, >> > unsigned int nob); >> > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > index 75a7e96..b3a4344 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > @@ -521,7 +521,7 @@ static int kiblnd_del_peer(struct lnet_ni *ni, lnet_nid_t nid) >> > >> > write_unlock_irqrestore(&kiblnd_data.kib_global_lock, flags); >> > >> > - kiblnd_txlist_done(ni, &zombies, -EIO); >> > + kiblnd_txlist_done(&zombies, -EIO); >> > >> > return rc; >> > } >> > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > index b1851b5..a3d89ec 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > @@ -1034,8 +1034,7 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, >> > void kiblnd_close_conn_locked(struct kib_conn *conn, int error); >> > >> > void kiblnd_launch_tx(struct lnet_ni *ni, struct kib_tx *tx, lnet_nid_t nid); >> > -void kiblnd_txlist_done(struct lnet_ni *ni, struct list_head *txlist, >> > - int status); >> > +void kiblnd_txlist_done(struct list_head *txlist, int status); >> > >> > void kiblnd_qp_event(struct ib_event *event, void *arg); >> > void kiblnd_cq_event(struct ib_event *event, void *arg); >> > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c >> > index cb752dc..debed17 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c >> > @@ -54,14 +54,12 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, >> > static void kiblnd_check_sends_locked(struct kib_conn *conn); >> > >> > static void >> > -kiblnd_tx_done(struct lnet_ni *ni, struct kib_tx *tx) >> > +kiblnd_tx_done(struct kib_tx *tx) >> > { >> > struct lnet_msg *lntmsg[2]; >> > - struct kib_net *net = ni->ni_data; >> > int rc; >> > int i; >> > >> > - LASSERT(net); >> > LASSERT(!in_interrupt()); >> > LASSERT(!tx->tx_queued); /* mustn't be queued for sending */ >> > LASSERT(!tx->tx_sending); /* mustn't be awaiting sent callback */ >> > @@ -76,8 +74,6 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, >> > rc = tx->tx_status; >> > >> > if (tx->tx_conn) { >> > - LASSERT(ni == tx->tx_conn->ibc_peer->ibp_ni); >> > - >> > kiblnd_conn_decref(tx->tx_conn); >> > tx->tx_conn = NULL; >> > } >> > @@ -92,12 +88,12 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, >> > if (!lntmsg[i]) >> > continue; >> > >> > - lnet_finalize(ni, lntmsg[i], rc); >> > + lnet_finalize(lntmsg[i], rc); >> > } >> > } >> > >> > void >> > -kiblnd_txlist_done(struct lnet_ni *ni, struct list_head *txlist, int status) >> > +kiblnd_txlist_done(struct list_head *txlist, int status) >> > { >> > struct kib_tx *tx; >> > >> > @@ -108,7 +104,7 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, >> > /* complete now */ >> > tx->tx_waiting = 0; >> > tx->tx_status = status; >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > } >> > } >> > >> > @@ -281,7 +277,7 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, >> > spin_unlock(&conn->ibc_lock); >> > >> > if (idle) >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > } >> > >> > static void >> > @@ -794,7 +790,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, >> > * posted NOOPs complete >> > */ >> > spin_unlock(&conn->ibc_lock); >> > - kiblnd_tx_done(peer_ni->ibp_ni, tx); >> > + kiblnd_tx_done(tx); >> > spin_lock(&conn->ibc_lock); >> > CDEBUG(D_NET, "%s(%d): redundant or enough NOOP\n", >> > libcfs_nid2str(peer_ni->ibp_nid), >> > @@ -888,7 +884,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, >> > kiblnd_close_conn(conn, rc); >> > >> > if (done) >> > - kiblnd_tx_done(peer_ni->ibp_ni, tx); >> > + kiblnd_tx_done(tx); >> > >> > spin_lock(&conn->ibc_lock); >> > >> > @@ -1007,7 +1003,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, >> > spin_unlock(&conn->ibc_lock); >> > >> > if (idle) >> > - kiblnd_tx_done(conn->ibc_peer->ibp_ni, tx); >> > + kiblnd_tx_done(tx); >> > } >> > >> > static void >> > @@ -1343,7 +1339,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > >> > CWARN("Abort reconnection of %s: %s\n", >> > libcfs_nid2str(peer_ni->ibp_nid), reason); >> > - kiblnd_txlist_done(peer_ni->ibp_ni, &txs, -ECONNABORTED); >> > + kiblnd_txlist_done(&txs, -ECONNABORTED); >> > return false; >> > } >> > >> > @@ -1421,7 +1417,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > if (tx) { >> > tx->tx_status = -EHOSTUNREACH; >> > tx->tx_waiting = 0; >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > } >> > return; >> > } >> > @@ -1557,7 +1553,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > if (rc) { >> > CERROR("Can't setup GET sink for %s: %d\n", >> > libcfs_nid2str(target.nid), rc); >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > return -EIO; >> > } >> > >> > @@ -1571,7 +1567,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > if (!tx->tx_lntmsg[1]) { >> > CERROR("Can't create reply for GET -> %s\n", >> > libcfs_nid2str(target.nid)); >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > return -EIO; >> > } >> > >> > @@ -1606,7 +1602,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > if (rc) { >> > CERROR("Can't setup PUT src for %s: %d\n", >> > libcfs_nid2str(target.nid), rc); >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > return -EIO; >> > } >> > >> > @@ -1697,7 +1693,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > >> > if (!nob) { >> > /* No RDMA: local completion may happen now! */ >> > - lnet_finalize(ni, lntmsg, 0); >> > + lnet_finalize(lntmsg, 0); >> > } else { >> > /* RDMA: lnet_finalize(lntmsg) when it completes */ >> > tx->tx_lntmsg[0] = lntmsg; >> > @@ -1707,9 +1703,9 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > return; >> > >> > failed_1: >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > failed_0: >> > - lnet_finalize(ni, lntmsg, -EIO); >> > + lnet_finalize(lntmsg, -EIO); >> > } >> > >> > int >> > @@ -1722,6 +1718,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > struct kib_tx *tx; >> > int nob; >> > int post_credit = IBLND_POSTRX_PEER_CREDIT; >> > + u64 ibprm_cookie; >> > int rc = 0; >> > >> > LASSERT(iov_iter_count(to) <= rlen); >> > @@ -1750,17 +1747,18 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > } >> > >> > rc = 0; >> > - lnet_finalize(ni, lntmsg, 0); >> > + lnet_finalize(lntmsg, 0); >> > break; >> > >> > case IBLND_MSG_PUT_REQ: { >> > + u64 ibprm_cookie = rxmsg->ibm_u.putreq.ibprm_cookie; >> > struct kib_msg *txmsg; >> > struct kib_rdma_desc *rd; >> > >> > if (!iov_iter_count(to)) { >> > - lnet_finalize(ni, lntmsg, 0); >> > - kiblnd_send_completion(rx->rx_conn, IBLND_MSG_PUT_NAK, 0, >> > - rxmsg->ibm_u.putreq.ibprm_cookie); >> > + lnet_finalize(lntmsg, 0); >> > + kiblnd_send_completion(rx->rx_conn, IBLND_MSG_PUT_NAK, >> > + 0, ibprm_cookie); >> > break; >> > } >> > >> > @@ -1788,15 +1786,15 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > if (rc) { >> > CERROR("Can't setup PUT sink for %s: %d\n", >> > libcfs_nid2str(conn->ibc_peer->ibp_nid), rc); >> > - kiblnd_tx_done(ni, tx); >> > + kiblnd_tx_done(tx); >> > /* tell peer_ni it's over */ >> > - kiblnd_send_completion(rx->rx_conn, IBLND_MSG_PUT_NAK, rc, >> > - rxmsg->ibm_u.putreq.ibprm_cookie); >> > + kiblnd_send_completion(rx->rx_conn, IBLND_MSG_PUT_NAK, >> > + rc, ibprm_cookie); >> > break; >> > } >> > >> > nob = offsetof(struct kib_putack_msg, ibpam_rd.rd_frags[rd->rd_nfrags]); >> > - txmsg->ibm_u.putack.ibpam_src_cookie = rxmsg->ibm_u.putreq.ibprm_cookie; >> > + txmsg->ibm_u.putack.ibpam_src_cookie = ibprm_cookie; >> > txmsg->ibm_u.putack.ibpam_dst_cookie = tx->tx_cookie; >> > >> > kiblnd_init_tx_msg(ni, tx, IBLND_MSG_PUT_ACK, nob); >> > @@ -1817,8 +1815,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > } else { >> > /* GET didn't match anything */ >> > kiblnd_send_completion(rx->rx_conn, IBLND_MSG_GET_DONE, >> > - -ENODATA, >> > - rxmsg->ibm_u.get.ibgm_cookie); >> > + -ENODATA, ibprm_cookie); >> > } >> > break; >> > } >> > @@ -2016,7 +2013,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > >> > spin_unlock(&conn->ibc_lock); >> > >> > - kiblnd_txlist_done(conn->ibc_peer->ibp_ni, &zombies, -ECONNABORTED); >> > + kiblnd_txlist_done(&zombies, -ECONNABORTED); >> > } >> > >> > static void >> > @@ -2098,7 +2095,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > CNETERR("Deleting messages for %s: connection failed\n", >> > libcfs_nid2str(peer_ni->ibp_nid)); >> > >> > - kiblnd_txlist_done(peer_ni->ibp_ni, &zombies, -EHOSTUNREACH); >> > + kiblnd_txlist_done(&zombies, -EHOSTUNREACH); >> > } >> > >> > static void >> > @@ -2170,13 +2167,11 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, >> > >> > if (!kiblnd_peer_active(peer_ni) || /* peer_ni has been deleted */ >> > conn->ibc_comms_error) { /* error has happened already */ >> > - struct lnet_ni *ni = peer_ni->ibp_ni; >> > - >> > /* start to shut down connection */ >> > kiblnd_close_conn_locked(conn, -ECONNABORTED); >> > write_unlock_irqrestore(&kiblnd_data.kib_global_lock, flags); >> > >> > - kiblnd_txlist_done(ni, &txs, -ECONNABORTED); >> > + kiblnd_txlist_done(&txs, -ECONNABORTED); >> > >> > return; >> > } >> > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c >> > index 534ba84..9b9cc87 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c >> > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c >> > @@ -1653,8 +1653,7 @@ struct ksock_peer * >> > &conn->ksnc_ipaddr, conn->ksnc_port, >> > iov_iter_count(&conn->ksnc_rx_to), conn->ksnc_rx_nob_left, >> > ktime_get_seconds() - last_rcv); >> > - lnet_finalize(conn->ksnc_peer->ksnp_ni, >> > - conn->ksnc_cookie, -EIO); >> > + lnet_finalize(conn->ksnc_cookie, -EIO); >> > break; >> > case SOCKNAL_RX_LNET_HEADER: >> > if (conn->ksnc_rx_started) >> > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c >> > index 1bf0170..2e99a17 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c >> > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c >> > @@ -343,7 +343,7 @@ struct ksock_tx * >> > >> > ksocknal_free_tx(tx); >> > if (lnetmsg) /* KSOCK_MSG_NOOP go without lnetmsg */ >> > - lnet_finalize(ni, lnetmsg, rc); >> > + lnet_finalize(lnetmsg, rc); >> > } >> > >> > void >> > @@ -1226,7 +1226,7 @@ struct ksock_route * >> > le64_to_cpu(lhdr->src_nid) != id->nid); >> > } >> > >> > - lnet_finalize(conn->ksnc_peer->ksnp_ni, conn->ksnc_cookie, rc); >> > + lnet_finalize(conn->ksnc_cookie, rc); >> > >> > if (rc) { >> > ksocknal_new_packet(conn, 0); >> > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c >> > index d39331f..a213387 100644 >> > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c >> > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c >> > @@ -408,7 +408,7 @@ >> > } >> > rc = ni->ni_net->net_lnd->lnd_recv(ni, private, msg, delayed, &to, rlen); >> > if (rc < 0) >> > - lnet_finalize(ni, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > >> > static void >> > @@ -462,7 +462,7 @@ >> > >> > rc = ni->ni_net->net_lnd->lnd_send(ni, priv, msg); >> > if (rc < 0) >> > - lnet_finalize(ni, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > >> > static int >> > @@ -637,7 +637,7 @@ >> > CNETERR("Dropping message for %s: peer not alive\n", >> > libcfs_id2str(msg->msg_target)); >> > if (do_send) >> > - lnet_finalize(ni, msg, -EHOSTUNREACH); >> > + lnet_finalize(msg, -EHOSTUNREACH); >> > >> > lnet_net_lock(cpt); >> > return -EHOSTUNREACH; >> > @@ -650,7 +650,7 @@ >> > CNETERR("Aborting message for %s: LNetM[DE]Unlink() already called on the MD/ME.\n", >> > libcfs_id2str(msg->msg_target)); >> > if (do_send) >> > - lnet_finalize(ni, msg, -ECANCELED); >> > + lnet_finalize(msg, -ECANCELED); >> > >> > lnet_net_lock(cpt); >> > return -ECANCELED; >> > @@ -915,7 +915,7 @@ >> > lnet_ni_recv(msg->msg_rxni, msg->msg_private, NULL, >> > 0, 0, 0, msg->msg_hdr.payload_length); >> > list_del_init(&msg->msg_list); >> > - lnet_finalize(NULL, msg, -ECANCELED); >> > + lnet_finalize(msg, -ECANCELED); >> > } >> > >> > lnet_net_lock(cpt); >> > @@ -1914,7 +1914,7 @@ >> > libcfs_nid2str(ni->ni_nid), >> > libcfs_id2str(info.mi_id), rc); >> > >> > - lnet_finalize(ni, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > >> > return 0; >> > @@ -2402,7 +2402,7 @@ >> > >> > free_drop: >> > LASSERT(!msg->msg_md); >> > - lnet_finalize(ni, msg, rc); >> > + lnet_finalize(msg, rc); >> > >> > drop: >> > lnet_drop_message(ni, cpt, private, payload_length); >> > @@ -2447,7 +2447,7 @@ >> > * but we still should give error code so lnet_msg_decommit() >> > * can skip counters operations and other checks. >> > */ >> > - lnet_finalize(msg->msg_rxni, msg, -ENOENT); >> > + lnet_finalize(msg, -ENOENT); >> > } >> > } >> > >> > @@ -2605,7 +2605,7 @@ >> > if (rc) { >> > CNETERR("Error sending PUT to %s: %d\n", >> > libcfs_id2str(target), rc); >> > - lnet_finalize(NULL, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > >> > /* completion will be signalled by an event */ >> > @@ -2804,7 +2804,7 @@ struct lnet_msg * >> > if (rc < 0) { >> > CNETERR("Error sending GET to %s: %d\n", >> > libcfs_id2str(target), rc); >> > - lnet_finalize(NULL, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > >> > /* completion will be signalled by an event */ >> > diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c >> > index aa28b6a..00be9ab 100644 >> > --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c >> > +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c >> > @@ -452,7 +452,7 @@ >> > } >> > >> > void >> > -lnet_finalize(struct lnet_ni *ni, struct lnet_msg *msg, int status) >> > +lnet_finalize(struct lnet_msg *msg, int status) >> > { >> > struct lnet_msg_container *container; >> > int my_slot; >> > diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c >> > index 8167980..c8a1eb62 100644 >> > --- a/drivers/staging/lustre/lnet/lnet/lo.c >> > +++ b/drivers/staging/lustre/lnet/lnet/lo.c >> > @@ -62,10 +62,10 @@ >> > sendmsg->msg_offset, >> > iov_iter_count(to)); >> > >> > - lnet_finalize(ni, lntmsg, 0); >> > + lnet_finalize(lntmsg, 0); >> > } >> > >> > - lnet_finalize(ni, sendmsg, 0); >> > + lnet_finalize(sendmsg, 0); >> > return 0; >> > } >> > >> > diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c >> > index 17891f6..3841bac 100644 >> > --- a/drivers/staging/lustre/lnet/lnet/net_fault.c >> > +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c >> > @@ -633,7 +633,7 @@ struct delay_daemon_data { >> > } >> > >> > lnet_drop_message(ni, cpt, msg->msg_private, msg->msg_len); >> > - lnet_finalize(ni, msg, rc); >> > + lnet_finalize(msg, rc); >> > } >> > } >> > >> > -- >> > 1.8.3.1 >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 2 04:35:42 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 02 Oct 2018 14:35:42 +1000 Subject: [lustre-devel] [PATCH 24/30] lustre: llite: rcu-walk check should not depend on statahead In-Reply-To: References: <1537205440-6656-1-git-send-email-jsimmons@infradead.org> <1537205440-6656-25-git-send-email-jsimmons@infradead.org> <87r2hj4j9c.fsf@notabene.neil.brown.name> Message-ID: <8736tprmn5.fsf@notabene.neil.brown.name> On Sat, Sep 29 2018, James Simmons wrote: >> On Mon, Sep 17 2018, James Simmons wrote: >> >> > From: Steve Guminski >> > >> > Moves the check for the LOOKUP_RCU flag, so that it does not depend >> > on the statahead setting. The caller is now informed if rcu-walk >> > was requested but the filesystem does not support it, regardless >> > of whether statahead is enabled or disabled. >> >> Nope, this is wrong. >> >> The filesystem only returns -ECHILD if it couldn't complete the request >> because it would have to block. >> If statahead is disabled, then it can complete the request immediately, >> doesn't need to block, and so doesn't need to return -ECHILD. >> >> Patch deleted. > > Do this patch need to be reverted in the OpenSFS branch or can it be > ignored? It can be ignored. The justification for the patch (and it is definitely nice to see a clearly stated justification!!) was based on a misunderstanding, and as wrong. The code itself introduces a small performance hit when statahead is not being used. I can't really say if it would be noticeable or not, but you could only notice it on a many CPU machine where lots of the filesystem was cached locally, and there was no need to go to the server to service lots of lookups. NeilBrown > >> > Signed-off-by: Steve Guminski >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-8891 >> > Reviewed-on: https://review.whamcloud.com/24195 >> > Reviewed-by: John L. Hammond >> > Reviewed-by: Andreas Dilger >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > drivers/staging/lustre/lustre/llite/dcache.c | 7 +++---- >> > 1 file changed, 3 insertions(+), 4 deletions(-) >> > >> > diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c >> > index 11b82c63..ee1ba16 100644 >> > --- a/drivers/staging/lustre/lustre/llite/dcache.c >> > +++ b/drivers/staging/lustre/lustre/llite/dcache.c >> > @@ -270,13 +270,12 @@ static int ll_revalidate_dentry(struct dentry *dentry, >> > if (lookup_flags & LOOKUP_REVAL) >> > return 0; >> > >> > - if (!dentry_may_statahead(dir, dentry)) >> > - return 1; >> > - >> > if (lookup_flags & LOOKUP_RCU) >> > return -ECHILD; >> > >> > - ll_statahead(dir, &dentry, !d_inode(dentry)); >> > + if (dentry_may_statahead(dir, dentry)) >> > + ll_statahead(dir, &dentry, !d_inode(dentry)); >> > + >> > return 1; >> > } >> > >> > -- >> > 1.8.3.1 >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 00/24] Port Dynamic Discovery to drivers/staging Message-ID: <153895417139.16383.3791701638653772865.stgit@noble> This is a port of the "Dynamic Discovery" series (756abb9cf00b936b3..1c45d9051764e0637ba90b3) to my mainline-linux-with-lustre tree. It is all fairly straight forward, but I don't think I have the hardware to testing properly. And review never hurts. This is all in my lustre-testing branch. Thanks, NeilBrown --- Amir Shehata (2): lustre: lnet: add enhanced statistics lustre: lnet: show peer state John L. Hammond (1): lustre: lnet: balance references in lnet_discover_peer_locked() Olaf Weber (20): lustre: lnet: add lnet_interfaces_max tunable lustre: lnet: configure lnet_interfaces_max tunable from dlc lustre: lnet: add struct lnet_ping_buffer lustre: lnet: automatic sizing of router pinger buffers lustre: lnet: add Multi-Rail and Discovery ping feature bits lustre: lnet: add sanity checks on ping-related constants lustre: lnet: cleanup of lnet_peer_ni_addref/decref_locked() lustre: lnet: rename lnet_add/del_peer_ni_to/from_peer() lustre: lnet: refactor lnet_del_peer_ni() lustre: lnet: refactor lnet_add_peer_ni() lustre: lnet: introduce LNET_PEER_MULTI_RAIL flag bit lustre: lnet: preferred NIs for non-Multi-Rail peers lustre: lnet: add LNET_PEER_CONFIGURED flag lustre: lnet: reference counts on lnet_peer/lnet_peer_net lustre: lnet: add msg_type to lnet_event lustre: lnet: add discovery thread lustre: lnet: add the Push target lustre: lnet: implement Peer Discovery lustre: lnet: add "lnetctl peer list" lustre: lnet: add "lnetctl ping" command Sonia Sharma (1): lustre: lnet: add "lnetctl discover" .../staging/lustre/include/linux/lnet/lib-lnet.h | 156 + .../staging/lustre/include/linux/lnet/lib-types.h | 258 ++ .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 8 .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 10 .../lustre/include/uapi/linux/lnet/lnet-types.h | 42 .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 2 .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 22 .../staging/lustre/lnet/klnds/socklnd/socklnd.h | 4 .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 2 .../lustre/lnet/klnds/socklnd/socklnd_modparams.c | 2 .../lustre/lnet/klnds/socklnd/socklnd_proto.c | 4 drivers/staging/lustre/lnet/lnet/api-ni.c | 907 +++++- drivers/staging/lustre/lnet/lnet/config.c | 10 drivers/staging/lustre/lnet/lnet/lib-move.c | 242 +- drivers/staging/lustre/lnet/lnet/lib-msg.c | 17 drivers/staging/lustre/lnet/lnet/net_fault.c | 3 drivers/staging/lustre/lnet/lnet/peer.c | 3002 +++++++++++++++++--- drivers/staging/lustre/lnet/lnet/router.c | 174 + 19 files changed, 4056 insertions(+), 811 deletions(-) -- Signature From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 01/24] lustre: lnet: add lnet_interfaces_max tunable In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437756.16383.14536895691182127915.stgit@noble> From: Olaf Weber Add an lnet_interfaces_max tunable value, that describes the maximum number of interfaces per node. This tunable is primarily useful for sanity checks prior to allocating memory. Allow lnet_interfaces_max to be set and get from the sysfs interface. Add LNET_INTERFACES_MIN, value 16, as the minimum value. Add LNET_INTERFACES_MAX_DEFAULT, value 200, as the default value. This value was chosen to ensure that the size of an LNet ping message with any associated LND overhead would fit in 4096 bytes. (The LNET_INTERFACES_MAX name was not reused to allow for the early detection of issues when merging code that uses it.) Rename LNET_NUM_INTERFACES to LNET_INTERFACES_NUM WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Signed-off-by: Amir Shehata Reviewed-on: https://review.whamcloud.com/25770 Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-types.h | 2 + .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 4 +-- .../lustre/include/uapi/linux/lnet/lnet-types.h | 7 ++++ .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 + .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 22 +++++++------- .../staging/lustre/lnet/klnds/socklnd/socklnd.h | 4 +-- .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 2 + .../lustre/lnet/klnds/socklnd/socklnd_proto.c | 4 +-- drivers/staging/lustre/lnet/lnet/api-ni.c | 32 +++++++++++++++++++- drivers/staging/lustre/lnet/lnet/config.c | 10 +++--- 10 files changed, 62 insertions(+), 27 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 7219a7bacf6e..7b11c31f0029 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -371,7 +371,7 @@ struct lnet_ni { * equivalent interfaces to use * This is an array because socklnd bonding can still be configured */ - char *ni_interfaces[LNET_NUM_INTERFACES]; + char *ni_interfaces[LNET_INTERFACES_NUM]; /* original net namespace */ struct net *ni_net_ns; }; diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h index 8f03aa3c5676..d88b30d2e76c 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h @@ -81,7 +81,7 @@ struct lnet_ioctl_config_lnd_tunables { }; struct lnet_ioctl_net_config { - char ni_interfaces[LNET_NUM_INTERFACES][LNET_MAX_STR_LEN]; + char ni_interfaces[LNET_INTERFACES_NUM][LNET_MAX_STR_LEN]; __u32 ni_status; __u32 ni_cpts[LNET_MAX_SHOW_NUM_CPT]; char cfg_bulk[0]; @@ -184,7 +184,7 @@ struct lnet_ioctl_element_msg_stats { struct lnet_ioctl_config_ni { struct libcfs_ioctl_hdr lic_cfg_hdr; lnet_nid_t lic_nid; - char lic_ni_intf[LNET_NUM_INTERFACES][LNET_MAX_STR_LEN]; + char lic_ni_intf[LNET_INTERFACES_NUM][LNET_MAX_STR_LEN]; char lic_legacy_ip2nets[LNET_MAX_STR_LEN]; __u32 lic_cpts[LNET_MAX_SHOW_NUM_CPT]; __u32 lic_ncpts; diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h index f8a873bab135..6ee60d07ff84 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h @@ -264,7 +264,12 @@ struct lnet_counters { #define LNET_NI_STATUS_DOWN 0xdeadface #define LNET_NI_STATUS_INVALID 0x00000000 -#define LNET_NUM_INTERFACES 16 +#define LNET_INTERFACES_NUM 16 + +/* The minimum number of interfaces per node supported by LNet. */ +#define LNET_INTERFACES_MIN 16 +/* The default - arbitrary - value of the lnet_max_interfaces tunable. */ +#define LNET_INTERFACES_MAX_DEFAULT 200 /** * Objects maintained by the LNet are accessed through handles. Handle types diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index c20766379323..bf969b3891a9 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -2915,7 +2915,7 @@ static int kiblnd_startup(struct lnet_ni *ni) if (ni->ni_interfaces[0]) { /* Use the IPoIB interface specified in 'networks=' */ - BUILD_BUG_ON(LNET_NUM_INTERFACES <= 1); + BUILD_BUG_ON(LNET_INTERFACES_NUM <= 1); if (ni->ni_interfaces[1]) { CERROR("Multiple interfaces not supported\n"); goto failed; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c index b2f0148d0087..ff8d73295fff 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c @@ -53,7 +53,7 @@ ksocknal_ip2iface(struct lnet_ni *ni, __u32 ip) struct ksock_interface *iface; for (i = 0; i < net->ksnn_ninterfaces; i++) { - LASSERT(i < LNET_NUM_INTERFACES); + LASSERT(i < LNET_INTERFACES_NUM); iface = &net->ksnn_interfaces[i]; if (iface->ksni_ipaddr == ip) @@ -221,7 +221,7 @@ ksocknal_unlink_peer_locked(struct ksock_peer *peer_ni) struct ksock_interface *iface; for (i = 0; i < peer_ni->ksnp_n_passive_ips; i++) { - LASSERT(i < LNET_NUM_INTERFACES); + LASSERT(i < LNET_INTERFACES_NUM); ip = peer_ni->ksnp_passive_ips[i]; iface = ksocknal_ip2iface(peer_ni->ksnp_ni, ip); @@ -689,7 +689,7 @@ ksocknal_local_ipvec(struct lnet_ni *ni, __u32 *ipaddrs) read_lock(&ksocknal_data.ksnd_global_lock); nip = net->ksnn_ninterfaces; - LASSERT(nip <= LNET_NUM_INTERFACES); + LASSERT(nip <= LNET_INTERFACES_NUM); /* * Only offer interfaces for additional connections if I have @@ -770,8 +770,8 @@ ksocknal_select_ips(struct ksock_peer *peer_ni, __u32 *peerips, int n_peerips) */ write_lock_bh(global_lock); - LASSERT(n_peerips <= LNET_NUM_INTERFACES); - LASSERT(net->ksnn_ninterfaces <= LNET_NUM_INTERFACES); + LASSERT(n_peerips <= LNET_INTERFACES_NUM); + LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM); /* * Only match interfaces for additional connections @@ -890,7 +890,7 @@ ksocknal_create_routes(struct ksock_peer *peer_ni, int port, return; } - LASSERT(npeer_ipaddrs <= LNET_NUM_INTERFACES); + LASSERT(npeer_ipaddrs <= LNET_INTERFACES_NUM); for (i = 0; i < npeer_ipaddrs; i++) { if (newroute) { @@ -919,7 +919,7 @@ ksocknal_create_routes(struct ksock_peer *peer_ni, int port, best_nroutes = 0; best_netmatch = 0; - LASSERT(net->ksnn_ninterfaces <= LNET_NUM_INTERFACES); + LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM); /* Select interface to connect from */ for (j = 0; j < net->ksnn_ninterfaces; j++) { @@ -1060,7 +1060,7 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_route *route, atomic_set(&conn->ksnc_tx_nob, 0); hello = kvzalloc(offsetof(struct ksock_hello_msg, - kshm_ips[LNET_NUM_INTERFACES]), + kshm_ips[LNET_INTERFACES_NUM]), GFP_KERNEL); if (!hello) { rc = -ENOMEM; @@ -1983,7 +1983,7 @@ ksocknal_add_interface(struct lnet_ni *ni, __u32 ipaddress, __u32 netmask) if (iface) { /* silently ignore dups */ rc = 0; - } else if (net->ksnn_ninterfaces == LNET_NUM_INTERFACES) { + } else if (net->ksnn_ninterfaces == LNET_INTERFACES_NUM) { rc = -ENOSPC; } else { iface = &net->ksnn_interfaces[net->ksnn_ninterfaces++]; @@ -2624,7 +2624,7 @@ ksocknal_enumerate_interfaces(struct ksock_net *net, char *iname) continue; } - if (j == LNET_NUM_INTERFACES) { + if (j == LNET_INTERFACES_NUM) { CWARN("Ignoring interface %s (too many interfaces)\n", name); continue; @@ -2812,7 +2812,7 @@ ksocknal_startup(struct lnet_ni *ni) net->ksnn_ninterfaces = rc; } else { - for (i = 0; i < LNET_NUM_INTERFACES; i++) { + for (i = 0; i < LNET_INTERFACES_NUM; i++) { if (!ni->ni_interfaces[i]) break; rc = ksocknal_enumerate_interfaces(net, ni->ni_interfaces[i]); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h index 82e3523f6463..297d1e5af1bd 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h @@ -173,7 +173,7 @@ struct ksock_net { int ksnn_npeers; /* # peers */ int ksnn_shutdown; /* shutting down? */ int ksnn_ninterfaces; /* IP interfaces */ - struct ksock_interface ksnn_interfaces[LNET_NUM_INTERFACES]; + struct ksock_interface ksnn_interfaces[LNET_INTERFACES_NUM]; }; /** connd timeout */ @@ -441,7 +441,7 @@ struct ksock_peer { int ksnp_n_passive_ips; /* # of... */ /* preferred local interfaces */ - u32 ksnp_passive_ips[LNET_NUM_INTERFACES]; + u32 ksnp_passive_ips[LNET_INTERFACES_NUM]; }; struct ksock_connreq { diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index dc9a12910a8d..c401896bf649 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -1579,7 +1579,7 @@ ksocknal_send_hello(struct lnet_ni *ni, struct ksock_conn *conn, /* CAVEAT EMPTOR: this byte flips 'ipaddrs' */ struct ksock_net *net = (struct ksock_net *)ni->ni_data; - LASSERT(hello->kshm_nips <= LNET_NUM_INTERFACES); + LASSERT(hello->kshm_nips <= LNET_INTERFACES_NUM); /* rely on caller to hold a ref on socket so it wouldn't disappear */ LASSERT(conn->ksnc_proto); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c index 10a2757895f3..54ec5d0a85c8 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c @@ -614,7 +614,7 @@ ksocknal_recv_hello_v1(struct ksock_conn *conn, struct ksock_hello_msg *hello, hello->kshm_nips = le32_to_cpu(hdr->payload_length) / sizeof(__u32); - if (hello->kshm_nips > LNET_NUM_INTERFACES) { + if (hello->kshm_nips > LNET_INTERFACES_NUM) { CERROR("Bad nips %d from ip %pI4h\n", hello->kshm_nips, &conn->ksnc_ipaddr); rc = -EPROTO; @@ -684,7 +684,7 @@ ksocknal_recv_hello_v2(struct ksock_conn *conn, struct ksock_hello_msg *hello, __swab32s(&hello->kshm_nips); } - if (hello->kshm_nips > LNET_NUM_INTERFACES) { + if (hello->kshm_nips > LNET_INTERFACES_NUM) { CERROR("Bad nips %d from ip %pI4h\n", hello->kshm_nips, &conn->ksnc_ipaddr); return -EPROTO; diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index b37abdedccaa..6a692d5c4608 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -34,6 +34,7 @@ #define DEBUG_SUBSYSTEM S_LNET #include #include +#include #include #include @@ -70,6 +71,13 @@ module_param(lnet_numa_range, uint, 0444); MODULE_PARM_DESC(lnet_numa_range, "NUMA range to consider during Multi-Rail selection"); +static int lnet_interfaces_max = LNET_INTERFACES_MAX_DEFAULT; +static int intf_max_set(const char *val, const struct kernel_param *kp); +module_param_call(lnet_interfaces_max, intf_max_set, param_get_int, + &lnet_interfaces_max, 0644); +MODULE_PARM_DESC(lnet_interfaces_max, + "Maximum number of interfaces in a node."); + /* * This sequence number keeps track of how many times DLC was used to * update the local NIs. It is incremented when a NI is added or @@ -82,6 +90,28 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); static int lnet_ping(struct lnet_process_id id, signed long timeout, struct lnet_process_id __user *ids, int n_ids); +static int +intf_max_set(const char *val, const struct kernel_param *kp) +{ + int value, rc; + + rc = kstrtoint(val, 0, &value); + if (rc) { + CERROR("Invalid module parameter value for 'lnet_interfaces_max'\n"); + return rc; + } + + if (value < LNET_INTERFACES_MIN) { + CWARN("max interfaces provided are too small, setting to %d\n", + LNET_INTERFACES_MIN); + value = LNET_INTERFACES_MIN; + } + + *(int *)kp->arg = value; + + return 0; +} + static char * lnet_get_routes(void) { @@ -2924,7 +2954,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]); /* n_ids limit is arbitrary */ - if (n_ids <= 0 || n_ids > 20 || id.nid == LNET_NID_ANY) + if (n_ids <= 0 || n_ids > lnet_interfaces_max || id.nid == LNET_NID_ANY) return -EINVAL; if (id.pid == LNET_PID_ANY) diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c index 3ea56c81ec0e..087d9a8a6b6a 100644 --- a/drivers/staging/lustre/lnet/lnet/config.c +++ b/drivers/staging/lustre/lnet/lnet/config.c @@ -123,10 +123,10 @@ lnet_ni_unique_net(struct list_head *nilist, char *iface) /* check that the NI is unique to the interfaces with in the same NI. * This is only a consideration if use_tcp_bonding is set */ static bool -lnet_ni_unique_ni(char *iface_list[LNET_NUM_INTERFACES], char *iface) +lnet_ni_unique_ni(char *iface_list[LNET_INTERFACES_NUM], char *iface) { int i; - for (i = 0; i < LNET_NUM_INTERFACES; i++) { + for (i = 0; i < LNET_INTERFACES_NUM; i++) { if (iface_list[i] && strncmp(iface_list[i], iface, strlen(iface)) == 0) return false; @@ -304,7 +304,7 @@ lnet_ni_free(struct lnet_ni *ni) kfree(ni->ni_cpts); - for (i = 0; i < LNET_NUM_INTERFACES && ni->ni_interfaces[i]; i++) + for (i = 0; i < LNET_INTERFACES_NUM && ni->ni_interfaces[i]; i++) kfree(ni->ni_interfaces[i]); /* release reference to net namespace */ @@ -397,11 +397,11 @@ lnet_ni_add_interface(struct lnet_ni *ni, char *iface) * can free the tokens at the end of the function. * The newly allocated ni_interfaces[] can be * freed when freeing the NI */ - while (niface < LNET_NUM_INTERFACES && + while (niface < LNET_INTERFACES_NUM && ni->ni_interfaces[niface]) niface++; - if (niface >= LNET_NUM_INTERFACES) { + if (niface >= LNET_INTERFACES_NUM) { LCONSOLE_ERROR_MSG(0x115, "Too many interfaces " "for net %s\n", libcfs_net2str(LNET_NIDNET(ni->ni_nid))); From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 02/24] lustre: lnet: configure lnet_interfaces_max tunable from dlc In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437761.16383.2145517278397754849.stgit@noble> From: Olaf Weber Added the ability to configure lnet_interfaces_max from DLC. Combined the configure and show of numa range and max interfaces under a "global" YAML element when configuring using YAML. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Amir Shehata Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25771 Signed-off-by: NeilBrown --- .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 6 +++--- drivers/staging/lustre/lnet/lnet/api-ni.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h index d88b30d2e76c..706892ca7efb 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h @@ -230,9 +230,9 @@ struct lnet_ioctl_peer_cfg { void __user *prcfg_bulk; }; -struct lnet_ioctl_numa_range { - struct libcfs_ioctl_hdr nr_hdr; - __u32 nr_range; +struct lnet_ioctl_set_value { + struct libcfs_ioctl_hdr sv_hdr; + __u32 sv_value; }; struct lnet_ioctl_lnet_stats { diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 6a692d5c4608..8b6400da2836 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -2708,24 +2708,24 @@ LNetCtl(unsigned int cmd, void *arg) return rc; case IOC_LIBCFS_SET_NUMA_RANGE: { - struct lnet_ioctl_numa_range *numa; + struct lnet_ioctl_set_value *numa; numa = arg; - if (numa->nr_hdr.ioc_len != sizeof(*numa)) + if (numa->sv_hdr.ioc_len != sizeof(*numa)) return -EINVAL; - mutex_lock(&the_lnet.ln_api_mutex); - lnet_numa_range = numa->nr_range; - mutex_unlock(&the_lnet.ln_api_mutex); + lnet_net_lock(LNET_LOCK_EX); + lnet_numa_range = numa->sv_value; + lnet_net_unlock(LNET_LOCK_EX); return 0; } case IOC_LIBCFS_GET_NUMA_RANGE: { - struct lnet_ioctl_numa_range *numa; + struct lnet_ioctl_set_value *numa; numa = arg; - if (numa->nr_hdr.ioc_len != sizeof(*numa)) + if (numa->sv_hdr.ioc_len != sizeof(*numa)) return -EINVAL; - numa->nr_range = lnet_numa_range; + numa->sv_value = lnet_numa_range; return 0; } From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 03/24] lustre: lnet: add struct lnet_ping_buffer In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437765.16383.7644707942018591818.stgit@noble> From: Olaf Weber The Multi-Rail code will use the ping target buffer also as the source of data to push to other nodes. This means that there will be multiple MDs referencing the same buffer, and care must be taken to ensure that the buffer is not freed while any such reference remains. Encapsulate the struct lnet_ping_info (aka lnet_ping_info_t) in a struct lnet_ping_buffer. This adds a reference count, and the number of NIDs for the encapsulated lnet_ping_info has been sized. For sizing the buffer the constant LNET_PINGINFO_SIZE is replaced with LNET_PING_INFO_SIZE(NNIS). WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25773 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 22 + .../staging/lustre/include/linux/lnet/lib-types.h | 40 ++ drivers/staging/lustre/lnet/lnet/api-ni.c | 345 +++++++++++--------- drivers/staging/lustre/lnet/lnet/router.c | 94 +++-- 4 files changed, 301 insertions(+), 200 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 16e64d83840d..2e2b5ed27116 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -634,7 +634,27 @@ int lnet_peer_buffer_credits(struct lnet_net *net); int lnet_router_checker_start(void); void lnet_router_checker_stop(void); void lnet_router_ni_update_locked(struct lnet_peer_ni *gw, __u32 net); -void lnet_swap_pinginfo(struct lnet_ping_info *info); +void lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf); + +int lnet_ping_info_validate(struct lnet_ping_info *pinfo); +struct lnet_ping_buffer *lnet_ping_buffer_alloc(int nnis, gfp_t gfp); +void lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf); + +static inline void lnet_ping_buffer_addref(struct lnet_ping_buffer *pbuf) +{ + atomic_inc(&pbuf->pb_refcnt); +} + +static inline void lnet_ping_buffer_decref(struct lnet_ping_buffer *pbuf) +{ + if (atomic_dec_and_test(&pbuf->pb_refcnt)) + lnet_ping_buffer_free(pbuf); +} + +static inline int lnet_ping_buffer_numref(struct lnet_ping_buffer *pbuf) +{ + return atomic_read(&pbuf->pb_refcnt); +} int lnet_parse_ip2nets(char **networksp, char *ip2nets); int lnet_parse_routes(char *route_str, int *im_a_router); diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 7b11c31f0029..ab8c6d66cdbf 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -387,12 +387,32 @@ struct lnet_ni { #define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ #define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ -#define LNET_PING_FEAT_MASK (LNET_PING_FEAT_BASE | \ - LNET_PING_FEAT_NI_STATUS) +#define LNET_PING_INFO_SIZE(NNIDS) \ + offsetof(struct lnet_ping_info, pi_ni[NNIDS]) +#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) +#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) + +/* + * Descriptor of a ping info buffer: keep a separate indicator of the + * size and a reference count. The type is used both as a source and + * sink of data, so we need to keep some information outside of the + * area that may be overwritten by network data. + */ +struct lnet_ping_buffer { + int pb_nnis; + atomic_t pb_refcnt; + struct lnet_ping_info pb_info; +}; + +#define LNET_PING_BUFFER_SIZE(NNIDS) \ + offsetof(struct lnet_ping_buffer, pb_info.pi_ni[NNIDS]) +#define LNET_PING_BUFFER_LONI(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_nid) +#define LNET_PING_BUFFER_SEQNO(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_status) + /* router checker data, per router */ -#define LNET_MAX_RTR_NIS 16 -#define LNET_PINGINFO_SIZE offsetof(struct lnet_ping_info, pi_ni[LNET_MAX_RTR_NIS]) +#define LNET_MAX_RTR_NIS LNET_INTERFACES_MIN +#define LNET_RTR_PINGINFO_SIZE LNET_PING_INFO_SIZE(LNET_MAX_RTR_NIS) struct lnet_rc_data { /* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */ struct list_head rcd_list; @@ -401,7 +421,7 @@ struct lnet_rc_data { /* reference to gateway */ struct lnet_peer_ni *rcd_gateway; /* ping buffer */ - struct lnet_ping_info *rcd_pinginfo; + struct lnet_ping_buffer *rcd_pingbuffer; }; struct lnet_peer_ni { @@ -792,9 +812,17 @@ struct lnet { /* percpt router buffer pools */ struct lnet_rtrbufpool **ln_rtrpools; + /* + * Ping target / Push source + * + * The ping target and push source share a single buffer. The + * ln_ping_target is protected against concurrent updates by + * ln_api_mutex. + */ struct lnet_handle_md ln_ping_target_md; struct lnet_handle_eq ln_ping_target_eq; - struct lnet_ping_info *ln_ping_info; + struct lnet_ping_buffer *ln_ping_target; + atomic_t ln_ping_target_seqno; /* router checker startup/shutdown state */ enum lnet_rc_state ln_rc_state; diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 8b6400da2836..ca28ad75fe2b 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -902,25 +902,44 @@ lnet_count_acceptor_nets(void) return count; } -static struct lnet_ping_info * -lnet_ping_info_create(int num_ni) +struct lnet_ping_buffer * +lnet_ping_buffer_alloc(int nnis, gfp_t gfp) { - struct lnet_ping_info *ping_info; - unsigned int infosz; + struct lnet_ping_buffer *pbuf; - infosz = offsetof(struct lnet_ping_info, pi_ni[num_ni]); - ping_info = kvzalloc(infosz, GFP_KERNEL); - if (!ping_info) { - CERROR("Can't allocate ping info[%d]\n", num_ni); + pbuf = kmalloc(LNET_PING_BUFFER_SIZE(nnis), gfp); + if (pbuf) { + pbuf->pb_nnis = nnis; + atomic_set(&pbuf->pb_refcnt, 1); + } + + return pbuf; +} + +void +lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf) +{ + LASSERT(lnet_ping_buffer_numref(pbuf) == 0); + kfree(pbuf); +} + +static struct lnet_ping_buffer * +lnet_ping_target_create(int nnis) +{ + struct lnet_ping_buffer *pbuf; + + pbuf = lnet_ping_buffer_alloc(nnis, GFP_KERNEL); + if (!pbuf) { + CERROR("Can't allocate ping source [%d]\n", nnis); return NULL; } - ping_info->pi_nnis = num_ni; - ping_info->pi_pid = the_lnet.ln_pid; - ping_info->pi_magic = LNET_PROTO_PING_MAGIC; - ping_info->pi_features = LNET_PING_FEAT_NI_STATUS; + pbuf->pb_info.pi_nnis = nnis; + pbuf->pb_info.pi_pid = the_lnet.ln_pid; + pbuf->pb_info.pi_magic = LNET_PROTO_PING_MAGIC; + pbuf->pb_info.pi_features = LNET_PING_FEAT_NI_STATUS; - return ping_info; + return pbuf; } static inline int @@ -966,14 +985,25 @@ lnet_get_ni_count(void) return count; } -static inline void -lnet_ping_info_free(struct lnet_ping_info *pinfo) +int +lnet_ping_info_validate(struct lnet_ping_info *pinfo) { - kvfree(pinfo); + if (!pinfo) + return -EINVAL; + if (pinfo->pi_magic != LNET_PROTO_PING_MAGIC) + return -EPROTO; + if (!(pinfo->pi_features & LNET_PING_FEAT_NI_STATUS)) + return -EPROTO; + /* Loopback is guaranteed to be present */ + if (pinfo->pi_nnis < 1 || pinfo->pi_nnis > lnet_interfaces_max) + return -ERANGE; + if (LNET_NETTYP(LNET_NIDNET(LNET_PING_INFO_LONI(pinfo))) != LOLND) + return -EPROTO; + return 0; } static void -lnet_ping_info_destroy(void) +lnet_ping_target_destroy(void) { struct lnet_net *net; struct lnet_ni *ni; @@ -988,25 +1018,25 @@ lnet_ping_info_destroy(void) } } - lnet_ping_info_free(the_lnet.ln_ping_info); - the_lnet.ln_ping_info = NULL; + lnet_ping_buffer_decref(the_lnet.ln_ping_target); + the_lnet.ln_ping_target = NULL; lnet_net_unlock(LNET_LOCK_EX); } static void -lnet_ping_event_handler(struct lnet_event *event) +lnet_ping_target_event_handler(struct lnet_event *event) { - struct lnet_ping_info *pinfo = event->md.user_ptr; + struct lnet_ping_buffer *pbuf = event->md.user_ptr; if (event->unlinked) - pinfo->pi_features = LNET_PING_FEAT_INVAL; + lnet_ping_buffer_decref(pbuf); } static int -lnet_ping_info_setup(struct lnet_ping_info **ppinfo, - struct lnet_handle_md *md_handle, - int ni_count, bool set_eq) +lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf, + struct lnet_handle_md *ping_mdh, + int ni_count, bool set_eq) { struct lnet_process_id id = { .nid = LNET_NID_ANY, .pid = LNET_PID_ANY }; @@ -1015,94 +1045,98 @@ lnet_ping_info_setup(struct lnet_ping_info **ppinfo, int rc, rc2; if (set_eq) { - rc = LNetEQAlloc(0, lnet_ping_event_handler, + rc = LNetEQAlloc(0, lnet_ping_target_event_handler, &the_lnet.ln_ping_target_eq); if (rc) { - CERROR("Can't allocate ping EQ: %d\n", rc); + CERROR("Can't allocate ping buffer EQ: %d\n", rc); return rc; } } - *ppinfo = lnet_ping_info_create(ni_count); - if (!*ppinfo) { + *ppbuf = lnet_ping_target_create(ni_count); + if (!*ppbuf) { rc = -ENOMEM; - goto failed_0; + goto fail_free_eq; } + /* Ping target ME/MD */ rc = LNetMEAttach(LNET_RESERVED_PORTAL, id, LNET_PROTO_PING_MATCHBITS, 0, LNET_UNLINK, LNET_INS_AFTER, &me_handle); if (rc) { - CERROR("Can't create ping ME: %d\n", rc); - goto failed_1; + CERROR("Can't create ping target ME: %d\n", rc); + goto fail_decref_ping_buffer; } /* initialize md content */ - md.start = *ppinfo; - md.length = offsetof(struct lnet_ping_info, - pi_ni[(*ppinfo)->pi_nnis]); + md.start = &(*ppbuf)->pb_info; + md.length = LNET_PING_INFO_SIZE((*ppbuf)->pb_nnis); md.threshold = LNET_MD_THRESH_INF; md.max_size = 0; md.options = LNET_MD_OP_GET | LNET_MD_TRUNCATE | LNET_MD_MANAGE_REMOTE; - md.user_ptr = NULL; md.eq_handle = the_lnet.ln_ping_target_eq; - md.user_ptr = *ppinfo; + md.user_ptr = *ppbuf; - rc = LNetMDAttach(me_handle, md, LNET_RETAIN, md_handle); + rc = LNetMDAttach(me_handle, md, LNET_RETAIN, ping_mdh); if (rc) { - CERROR("Can't attach ping MD: %d\n", rc); - goto failed_2; + CERROR("Can't attach ping target MD: %d\n", rc); + goto fail_unlink_ping_me; } + lnet_ping_buffer_addref(*ppbuf); return 0; -failed_2: +fail_unlink_ping_me: rc2 = LNetMEUnlink(me_handle); LASSERT(!rc2); -failed_1: - lnet_ping_info_free(*ppinfo); - *ppinfo = NULL; -failed_0: - if (set_eq) - LNetEQFree(the_lnet.ln_ping_target_eq); +fail_decref_ping_buffer: + LASSERT(lnet_ping_buffer_numref(*ppbuf) == 1); + lnet_ping_buffer_decref(*ppbuf); + *ppbuf = NULL; +fail_free_eq: + if (set_eq) { + rc2 = LNetEQFree(the_lnet.ln_ping_target_eq); + LASSERT(rc2 == 0); + } return rc; } static void -lnet_ping_md_unlink(struct lnet_ping_info *pinfo, - struct lnet_handle_md *md_handle) +lnet_ping_md_unlink(struct lnet_ping_buffer *pbuf, + struct lnet_handle_md *ping_mdh) { - LNetMDUnlink(*md_handle); - LNetInvalidateMDHandle(md_handle); + LNetMDUnlink(*ping_mdh); + LNetInvalidateMDHandle(ping_mdh); - /* NB md could be busy; this just starts the unlink */ - while (pinfo->pi_features != LNET_PING_FEAT_INVAL) { - CDEBUG(D_NET, "Still waiting for ping MD to unlink\n"); + /* NB the MD could be busy; this just starts the unlink */ + while (lnet_ping_buffer_numref(pbuf) > 1) { + CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n"); schedule_timeout_idle(HZ); } } static void -lnet_ping_info_install_locked(struct lnet_ping_info *ping_info) +lnet_ping_target_install_locked(struct lnet_ping_buffer *pbuf) { struct lnet_ni_status *ns; struct lnet_ni *ni; struct lnet_net *net; int i = 0; + int rc; list_for_each_entry(net, &the_lnet.ln_nets, net_list) { list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { - LASSERT(i < ping_info->pi_nnis); + LASSERT(i < pbuf->pb_nnis); - ns = &ping_info->pi_ni[i]; + ns = &pbuf->pb_info.pi_ni[i]; ns->ns_nid = ni->ni_nid; lnet_ni_lock(ni); ns->ns_status = ni->ni_status ? - ni->ni_status->ns_status : + ni->ni_status->ns_status : LNET_NI_STATUS_UP; ni->ni_status = ns; lnet_ni_unlock(ni); @@ -1110,35 +1144,47 @@ lnet_ping_info_install_locked(struct lnet_ping_info *ping_info) i++; } } + /* + * We (ab)use the ns_status of the loopback interface to + * transmit the sequence number. The first interface listed + * must be the loopback interface. + */ + rc = lnet_ping_info_validate(&pbuf->pb_info); + if (rc) { + LCONSOLE_EMERG("Invalid ping target: %d\n", rc); + LBUG(); + } + LNET_PING_BUFFER_SEQNO(pbuf) = + atomic_inc_return(&the_lnet.ln_ping_target_seqno); } static void -lnet_ping_target_update(struct lnet_ping_info *pinfo, - struct lnet_handle_md md_handle) +lnet_ping_target_update(struct lnet_ping_buffer *pbuf, + struct lnet_handle_md ping_mdh) { - struct lnet_ping_info *old_pinfo = NULL; - struct lnet_handle_md old_md; + struct lnet_ping_buffer *old_pbuf = NULL; + struct lnet_handle_md old_ping_md; /* switch the NIs to point to the new ping info created */ lnet_net_lock(LNET_LOCK_EX); if (!the_lnet.ln_routing) - pinfo->pi_features |= LNET_PING_FEAT_RTE_DISABLED; - lnet_ping_info_install_locked(pinfo); + pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; + lnet_ping_target_install_locked(pbuf); - if (the_lnet.ln_ping_info) { - old_pinfo = the_lnet.ln_ping_info; - old_md = the_lnet.ln_ping_target_md; + if (the_lnet.ln_ping_target) { + old_pbuf = the_lnet.ln_ping_target; + old_ping_md = the_lnet.ln_ping_target_md; } - the_lnet.ln_ping_target_md = md_handle; - the_lnet.ln_ping_info = pinfo; + the_lnet.ln_ping_target_md = ping_mdh; + the_lnet.ln_ping_target = pbuf; lnet_net_unlock(LNET_LOCK_EX); - if (old_pinfo) { - /* unlink the old ping info */ - lnet_ping_md_unlink(old_pinfo, &old_md); - lnet_ping_info_free(old_pinfo); + if (old_pbuf) { + /* unlink and free the old ping info */ + lnet_ping_md_unlink(old_pbuf, &old_ping_md); + lnet_ping_buffer_decref(old_pbuf); } } @@ -1147,13 +1193,13 @@ lnet_ping_target_fini(void) { int rc; - lnet_ping_md_unlink(the_lnet.ln_ping_info, + lnet_ping_md_unlink(the_lnet.ln_ping_target, &the_lnet.ln_ping_target_md); rc = LNetEQFree(the_lnet.ln_ping_target_eq); LASSERT(!rc); - lnet_ping_info_destroy(); + lnet_ping_target_destroy(); } static int @@ -1745,8 +1791,8 @@ LNetNIInit(lnet_pid_t requested_pid) int im_a_router = 0; int rc; int ni_count; - struct lnet_ping_info *pinfo; - struct lnet_handle_md md_handle; + struct lnet_ping_buffer *pbuf; + struct lnet_handle_md ping_mdh; struct list_head net_head; struct lnet_net *net; @@ -1823,11 +1869,11 @@ LNetNIInit(lnet_pid_t requested_pid) the_lnet.ln_refcount = 1; /* Now I may use my own API functions... */ - rc = lnet_ping_info_setup(&pinfo, &md_handle, ni_count, true); + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, ni_count, true); if (rc) goto err_acceptor_stop; - lnet_ping_target_update(pinfo, md_handle); + lnet_ping_target_update(pbuf, ping_mdh); rc = lnet_router_checker_start(); if (rc) @@ -1936,7 +1982,10 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni, } cfg_ni->lic_nid = ni->ni_nid; - cfg_ni->lic_status = ni->ni_status->ns_status; + if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND) + cfg_ni->lic_status = LNET_NI_STATUS_UP; + else + cfg_ni->lic_status = ni->ni_status->ns_status; cfg_ni->lic_tcp_bonding = use_tcp_bonding; cfg_ni->lic_dev_cpt = ni->ni_dev_cpt; @@ -2021,7 +2070,10 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni, config->cfg_config_u.cfg_net.net_peer_rtr_credits = ni->ni_net->net_tunables.lct_peer_rtr_credits; - net_config->ni_status = ni->ni_status->ns_status; + if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND) + net_config->ni_status = LNET_NI_STATUS_UP; + else + net_config->ni_status = ni->ni_status->ns_status; if (ni->ni_cpts) { int num_cpts = min(ni->ni_ncpts, LNET_MAX_SHOW_NUM_CPT); @@ -2172,8 +2224,8 @@ static int lnet_add_net_common(struct lnet_net *net, struct lnet_ioctl_config_lnd_tunables *tun) { u32 net_id; - struct lnet_ping_info *pinfo; - struct lnet_handle_md md_handle; + struct lnet_ping_buffer *pbuf; + struct lnet_handle_md ping_mdh; int rc; struct lnet_remotenet *rnet; int net_ni_count; @@ -2195,7 +2247,7 @@ static int lnet_add_net_common(struct lnet_net *net, /* * make sure you calculate the correct number of slots in the ping - * info. Since the ping info is a flattened list of all the NIs, + * buffer. Since the ping info is a flattened list of all the NIs, * we should allocate enough slots to accomodate the number of NIs * which will be added. * @@ -2204,9 +2256,9 @@ static int lnet_add_net_common(struct lnet_net *net, */ net_ni_count = lnet_get_net_ni_count_pre(net); - rc = lnet_ping_info_setup(&pinfo, &md_handle, - net_ni_count + lnet_get_ni_count(), - false); + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, + net_ni_count + lnet_get_ni_count(), + false); if (rc < 0) { lnet_net_free(net); return rc; @@ -2257,13 +2309,13 @@ static int lnet_add_net_common(struct lnet_net *net, lnet_peer_net_added(net); lnet_net_unlock(LNET_LOCK_EX); - lnet_ping_target_update(pinfo, md_handle); + lnet_ping_target_update(pbuf, ping_mdh); return 0; failed: - lnet_ping_md_unlink(pinfo, &md_handle); - lnet_ping_info_free(pinfo); + lnet_ping_md_unlink(pbuf, &ping_mdh); + lnet_ping_buffer_decref(pbuf); return rc; } @@ -2354,8 +2406,8 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) struct lnet_net *net; struct lnet_ni *ni; u32 net_id = LNET_NIDNET(conf->lic_nid); - struct lnet_ping_info *pinfo; - struct lnet_handle_md md_handle; + struct lnet_ping_buffer *pbuf; + struct lnet_handle_md ping_mdh; int rc; int net_count; u32 addr; @@ -2373,7 +2425,7 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) CERROR("net %s not found\n", libcfs_net2str(net_id)); rc = -ENOENT; - goto net_unlock; + goto unlock_net; } addr = LNET_NIDADDR(conf->lic_nid); @@ -2384,20 +2436,20 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) lnet_net_unlock(0); /* create and link a new ping info, before removing the old one */ - rc = lnet_ping_info_setup(&pinfo, &md_handle, - lnet_get_ni_count() - net_count, - false); + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, + lnet_get_ni_count() - net_count, + false); if (rc != 0) - goto out; + goto unlock_api_mutex; lnet_shutdown_lndnet(net); if (lnet_count_acceptor_nets() == 0) lnet_acceptor_stop(); - lnet_ping_target_update(pinfo, md_handle); + lnet_ping_target_update(pbuf, ping_mdh); - goto out; + goto unlock_api_mutex; } ni = lnet_nid2ni_locked(conf->lic_nid, 0); @@ -2405,7 +2457,7 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) CERROR("nid %s not found\n", libcfs_nid2str(conf->lic_nid)); rc = -ENOENT; - goto net_unlock; + goto unlock_net; } net_count = lnet_get_net_ni_count_locked(net); @@ -2413,27 +2465,27 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) lnet_net_unlock(0); /* create and link a new ping info, before removing the old one */ - rc = lnet_ping_info_setup(&pinfo, &md_handle, - lnet_get_ni_count() - 1, false); + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, + lnet_get_ni_count() - 1, false); if (rc != 0) - goto out; + goto unlock_api_mutex; lnet_shutdown_lndni(ni); if (lnet_count_acceptor_nets() == 0) lnet_acceptor_stop(); - lnet_ping_target_update(pinfo, md_handle); + lnet_ping_target_update(pbuf, ping_mdh); /* check if the net is empty and remove it if it is */ if (net_count == 1) lnet_shutdown_lndnet(net); - goto out; + goto unlock_api_mutex; -net_unlock: +unlock_net: lnet_net_unlock(0); -out: +unlock_api_mutex: mutex_unlock(&the_lnet.ln_api_mutex); return rc; @@ -2501,8 +2553,8 @@ int lnet_dyn_del_net(__u32 net_id) { struct lnet_net *net; - struct lnet_ping_info *pinfo; - struct lnet_handle_md md_handle; + struct lnet_ping_buffer *pbuf; + struct lnet_handle_md ping_mdh; int rc; int net_ni_count; @@ -2525,8 +2577,8 @@ lnet_dyn_del_net(__u32 net_id) lnet_net_unlock(0); /* create and link a new ping info, before removing the old one */ - rc = lnet_ping_info_setup(&pinfo, &md_handle, - lnet_get_ni_count() - net_ni_count, false); + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, + lnet_get_ni_count() - net_ni_count, false); if (rc) goto out; @@ -2535,7 +2587,7 @@ lnet_dyn_del_net(__u32 net_id) if (!lnet_count_acceptor_nets()) lnet_acceptor_stop(); - lnet_ping_target_update(pinfo, md_handle); + lnet_ping_target_update(pbuf, ping_mdh); out: mutex_unlock(&the_lnet.ln_api_mutex); @@ -2943,16 +2995,13 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, int unlinked = 0; int replied = 0; const signed long a_long_time = 60*HZ; - int infosz; - struct lnet_ping_info *info; + struct lnet_ping_buffer *pbuf; struct lnet_process_id tmpid; int i; int nob; int rc; int rc2; - infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]); - /* n_ids limit is arbitrary */ if (n_ids <= 0 || n_ids > lnet_interfaces_max || id.nid == LNET_NID_ANY) return -EINVAL; @@ -2960,20 +3009,20 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, if (id.pid == LNET_PID_ANY) id.pid = LNET_PID_LUSTRE; - info = kzalloc(infosz, GFP_KERNEL); - if (!info) + pbuf = lnet_ping_buffer_alloc(n_ids, GFP_NOFS); + if (!pbuf) return -ENOMEM; /* NB 2 events max (including any unlink event) */ rc = LNetEQAlloc(2, LNET_EQ_HANDLER_NONE, &eqh); if (rc) { CERROR("Can't allocate EQ: %d\n", rc); - goto out_0; + goto fail_ping_buffer_decref; } /* initialize md content */ - md.start = info; - md.length = infosz; + md.start = &pbuf->pb_info; + md.length = LNET_PING_INFO_SIZE(n_ids); md.threshold = 2; /*GET/REPLY*/ md.max_size = 0; md.options = LNET_MD_TRUNCATE; @@ -2983,7 +3032,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, rc = LNetMDBind(md, LNET_UNLINK, &mdh); if (rc) { CERROR("Can't bind MD: %d\n", rc); - goto out_1; + goto fail_free_eq; } rc = LNetGet(LNET_NID_ANY, mdh, id, @@ -3044,11 +3093,11 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, CWARN("%s: Unexpected rc >= 0 but no reply!\n", libcfs_id2str(id)); rc = -EIO; - goto out_1; + goto fail_free_eq; } nob = rc; - LASSERT(nob >= 0 && nob <= infosz); + LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids)); rc = -EPROTO; /* if I can't parse... */ @@ -3056,56 +3105,56 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, /* can't check magic/version */ CERROR("%s: ping info too short %d\n", libcfs_id2str(id), nob); - goto out_1; + goto fail_free_eq; } - if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { - lnet_swap_pinginfo(info); - } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) { + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { + lnet_swap_pinginfo(pbuf); + } else if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) { CERROR("%s: Unexpected magic %08x\n", - libcfs_id2str(id), info->pi_magic); - goto out_1; + libcfs_id2str(id), pbuf->pb_info.pi_magic); + goto fail_free_eq; } - if (!(info->pi_features & LNET_PING_FEAT_NI_STATUS)) { + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_NI_STATUS)) { CERROR("%s: ping w/o NI status: 0x%x\n", - libcfs_id2str(id), info->pi_features); - goto out_1; + libcfs_id2str(id), pbuf->pb_info.pi_features); + goto fail_free_eq; } - if (nob < offsetof(struct lnet_ping_info, pi_ni[0])) { + if (nob < LNET_PING_INFO_SIZE(0)) { CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), - nob, (int)offsetof(struct lnet_ping_info, pi_ni[0])); - goto out_1; + nob, (int)LNET_PING_INFO_SIZE(0)); + goto fail_free_eq; } - if (info->pi_nnis < n_ids) - n_ids = info->pi_nnis; + if (pbuf->pb_info.pi_nnis < n_ids) + n_ids = pbuf->pb_info.pi_nnis; - if (nob < offsetof(struct lnet_ping_info, pi_ni[n_ids])) { + if (nob < LNET_PING_INFO_SIZE(n_ids)) { CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), - nob, (int)offsetof(struct lnet_ping_info, pi_ni[n_ids])); - goto out_1; + nob, (int)LNET_PING_INFO_SIZE(n_ids)); + goto fail_free_eq; } rc = -EFAULT; /* If I SEGV... */ memset(&tmpid, 0, sizeof(tmpid)); for (i = 0; i < n_ids; i++) { - tmpid.pid = info->pi_pid; - tmpid.nid = info->pi_ni[i].ns_nid; + tmpid.pid = pbuf->pb_info.pi_pid; + tmpid.nid = pbuf->pb_info.pi_ni[i].ns_nid; if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid))) - goto out_1; + goto fail_free_eq; } - rc = info->pi_nnis; + rc = pbuf->pb_info.pi_nnis; - out_1: + fail_free_eq: rc2 = LNetEQFree(eqh); if (rc2) CERROR("rc2 %d\n", rc2); LASSERT(!rc2); - out_0: - kfree(info); + fail_ping_buffer_decref: + lnet_ping_buffer_decref(pbuf); return rc; } diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index b31a383fe974..e97957ce9252 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -618,17 +618,21 @@ lnet_get_route(int idx, __u32 *net, __u32 *hops, } void -lnet_swap_pinginfo(struct lnet_ping_info *info) +lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf) { - int i; struct lnet_ni_status *stat; + int nnis; + int i; - __swab32s(&info->pi_magic); - __swab32s(&info->pi_features); - __swab32s(&info->pi_pid); - __swab32s(&info->pi_nnis); - for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) { - stat = &info->pi_ni[i]; + __swab32s(&pbuf->pb_info.pi_magic); + __swab32s(&pbuf->pb_info.pi_features); + __swab32s(&pbuf->pb_info.pi_pid); + __swab32s(&pbuf->pb_info.pi_nnis); + nnis = pbuf->pb_info.pi_nnis; + if (nnis > pbuf->pb_nnis) + nnis = pbuf->pb_nnis; + for (i = 0; i < nnis; i++) { + stat = &pbuf->pb_info.pi_ni[i]; __swab64s(&stat->ns_nid); __swab32s(&stat->ns_status); } @@ -641,11 +645,12 @@ lnet_swap_pinginfo(struct lnet_ping_info *info) static void lnet_parse_rc_info(struct lnet_rc_data *rcd) { - struct lnet_ping_info *info = rcd->rcd_pinginfo; + struct lnet_ping_buffer *pbuf = rcd->rcd_pingbuffer; struct lnet_peer_ni *gw = rcd->rcd_gateway; struct lnet_route *rte; + int nnis; - if (!gw->lpni_alive) + if (!gw->lpni_alive || !pbuf) return; /* @@ -654,51 +659,48 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) */ spin_lock(&gw->lpni_lock); - if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) - lnet_swap_pinginfo(info); + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) + lnet_swap_pinginfo(pbuf); /* NB always racing with network! */ - if (info->pi_magic != LNET_PROTO_PING_MAGIC) { + if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) { CDEBUG(D_NET, "%s: Unexpected magic %08x\n", - libcfs_nid2str(gw->lpni_nid), info->pi_magic); + libcfs_nid2str(gw->lpni_nid), pbuf->pb_info.pi_magic); gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; - spin_unlock(&gw->lpni_lock); - return; + goto out; } - gw->lpni_ping_feats = info->pi_features; - if (!(gw->lpni_ping_feats & LNET_PING_FEAT_MASK)) { - CDEBUG(D_NET, "%s: Unexpected features 0x%x\n", - libcfs_nid2str(gw->lpni_nid), gw->lpni_ping_feats); - spin_unlock(&gw->lpni_lock); - return; /* nothing I can understand */ - } + gw->lpni_ping_feats = pbuf->pb_info.pi_features; - if (!(gw->lpni_ping_feats & LNET_PING_FEAT_NI_STATUS)) { - spin_unlock(&gw->lpni_lock); - return; /* can't carry NI status info */ - } + /* Without NI status info there's nothing more to do. */ + if (!(gw->lpni_ping_feats & LNET_PING_FEAT_NI_STATUS)) + goto out; + + /* Determine the number of NIs for which there is data. */ + nnis = pbuf->pb_info.pi_nnis; + if (pbuf->pb_nnis < nnis) + nnis = pbuf->pb_nnis; list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) { int down = 0; int up = 0; int i; + /* If routing disabled then the route is down. */ if (gw->lpni_ping_feats & LNET_PING_FEAT_RTE_DISABLED) { rte->lr_downis = 1; continue; } - for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) { - struct lnet_ni_status *stat = &info->pi_ni[i]; + for (i = 0; i < nnis; i++) { + struct lnet_ni_status *stat = &pbuf->pb_info.pi_ni[i]; lnet_nid_t nid = stat->ns_nid; if (nid == LNET_NID_ANY) { CDEBUG(D_NET, "%s: unexpected LNET_NID_ANY\n", libcfs_nid2str(gw->lpni_nid)); gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; - spin_unlock(&gw->lpni_lock); - return; + goto out; } if (LNET_NETTYP(LNET_NIDNET(nid)) == LOLND) @@ -720,8 +722,7 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) CDEBUG(D_NET, "%s: Unexpected status 0x%x\n", libcfs_nid2str(gw->lpni_nid), stat->ns_status); gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; - spin_unlock(&gw->lpni_lock); - return; + goto out; } if (up) { /* ignore downed NIs if NI for dest network is up */ @@ -737,7 +738,7 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) rte->lr_downis = down; } - +out: spin_unlock(&gw->lpni_lock); } @@ -903,7 +904,8 @@ lnet_destroy_rc_data(struct lnet_rc_data *rcd) lnet_net_unlock(cpt); } - kfree(rcd->rcd_pinginfo); + if (rcd->rcd_pingbuffer) + lnet_ping_buffer_decref(rcd->rcd_pingbuffer); kfree(rcd); } @@ -912,7 +914,7 @@ static struct lnet_rc_data * lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) { struct lnet_rc_data *rcd = NULL; - struct lnet_ping_info *pi; + struct lnet_ping_buffer *pbuf; struct lnet_md md; int rc; int i; @@ -926,19 +928,19 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) LNetInvalidateMDHandle(&rcd->rcd_mdh); INIT_LIST_HEAD(&rcd->rcd_list); - pi = kzalloc(LNET_PINGINFO_SIZE, GFP_NOFS); - if (!pi) + pbuf = lnet_ping_buffer_alloc(LNET_MAX_RTR_NIS, GFP_NOFS); + if (!pbuf) goto out; for (i = 0; i < LNET_MAX_RTR_NIS; i++) { - pi->pi_ni[i].ns_nid = LNET_NID_ANY; - pi->pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; + pbuf->pb_info.pi_ni[i].ns_nid = LNET_NID_ANY; + pbuf->pb_info.pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; } - rcd->rcd_pinginfo = pi; + rcd->rcd_pingbuffer = pbuf; - md.start = pi; + md.start = &pbuf->pb_info; md.user_ptr = rcd; - md.length = LNET_PINGINFO_SIZE; + md.length = LNET_RTR_PINGINFO_SIZE; md.threshold = LNET_MD_THRESH_INF; md.options = LNET_MD_TRUNCATE; md.eq_handle = the_lnet.ln_rc_eqh; @@ -1714,7 +1716,8 @@ lnet_rtrpools_enable(void) lnet_net_lock(LNET_LOCK_EX); the_lnet.ln_routing = 1; - the_lnet.ln_ping_info->pi_features &= ~LNET_PING_FEAT_RTE_DISABLED; + the_lnet.ln_ping_target->pb_info.pi_features &= + ~LNET_PING_FEAT_RTE_DISABLED; lnet_net_unlock(LNET_LOCK_EX); return rc; @@ -1728,7 +1731,8 @@ lnet_rtrpools_disable(void) lnet_net_lock(LNET_LOCK_EX); the_lnet.ln_routing = 0; - the_lnet.ln_ping_info->pi_features |= LNET_PING_FEAT_RTE_DISABLED; + the_lnet.ln_ping_target->pb_info.pi_features |= + LNET_PING_FEAT_RTE_DISABLED; tiny_router_buffers = 0; small_router_buffers = 0; From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 04/24] lustre: lnet: automatic sizing of router pinger buffers In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437770.16383.3391026679795909640.stgit@noble> From: Olaf Weber The router pinger uses fixed-size buffers to receive the data returned by a ping. When a router has more than 16 interfaces (including loopback) this means the data for some interfaces is dropped. Detect this situation, and track the number of remote NIs in the lnet_rc_data_t structure. lnet_create_rc_data_locked() becomes lnet_update_rc_data_locked(), and modified to replace an existing ping buffer if one is present. It is now also called by lnet_ping_router_locked() when the existing ping buffer is too small. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25774 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-types.h | 4 - drivers/staging/lustre/lnet/lnet/router.c | 90 +++++++++++++------- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index ab8c6d66cdbf..d1d17ededd06 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -411,8 +411,6 @@ struct lnet_ping_buffer { /* router checker data, per router */ -#define LNET_MAX_RTR_NIS LNET_INTERFACES_MIN -#define LNET_RTR_PINGINFO_SIZE LNET_PING_INFO_SIZE(LNET_MAX_RTR_NIS) struct lnet_rc_data { /* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */ struct list_head rcd_list; @@ -422,6 +420,8 @@ struct lnet_rc_data { struct lnet_peer_ni *rcd_gateway; /* ping buffer */ struct lnet_ping_buffer *rcd_pingbuffer; + /* desired size of buffer */ + int rcd_nnis; }; struct lnet_peer_ni { diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c index e97957ce9252..86cce27e10d8 100644 --- a/drivers/staging/lustre/lnet/lnet/router.c +++ b/drivers/staging/lustre/lnet/lnet/router.c @@ -678,8 +678,11 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) /* Determine the number of NIs for which there is data. */ nnis = pbuf->pb_info.pi_nnis; - if (pbuf->pb_nnis < nnis) + if (pbuf->pb_nnis < nnis) { + if (rcd->rcd_nnis < nnis) + rcd->rcd_nnis = nnis; nnis = pbuf->pb_nnis; + } list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) { int down = 0; @@ -911,28 +914,47 @@ lnet_destroy_rc_data(struct lnet_rc_data *rcd) } static struct lnet_rc_data * -lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) +lnet_update_rc_data_locked(struct lnet_peer_ni *gateway) { - struct lnet_rc_data *rcd = NULL; - struct lnet_ping_buffer *pbuf; + struct lnet_handle_md mdh; + struct lnet_rc_data *rcd; + struct lnet_ping_buffer *pbuf = NULL; struct lnet_md md; + int nnis = LNET_INTERFACES_MIN; int rc; int i; + rcd = gateway->lpni_rcd; + if (rcd) { + nnis = rcd->rcd_nnis; + mdh = rcd->rcd_mdh; + LNetInvalidateMDHandle(&rcd->rcd_mdh); + pbuf = rcd->rcd_pingbuffer; + rcd->rcd_pingbuffer = NULL; + } else { + LNetInvalidateMDHandle(&mdh); + } + lnet_net_unlock(gateway->lpni_cpt); - rcd = kzalloc(sizeof(*rcd), GFP_NOFS); - if (!rcd) - goto out; + if (rcd) { + LNetMDUnlink(mdh); + lnet_ping_buffer_decref(pbuf); + } else { + rcd = kzalloc(sizeof(*rcd), GFP_NOFS); + if (!rcd) + goto out; - LNetInvalidateMDHandle(&rcd->rcd_mdh); - INIT_LIST_HEAD(&rcd->rcd_list); + LNetInvalidateMDHandle(&rcd->rcd_mdh); + INIT_LIST_HEAD(&rcd->rcd_list); + rcd->rcd_nnis = nnis; + } - pbuf = lnet_ping_buffer_alloc(LNET_MAX_RTR_NIS, GFP_NOFS); + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); if (!pbuf) goto out; - for (i = 0; i < LNET_MAX_RTR_NIS; i++) { + for (i = 0; i < nnis; i++) { pbuf->pb_info.pi_ni[i].ns_nid = LNET_NID_ANY; pbuf->pb_info.pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; } @@ -940,7 +962,7 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) md.start = &pbuf->pb_info; md.user_ptr = rcd; - md.length = LNET_RTR_PINGINFO_SIZE; + md.length = LNET_PING_INFO_SIZE(nnis); md.threshold = LNET_MD_THRESH_INF; md.options = LNET_MD_TRUNCATE; md.eq_handle = the_lnet.ln_rc_eqh; @@ -949,33 +971,37 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) rc = LNetMDBind(md, LNET_UNLINK, &rcd->rcd_mdh); if (rc < 0) { CERROR("Can't bind MD: %d\n", rc); - goto out; + goto out_ping_buffer_decref; } LASSERT(!rc); lnet_net_lock(gateway->lpni_cpt); - /* router table changed or someone has created rcd for this gateway */ - if (!lnet_isrouter(gateway) || gateway->lpni_rcd) { - lnet_net_unlock(gateway->lpni_cpt); - goto out; + /* Check if this is still a router. */ + if (!lnet_isrouter(gateway)) + goto out_unlock; + /* Check if someone else installed router data. */ + if (gateway->lpni_rcd && gateway->lpni_rcd != rcd) + goto out_unlock; + + /* Install and/or update the router data. */ + if (!gateway->lpni_rcd) { + lnet_peer_ni_addref_locked(gateway); + rcd->rcd_gateway = gateway; + gateway->lpni_rcd = rcd; } - - lnet_peer_ni_addref_locked(gateway); - rcd->rcd_gateway = gateway; - gateway->lpni_rcd = rcd; gateway->lpni_ping_notsent = 0; return rcd; - out: - if (rcd) { - if (!LNetMDHandleIsInvalid(rcd->rcd_mdh)) { - rc = LNetMDUnlink(rcd->rcd_mdh); - LASSERT(!rc); - } +out_unlock: + lnet_net_unlock(gateway->lpni_cpt); + rc = LNetMDUnlink(mdh); + LASSERT(!rc); +out_ping_buffer_decref: + lnet_ping_buffer_decref(pbuf); +out: + if (rcd && rcd != gateway->lpni_rcd) lnet_destroy_rc_data(rcd); - } - lnet_net_lock(gateway->lpni_cpt); return gateway->lpni_rcd; } @@ -1018,9 +1044,9 @@ lnet_ping_router_locked(struct lnet_peer_ni *rtr) return; } - rcd = rtr->lpni_rcd ? - rtr->lpni_rcd : lnet_create_rc_data_locked(rtr); - + rcd = rtr->lpni_rcd; + if (!rcd || rcd->rcd_nnis > rcd->rcd_pingbuffer->pb_nnis) + rcd = lnet_update_rc_data_locked(rtr); if (!rcd) return; From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 05/24] lustre: lnet: add Multi-Rail and Discovery ping feature bits In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437774.16383.2810116639916310757.stgit@noble> From: Olaf Weber Claim ping features bit for Multi-Rail and Discovery. Assert in lnet_ping_target_update() that no unknown bits will be send over the wire. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25775 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-types.h | 16 ++++++++++++++++ drivers/staging/lustre/lnet/lnet/api-ni.c | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index d1d17ededd06..f4467a3bbfd1 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -386,6 +386,22 @@ struct lnet_ni { #define LNET_PING_FEAT_BASE BIT(0) /* just a ping */ #define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ #define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ +#define LNET_PING_FEAT_MULTI_RAIL BIT(3) /* Multi-Rail aware */ +#define LNET_PING_FEAT_DISCOVERY BIT(4) /* Supports Discovery */ + +/* + * All ping feature bits fit to hit the wire. + * In lnet_assert_wire_constants() this is compared against its open-coded + * value, and in lnet_ping_target_update() it is used to verify that no + * unknown bits have been set. + * New feature bits can be added, just be aware that this does change the + * over-the-wire protocol. + */ +#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ + LNET_PING_FEAT_NI_STATUS | \ + LNET_PING_FEAT_RTE_DISABLED | \ + LNET_PING_FEAT_MULTI_RAIL | \ + LNET_PING_FEAT_DISCOVERY) #define LNET_PING_INFO_SIZE(NNIDS) \ offsetof(struct lnet_ping_info, pi_ni[NNIDS]) diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index ca28ad75fe2b..68af723bc6a1 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -1170,6 +1170,11 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, if (!the_lnet.ln_routing) pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; + + /* Ensure only known feature bits have been set. */ + LASSERT(pbuf->pb_info.pi_features & LNET_PING_FEAT_BITS); + LASSERT(!(pbuf->pb_info.pi_features & ~LNET_PING_FEAT_BITS)); + lnet_ping_target_install_locked(pbuf); if (the_lnet.ln_ping_target) { From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 06/24] lustre: lnet: add sanity checks on ping-related constants In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437778.16383.4176394927995685300.stgit@noble> From: Olaf Weber Add sanity checks for LNet ping related data structures and constants to wirecheck.c, and update the generated code in lnet_assert_wire_constants(). In order for the structures and macros to be visible to wirecheck.c, which is a userspace program, they were moved from kernel-only lnet/lib-types.h to lnet/types.h WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25776 Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-types.h | 30 ---------------- .../lustre/include/uapi/linux/lnet/lnet-types.h | 30 ++++++++++++++++ drivers/staging/lustre/lnet/lnet/api-ni.c | 38 ++++++++++++++++++++ 3 files changed, 68 insertions(+), 30 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index f4467a3bbfd1..f28fa5342914 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -378,36 +378,6 @@ struct lnet_ni { #define LNET_PROTO_PING_MATCHBITS 0x8000000000000000LL -/* - * NB: value of these features equal to LNET_PROTO_PING_VERSION_x - * of old LNet, so there shouldn't be any compatibility issue - */ -#define LNET_PING_FEAT_INVAL (0) /* no feature */ -#define LNET_PING_FEAT_BASE BIT(0) /* just a ping */ -#define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ -#define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ -#define LNET_PING_FEAT_MULTI_RAIL BIT(3) /* Multi-Rail aware */ -#define LNET_PING_FEAT_DISCOVERY BIT(4) /* Supports Discovery */ - -/* - * All ping feature bits fit to hit the wire. - * In lnet_assert_wire_constants() this is compared against its open-coded - * value, and in lnet_ping_target_update() it is used to verify that no - * unknown bits have been set. - * New feature bits can be added, just be aware that this does change the - * over-the-wire protocol. - */ -#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ - LNET_PING_FEAT_NI_STATUS | \ - LNET_PING_FEAT_RTE_DISABLED | \ - LNET_PING_FEAT_MULTI_RAIL | \ - LNET_PING_FEAT_DISCOVERY) - -#define LNET_PING_INFO_SIZE(NNIDS) \ - offsetof(struct lnet_ping_info, pi_ni[NNIDS]) -#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) -#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) - /* * Descriptor of a ping info buffer: keep a separate indicator of the * size and a reference count. The type is used both as a source and diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h index 6ee60d07ff84..e0e4fd259795 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h @@ -190,6 +190,31 @@ struct lnet_hdr { } msg; } __packed; +/* + * NB: value of these features equal to LNET_PROTO_PING_VERSION_x + * of old LNet, so there shouldn't be any compatibility issue + */ +#define LNET_PING_FEAT_INVAL (0) /* no feature */ +#define LNET_PING_FEAT_BASE (1 << 0) /* just a ping */ +#define LNET_PING_FEAT_NI_STATUS (1 << 1) /* return NI status */ +#define LNET_PING_FEAT_RTE_DISABLED (1 << 2) /* Routing enabled */ +#define LNET_PING_FEAT_MULTI_RAIL (1 << 3) /* Multi-Rail aware */ +#define LNET_PING_FEAT_DISCOVERY (1 << 4) /* Supports Discovery */ + +/* + * All ping feature bits fit to hit the wire. + * In lnet_assert_wire_constants() this is compared against its open-coded + * value, and in lnet_ping_target_update() it is used to verify that no + * unknown bits have been set. + * New feature bits can be added, just be aware that this does change the + * over-the-wire protocol. + */ +#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ + LNET_PING_FEAT_NI_STATUS | \ + LNET_PING_FEAT_RTE_DISABLED | \ + LNET_PING_FEAT_MULTI_RAIL | \ + LNET_PING_FEAT_DISCOVERY) + /* * A HELLO message contains a magic number and protocol version * code in the header's dest_nid, the peer's NID in the src_nid, and @@ -246,6 +271,11 @@ struct lnet_ping_info { struct lnet_ni_status pi_ni[0]; } __packed; +#define LNET_PING_INFO_SIZE(NNIDS) \ + offsetof(struct lnet_ping_info, pi_ni[NNIDS]) +#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) +#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) + struct lnet_counters { __u32 msgs_alloc; __u32 msgs_max; diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 68af723bc6a1..d81501f4c282 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -313,6 +313,44 @@ static void lnet_assert_wire_constants(void) BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.incarnation) != 8); BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.type) != 40); BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.type) != 4); + + /* Checks for struct lnet_ni_status and related constants */ + BUILD_BUG_ON(LNET_NI_STATUS_INVALID != 0x00000000); + BUILD_BUG_ON(LNET_NI_STATUS_UP != 0x15aac0de); + BUILD_BUG_ON(LNET_NI_STATUS_DOWN != 0xdeadface); + + /* Checks for struct lnet_ni_status */ + BUILD_BUG_ON((int)sizeof(struct lnet_ni_status) != 16); + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_nid) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_nid) != 8); + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_status) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_status) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_unused) != 12); + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_unused) != 4); + + /* Checks for struct lnet_ping_info and related constants */ + BUILD_BUG_ON(LNET_PROTO_PING_MAGIC != 0x70696E67); + BUILD_BUG_ON(LNET_PING_FEAT_INVAL != 0); + BUILD_BUG_ON(LNET_PING_FEAT_BASE != 1); + BUILD_BUG_ON(LNET_PING_FEAT_NI_STATUS != 2); + BUILD_BUG_ON(LNET_PING_FEAT_RTE_DISABLED != 4); + BUILD_BUG_ON(LNET_PING_FEAT_MULTI_RAIL != 8); + BUILD_BUG_ON(LNET_PING_FEAT_DISCOVERY != 16); + BUILD_BUG_ON(LNET_PING_FEAT_BITS != 31); + + /* Checks for struct lnet_ping_info */ + BUILD_BUG_ON((int)sizeof(struct lnet_ping_info) != 16); + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_magic) != 0); + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_magic) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_features) != 4); + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_features) + != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_pid) != 8); + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_pid) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_nnis) != 12); + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_nnis) != 4); + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_ni) != 16); + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_ni) != 0); } static struct lnet_lnd * From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 07/24] lustre: lnet: cleanup of lnet_peer_ni_addref/decref_locked() In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437782.16383.10279057472731467540.stgit@noble> From: Olaf Weber Address style issues in lnet_peer_ni_addref_locked() and lnet_peer_ni_decref_locked(). In the latter routine, replace a sequence of atomic_dec()/atomic_read() with atomic_dec_and_test(). WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25777 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 2e2b5ed27116..f15f5c9c9a25 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -323,8 +323,7 @@ static inline void lnet_peer_ni_decref_locked(struct lnet_peer_ni *lp) { LASSERT(atomic_read(&lp->lpni_refcount) > 0); - atomic_dec(&lp->lpni_refcount); - if (atomic_read(&lp->lpni_refcount) == 0) + if (atomic_dec_and_test(&lp->lpni_refcount)) lnet_destroy_peer_ni_locked(lp); } From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 08/24] lustre: lnet: rename lnet_add/del_peer_ni_to/from_peer() In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437785.16383.10650578259435328953.stgit@noble> From: Olaf Weber Rename lnet_add_peer_ni_to_peer() to lnet_add_peer_ni(), and lnet_del_peer_ni_from_peer() to lnet_del_peer_ni(). This brings the function names closer to the ioctls they implement: IOCTL_LIBCFS_ADD_PEER_NI and IOCTL_LIBCFS_DEL_PEER_NI. These names are also a more accturate description their effect: adding or deleting an lnet_peer_ni to LNet. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25778 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 4 ++-- drivers/staging/lustre/lnet/lnet/api-ni.c | 10 +++++---- drivers/staging/lustre/lnet/lnet/peer.c | 22 +++++++++++++++----- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index f15f5c9c9a25..69f45a76f1cc 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -682,8 +682,8 @@ struct lnet_peer_net *lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id); bool lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, struct lnet_ni *ni); -int lnet_add_peer_ni_to_peer(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); -int lnet_del_peer_ni_from_peer(lnet_nid_t key_nid, lnet_nid_t nid); +int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); +int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, bool *mr, struct lnet_peer_ni_credit_info __user *peer_ni_info, diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index d81501f4c282..d64ae2939abc 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -2848,9 +2848,9 @@ LNetCtl(unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_add_peer_ni_to_peer(cfg->prcfg_prim_nid, - cfg->prcfg_cfg_nid, - cfg->prcfg_mr); + rc = lnet_add_peer_ni(cfg->prcfg_prim_nid, + cfg->prcfg_cfg_nid, + cfg->prcfg_mr); mutex_unlock(&the_lnet.ln_api_mutex); return rc; } @@ -2862,8 +2862,8 @@ LNetCtl(unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_del_peer_ni_from_peer(cfg->prcfg_prim_nid, - cfg->prcfg_cfg_nid); + rc = lnet_del_peer_ni(cfg->prcfg_prim_nid, + cfg->prcfg_cfg_nid); mutex_unlock(&the_lnet.ln_api_mutex); return rc; } diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index ebb84356302f..bbf07008dbb0 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -891,14 +891,16 @@ lnet_peer_ni_add_non_mr(lnet_nid_t nid) } /* + * Implementation of IOC_LIBCFS_ADD_PEER_NI. + * * This API handles the following combinations: - * Create a primary NI if only the prim_nid is provided - * Create or add an lpni to a primary NI. Primary NI must've already - * been created - * Create a non-MR peer. + * Create a primary NI if only the prim_nid is provided + * Create or add an lpni to a primary NI. Primary NI must've already + * been created + * Create a non-MR peer. */ int -lnet_add_peer_ni_to_peer(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) +lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) { /* * Caller trying to setup an MR like peer hierarchy but @@ -929,8 +931,16 @@ lnet_add_peer_ni_to_peer(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) return 0; } +/* + * Implementation of IOC_LIBCFS_DEL_PEER_NI. + * + * This API handles the following combinations: + * Delete a NI from a peer if both prim_nid and nid are provided. + * Delete a peer if only prim_nid is provided. + * Delete a peer if its primary nid is provided. + */ int -lnet_del_peer_ni_from_peer(lnet_nid_t prim_nid, lnet_nid_t nid) +lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) { lnet_nid_t local_nid; struct lnet_peer *peer; From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 09/24] lustre: lnet: refactor lnet_del_peer_ni() In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437789.16383.3567353433359493775.stgit@noble> From: Olaf Weber Refactor lnet_del_peer_ni(). In particular break out the code that removes an lnet_peer_ni from an lnet_peer and put it into a separate function, lnet_peer_del_nid(). WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25779 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- drivers/staging/lustre/lnet/lnet/peer.c | 96 +++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 25 deletions(-) diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index bbf07008dbb0..30a2486712e4 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -254,7 +254,7 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) * * The last reference may be lost in a place where the * lnet_net_lock locks only a single cpt, and that cpt may not - * be lpni->lpni_cpt. So the zombie list of this peer_table + * be lpni->lpni_cpt. So the zombie list of lnet_peer_table * has its own lock. */ spin_lock(&ptable->pt_zombie_lock); @@ -340,6 +340,61 @@ lnet_peer_del_locked(struct lnet_peer *peer) return rc2; } +static int +lnet_peer_del(struct lnet_peer *peer) +{ + lnet_net_lock(LNET_LOCK_EX); + lnet_peer_del_locked(peer); + lnet_net_unlock(LNET_LOCK_EX); + + return 0; +} + +/* + * Delete a NID from a peer. + * Implements a few sanity checks. + * Call with ln_api_mutex held. + */ +static int +lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) +{ + struct lnet_peer *lp2; + struct lnet_peer_ni *lpni; + + lpni = lnet_find_peer_ni_locked(nid); + if (!lpni) { + CERROR("Cannot remove unknown nid %s from peer %s\n", + libcfs_nid2str(nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -ENOENT; + } + lnet_peer_ni_decref_locked(lpni); + lp2 = lpni->lpni_peer_net->lpn_peer; + if (lp2 != lp) { + CERROR("Nid %s is attached to peer %s, not peer %s\n", + libcfs_nid2str(nid), + libcfs_nid2str(lp2->lp_primary_nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -EINVAL; + } + + /* + * This function only allows deletion of the primary NID if it + * is the only NID. + */ + if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { + CERROR("Cannot delete primary NID %s from multi-NID peer\n", + libcfs_nid2str(nid)); + return -EINVAL; + } + + lnet_net_lock(LNET_LOCK_EX); + lnet_peer_ni_del_locked(lpni); + lnet_net_unlock(LNET_LOCK_EX); + + return 0; +} + static void lnet_peer_table_cleanup_locked(struct lnet_net *net, struct lnet_peer_table *ptable) @@ -938,45 +993,36 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) * Delete a NI from a peer if both prim_nid and nid are provided. * Delete a peer if only prim_nid is provided. * Delete a peer if its primary nid is provided. + * + * The caller must hold ln_api_mutex. This prevents the peer from + * being modified/deleted by a different thread. */ int lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) { - lnet_nid_t local_nid; - struct lnet_peer *peer; + struct lnet_peer *lp; struct lnet_peer_ni *lpni; - int rc; if (prim_nid == LNET_NID_ANY) return -EINVAL; - local_nid = (nid != LNET_NID_ANY) ? nid : prim_nid; - - lpni = lnet_find_peer_ni_locked(local_nid); + lpni = lnet_find_peer_ni_locked(prim_nid); if (!lpni) - return -EINVAL; + return -ENOENT; lnet_peer_ni_decref_locked(lpni); + lp = lpni->lpni_peer_net->lpn_peer; - peer = lpni->lpni_peer_net->lpn_peer; - LASSERT(peer); - - if (peer->lp_primary_nid == lpni->lpni_nid) { - /* - * deleting the primary ni is equivalent to deleting the - * entire peer - */ - lnet_net_lock(LNET_LOCK_EX); - rc = lnet_peer_del_locked(peer); - lnet_net_unlock(LNET_LOCK_EX); - - return rc; + if (prim_nid != lp->lp_primary_nid) { + CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", + libcfs_nid2str(prim_nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -ENODEV; } - lnet_net_lock(LNET_LOCK_EX); - rc = lnet_peer_ni_del_locked(lpni); - lnet_net_unlock(LNET_LOCK_EX); + if (nid == LNET_NID_ANY || nid == lp->lp_primary_nid) + return lnet_peer_del(lp); - return rc; + return lnet_peer_del_nid(lp, nid); } void From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 10/24] lustre: lnet: refactor lnet_add_peer_ni() In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437792.16383.4508869255214195437.stgit@noble> From: Olaf Weber Refactor lnet_add_peer_ni() and the functions called by it. In particular, lnet_peer_add_nid() adds an lnet_peer_ni to an existing lnet_peer, lnet_peer_add() adds a new lnet_peer. lnet_find_or_create_peer_locked() is removed. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25780 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 1 drivers/staging/lustre/lnet/lnet/lib-move.c | 13 + drivers/staging/lustre/lnet/lnet/peer.c | 230 +++++++------------- 3 files changed, 92 insertions(+), 152 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 69f45a76f1cc..fc748ffa251d 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -668,7 +668,6 @@ u32 lnet_get_dlc_seq_locked(void); struct lnet_peer_ni *lnet_get_next_peer_ni_locked(struct lnet_peer *peer, struct lnet_peer_net *peer_net, struct lnet_peer_ni *prev); -struct lnet_peer *lnet_find_or_create_peer_locked(lnet_nid_t dst_nid, int cpt); struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index e8c021622f91..59ae8d0649e5 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -1262,11 +1262,18 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, return -ESHUTDOWN; } - peer = lnet_find_or_create_peer_locked(dst_nid, cpt); - if (IS_ERR(peer)) { + /* + * lnet_nid2peerni_locked() is the path that will find an + * existing peer_ni, or create one and mark it as having been + * created due to network traffic. + */ + lpni = lnet_nid2peerni_locked(dst_nid, cpt); + if (IS_ERR(lpni)) { lnet_net_unlock(cpt); - return PTR_ERR(peer); + return PTR_ERR(lpni); } + peer = lpni->lpni_peer_net->lpn_peer; + lnet_peer_ni_decref_locked(lpni); /* If peer is not healthy then can not send anything to it */ if (!lnet_is_peer_healthy_locked(peer)) { diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 30a2486712e4..6b7ca5c361b8 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -541,25 +541,6 @@ lnet_find_peer_ni_locked(lnet_nid_t nid) return lpni; } -struct lnet_peer * -lnet_find_or_create_peer_locked(lnet_nid_t dst_nid, int cpt) -{ - struct lnet_peer_ni *lpni; - struct lnet_peer *lp; - - lpni = lnet_find_peer_ni_locked(dst_nid); - if (!lpni) { - lpni = lnet_nid2peerni_locked(dst_nid, cpt); - if (IS_ERR(lpni)) - return ERR_CAST(lpni); - } - - lp = lpni->lpni_peer_net->lpn_peer; - lnet_peer_ni_decref_locked(lpni); - - return lp; -} - struct lnet_peer_ni * lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, struct lnet_peer **lp) @@ -774,131 +755,95 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni return -ENOMEM; } +/* + * Create a new peer, with nid as its primary nid. + * + * It is not an error if the peer already exists, provided that the + * given nid is the primary NID. + * + * Call with the lnet_api_mutex held. + */ static int -lnet_add_prim_lpni(lnet_nid_t nid) +lnet_peer_add(lnet_nid_t nid, bool mr) { - int rc; - struct lnet_peer *peer; + struct lnet_peer *lp; struct lnet_peer_ni *lpni; LASSERT(nid != LNET_NID_ANY); /* - * lookup the NID and its peer - * if the peer doesn't exist, create it. - * if this is a non-MR peer then change its state to MR and exit. - * if this is an MR peer and it's a primary NI: NO-OP. - * if this is an MR peer and it's not a primary NI. Operation not - * allowed. - * - * The adding and deleting of peer nis is being serialized through - * the api_mutex. So we can look up peers with the mutex locked - * safely. Only when we need to change the ptable, do we need to - * exclusively lock the lnet_net_lock() + * No need for the lnet_net_lock here, because the + * lnet_api_mutex is held. */ lpni = lnet_find_peer_ni_locked(nid); if (!lpni) { - rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); + int rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); if (rc != 0) return rc; lpni = lnet_find_peer_ni_locked(nid); + LASSERT(lpni); } - - LASSERT(lpni); - + lp = lpni->lpni_peer_net->lpn_peer; lnet_peer_ni_decref_locked(lpni); - peer = lpni->lpni_peer_net->lpn_peer; - - /* - * If we found a lpni with the same nid as the NID we're trying to - * create, then we're trying to create an already existing lpni - * that belongs to a different peer - */ - if (peer->lp_primary_nid != nid) + /* A found peer must have this primary NID */ + if (lp->lp_primary_nid != nid) return -EEXIST; /* - * if we found an lpni that is not a multi-rail, which could occur + * If we found an lpni that is not a multi-rail, which could occur * if lpni is already created as a non-mr lpni or we just created * it, then make sure you indicate that this lpni is a primary mr * capable peer. * * TODO: update flags if necessary */ - if (!peer->lp_multi_rail && peer->lp_primary_nid == nid) - peer->lp_multi_rail = true; + if (mr && !lp->lp_multi_rail) { + lp->lp_multi_rail = true; + } else if (!mr && lp->lp_multi_rail) { + /* The mr state is sticky. */ + CDEBUG(D_NET, "Cannot clear multi-flag from peer %s\n", + libcfs_nid2str(nid)); + } - return rc; + return 0; } static int -lnet_add_peer_ni_to_prim_lpni(lnet_nid_t prim_nid, lnet_nid_t nid) +lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) { - struct lnet_peer *peer, *primary_peer; - struct lnet_peer_ni *lpni = NULL, *klpni = NULL; - - LASSERT(prim_nid != LNET_NID_ANY && nid != LNET_NID_ANY); + struct lnet_peer_ni *lpni; - /* - * key nid must be created by this point. If not then this - * operation is not permitted - */ - klpni = lnet_find_peer_ni_locked(prim_nid); - if (!klpni) - return -ENOENT; + LASSERT(lp); + LASSERT(nid != LNET_NID_ANY); - lnet_peer_ni_decref_locked(klpni); + if (!mr && !lp->lp_multi_rail) { + CERROR("Cannot add nid %s to non-multi-rail peer %s\n", + libcfs_nid2str(nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -EPERM; + } - primary_peer = klpni->lpni_peer_net->lpn_peer; + if (!lp->lp_multi_rail) + lp->lp_multi_rail = true; lpni = lnet_find_peer_ni_locked(nid); - if (lpni) { - lnet_peer_ni_decref_locked(lpni); - - peer = lpni->lpni_peer_net->lpn_peer; - /* - * lpni already exists in the system but it belongs to - * a different peer. We can't re-added it - */ - if (peer->lp_primary_nid != prim_nid && peer->lp_multi_rail) { - CERROR("Cannot add NID %s owned by peer %s to peer %s\n", - libcfs_nid2str(lpni->lpni_nid), - libcfs_nid2str(peer->lp_primary_nid), - libcfs_nid2str(prim_nid)); - return -EEXIST; - } else if (peer->lp_primary_nid == prim_nid) { - /* - * found a peer_ni that is already part of the - * peer. This is a no-op operation. - */ - return 0; - } - - /* - * TODO: else if (peer->lp_primary_nid != prim_nid && - * !peer->lp_multi_rail) - * peer is not an MR peer and it will be moved in the next - * step to klpni, so update its flags accordingly. - * lnet_move_peer_ni() - */ - - /* - * TODO: call lnet_update_peer() from here to update the - * flags. This is the case when the lpni you're trying to - * add is already part of the peer. This could've been - * added by the DD previously, so go ahead and do any - * updates to the state if necessary - */ + if (!lpni) + return lnet_peer_setup_hierarchy(lp, NULL, nid); + if (lpni->lpni_peer_net->lpn_peer != lp) { + struct lnet_peer *lp2 = lpni->lpni_peer_net->lpn_peer; + CERROR("Cannot add NID %s owned by peer %s to peer %s\n", + libcfs_nid2str(lpni->lpni_nid), + libcfs_nid2str(lp2->lp_primary_nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -EEXIST; } - /* - * When we get here we either have found an existing lpni, which - * we can switch to the new peer. Or we need to create one and - * add it to the new peer - */ - return lnet_peer_setup_hierarchy(primary_peer, lpni, nid); + CDEBUG(D_NET, "NID %s is already owned by peer %s\n", + libcfs_nid2str(lpni->lpni_nid), + libcfs_nid2str(lp->lp_primary_nid)); + return 0; } /* @@ -929,61 +874,50 @@ lnet_peer_ni_traffic_add(lnet_nid_t nid) return rc; } -static int -lnet_peer_ni_add_non_mr(lnet_nid_t nid) -{ - struct lnet_peer_ni *lpni; - - lpni = lnet_find_peer_ni_locked(nid); - if (lpni) { - CERROR("Cannot add %s as non-mr when it already exists\n", - libcfs_nid2str(nid)); - lnet_peer_ni_decref_locked(lpni); - return -EEXIST; - } - - return lnet_peer_setup_hierarchy(NULL, NULL, nid); -} - /* * Implementation of IOC_LIBCFS_ADD_PEER_NI. * * This API handles the following combinations: - * Create a primary NI if only the prim_nid is provided - * Create or add an lpni to a primary NI. Primary NI must've already - * been created - * Create a non-MR peer. + * Create a peer with its primary NI if only the prim_nid is provided + * Add a NID to a peer identified by the prim_nid. The peer identified + * by the prim_nid must already exist. + * The peer being created may be non-MR. + * + * The caller must hold ln_api_mutex. This prevents the peer from + * being created/modified/deleted by a different thread. */ int lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) { + struct lnet_peer *lp = NULL; + struct lnet_peer_ni *lpni; + + /* The prim_nid must always be specified */ + if (prim_nid == LNET_NID_ANY) + return -EINVAL; + /* - * Caller trying to setup an MR like peer hierarchy but - * specifying it to be non-MR. This is not allowed. + * If nid isn't specified, we must create a new peer with + * prim_nid as its primary nid. */ - if (prim_nid != LNET_NID_ANY && - nid != LNET_NID_ANY && !mr) - return -EPERM; - - /* Add the primary NID of a peer */ - if (prim_nid != LNET_NID_ANY && - nid == LNET_NID_ANY && mr) - return lnet_add_prim_lpni(prim_nid); + if (nid == LNET_NID_ANY) + return lnet_peer_add(prim_nid, mr); - /* Add a NID to an existing peer */ - if (prim_nid != LNET_NID_ANY && - nid != LNET_NID_ANY && mr) - return lnet_add_peer_ni_to_prim_lpni(prim_nid, nid); + /* Look up the prim_nid, which must exist. */ + lpni = lnet_find_peer_ni_locked(prim_nid); + if (!lpni) + return -ENOENT; + lnet_peer_ni_decref_locked(lpni); + lp = lpni->lpni_peer_net->lpn_peer; - /* Add a non-MR peer NI */ - if (((prim_nid != LNET_NID_ANY && - nid == LNET_NID_ANY) || - (prim_nid == LNET_NID_ANY && - nid != LNET_NID_ANY)) && !mr) - return lnet_peer_ni_add_non_mr(prim_nid != LNET_NID_ANY ? - prim_nid : nid); + if (lp->lp_primary_nid != prim_nid) { + CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", + libcfs_nid2str(prim_nid), + libcfs_nid2str(lp->lp_primary_nid)); + return -ENODEV; + } - return 0; + return lnet_peer_add_nid(lp, nid, mr); } /* From neilb at suse.com Sun Oct 7 23:19:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:37 +1100 Subject: [lustre-devel] [PATCH 11/24] lustre: lnet: introduce LNET_PEER_MULTI_RAIL flag bit In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437796.16383.5518559009775786439.stgit@noble> From: Olaf Weber Add lp_state as a flag word to lnet_peer, and add lp_lock to protect it. This lock needs to be taken whenever the field is updated, because setting or clearing a bit is a read-modify-write cycle. The lp_multi_rail is removed, its function is replaced by the new LNET_PEER_MULTI_RAIL flag bit. The helper lnet_peer_is_multi_rail() tests the bit. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25781 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 6 +++++ .../staging/lustre/include/linux/lnet/lib-types.h | 11 ++++++++-- drivers/staging/lustre/lnet/lnet/lib-move.c | 9 +++++--- drivers/staging/lustre/lnet/lnet/peer.c | 22 +++++++++++++------- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index fc748ffa251d..75b47628c70e 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -757,4 +757,10 @@ lnet_peer_set_alive(struct lnet_peer_ni *lp) lnet_notify_locked(lp, 0, 1, lp->lpni_last_alive); } +static inline bool +lnet_peer_is_multi_rail(struct lnet_peer *lp) +{ + return lp->lp_state & LNET_PEER_MULTI_RAIL; +} + #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index f28fa5342914..602978a1c86e 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -467,6 +467,8 @@ struct lnet_peer_ni { atomic_t lpni_refcount; /* CPT this peer attached on */ int lpni_cpt; + /* state flags -- protected by lpni_lock */ + unsigned int lpni_state; /* # refs from lnet_route::lr_gateway */ int lpni_rtr_refcount; /* sequence number used to round robin over peer nis within a net */ @@ -497,10 +499,15 @@ struct lnet_peer { /* primary NID of the peer */ lnet_nid_t lp_primary_nid; - /* peer is Multi-Rail enabled peer */ - bool lp_multi_rail; + /* lock protecting peer state flags */ + spinlock_t lp_lock; + + /* peer state flags */ + unsigned int lp_state; }; +#define LNET_PEER_MULTI_RAIL BIT(0) + struct lnet_peer_net { /* chain on peer block */ struct list_head lpn_on_peer_list; diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 59ae8d0649e5..0d0ad30bb164 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -1281,7 +1281,8 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, return -EHOSTUNREACH; } - if (!peer->lp_multi_rail && lnet_get_num_peer_nis(peer) > 1) { + if (!lnet_peer_is_multi_rail(peer) && + lnet_get_num_peer_nis(peer) > 1) { lnet_net_unlock(cpt); CERROR("peer %s is declared to be non MR capable, yet configured with more than one NID\n", libcfs_nid2str(dst_nid)); @@ -1307,7 +1308,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, if (msg->msg_type == LNET_MSG_REPLY || msg->msg_type == LNET_MSG_ACK || - !peer->lp_multi_rail || + !lnet_peer_is_multi_rail(peer) || best_ni) { /* * for replies we want to respond on the same peer_ni we @@ -1354,7 +1355,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, * then use the best_gw found to send * the message to */ - if (!peer->lp_multi_rail) + if (!lnet_peer_is_multi_rail(peer)) best_lpni = best_gw; else best_lpni = NULL; @@ -1375,7 +1376,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, * if the peer is not MR capable, then we should always send to it * using the first NI in the NET we determined. */ - if (!peer->lp_multi_rail) { + if (!lnet_peer_is_multi_rail(peer)) { if (!best_lpni) { lnet_net_unlock(cpt); CERROR("no route to %s\n", diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 6b7ca5c361b8..cc2b926b76e4 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -182,6 +182,7 @@ lnet_peer_alloc(lnet_nid_t nid) INIT_LIST_HEAD(&lp->lp_on_lnet_peer_list); INIT_LIST_HEAD(&lp->lp_peer_nets); + spin_lock_init(&lp->lp_lock); lp->lp_primary_nid = nid; /* TODO: update flags */ @@ -798,13 +799,15 @@ lnet_peer_add(lnet_nid_t nid, bool mr) * * TODO: update flags if necessary */ - if (mr && !lp->lp_multi_rail) { - lp->lp_multi_rail = true; - } else if (!mr && lp->lp_multi_rail) { + spin_lock(&lp->lp_lock); + if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + lp->lp_state |= LNET_PEER_MULTI_RAIL; + } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { /* The mr state is sticky. */ - CDEBUG(D_NET, "Cannot clear multi-flag from peer %s\n", + CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", libcfs_nid2str(nid)); } + spin_unlock(&lp->lp_lock); return 0; } @@ -817,15 +820,18 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) LASSERT(lp); LASSERT(nid != LNET_NID_ANY); - if (!mr && !lp->lp_multi_rail) { + spin_lock(&lp->lp_lock); + if (!mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + spin_unlock(&lp->lp_lock); CERROR("Cannot add nid %s to non-multi-rail peer %s\n", libcfs_nid2str(nid), libcfs_nid2str(lp->lp_primary_nid)); return -EPERM; } - if (!lp->lp_multi_rail) - lp->lp_multi_rail = true; + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) + lp->lp_state |= LNET_PEER_MULTI_RAIL; + spin_unlock(&lp->lp_lock); lpni = lnet_find_peer_ni_locked(nid); if (!lpni) @@ -1183,7 +1189,7 @@ int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, return -ENOENT; *primary_nid = lp->lp_primary_nid; - *mr = lp->lp_multi_rail; + *mr = lnet_peer_is_multi_rail(lp); *nid = lpni->lpni_nid; snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, "NA"); if (lnet_isrouter(lpni) || From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 12/24] lustre: lnet: preferred NIs for non-Multi-Rail peers In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437800.16383.15417431282816541221.stgit@noble> From: Olaf Weber When a node sends a message to a peer NI, there may be a preferred local NI that should be the source of the message. This is in particular the case for non-Multi- Rail (NMR) peers, as an NMR peer depends in some cases on the source address of a message to correctly identify its origin. (This as opposed to using a UUID provided by a higher protocol layer.) Implement this by keeping an array of preferred local NIDs in the lnet_peer_ni structure. The case where only a single NID needs to be stored is optimized so that this can be done without needing to allocate any memory. A flag in the lnet_peer_ni, LNET_PEER_NI_NON_MR_PREF, indicates that the preferred NI was automatically added for an NMR peer. Note that a peer which has not been explicitly configured as Multi-Rail will be treated as non-Multi-Rail until proven otherwise. These automatic preferences will be cleared if the peer is changed to Multi-Rail. - lnet_peer_ni_set_non_mr_pref_nid() set NMR preferred NI for peer_ni - lnet_peer_ni_clr_non_mr_pref_nid() clear NMR preferred NI for peer_ni - lnet_peer_clr_non_mr_pref_nids() clear NMR preferred NIs for all peer_ni - lnet_peer_add_pref_nid() add a preferred NID - lnet_peer_del_pref_nid() delete a preferred NID WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25782 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 7 - .../staging/lustre/include/linux/lnet/lib-types.h | 10 + drivers/staging/lustre/lnet/lnet/lib-move.c | 49 +++- drivers/staging/lustre/lnet/lnet/peer.c | 257 +++++++++++++++++++- 4 files changed, 285 insertions(+), 38 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 75b47628c70e..2864bd8a403b 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -668,7 +668,8 @@ u32 lnet_get_dlc_seq_locked(void); struct lnet_peer_ni *lnet_get_next_peer_ni_locked(struct lnet_peer *peer, struct lnet_peer_net *peer_net, struct lnet_peer_ni *prev); -struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, int cpt); +struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, + int cpt); struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); void lnet_peer_net_added(struct lnet_net *net); @@ -679,8 +680,8 @@ int lnet_peer_tables_create(void); void lnet_debug_peer(lnet_nid_t nid); struct lnet_peer_net *lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id); -bool lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, - struct lnet_ni *ni); +bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); +int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 602978a1c86e..eff2aed5e5c1 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -481,14 +481,20 @@ struct lnet_peer_ni { unsigned int lpni_ping_feats; /* routers on this peer */ struct list_head lpni_routes; - /* array of preferred local nids */ - lnet_nid_t *lpni_pref_nids; + /* preferred local nids: if only one, use lpni_pref.nid */ + union lpni_pref { + lnet_nid_t nid; + lnet_nid_t *nids; + } lpni_pref; /* number of preferred NIDs in lnpi_pref_nids */ u32 lpni_pref_nnids; /* router checker state */ struct lnet_rc_data *lpni_rcd; }; +/* Preferred path added due to traffic on non-MR peer_ni */ +#define LNET_PEER_NI_NON_MR_PREF BIT(0) + struct lnet_peer { /* chain on global peer list */ struct list_head lp_on_lnet_peer_list; diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 0d0ad30bb164..99d8b22356bb 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -1267,7 +1267,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, * existing peer_ni, or create one and mark it as having been * created due to network traffic. */ - lpni = lnet_nid2peerni_locked(dst_nid, cpt); + lpni = lnet_nid2peerni_locked(dst_nid, LNET_NID_ANY, cpt); if (IS_ERR(lpni)) { lnet_net_unlock(cpt); return PTR_ERR(lpni); @@ -1281,14 +1281,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, return -EHOSTUNREACH; } - if (!lnet_peer_is_multi_rail(peer) && - lnet_get_num_peer_nis(peer) > 1) { - lnet_net_unlock(cpt); - CERROR("peer %s is declared to be non MR capable, yet configured with more than one NID\n", - libcfs_nid2str(dst_nid)); - return -EINVAL; - } - /* * STEP 1: first jab at determining best_ni * if src_nid is explicitly specified, then best_ni is already @@ -1373,8 +1365,14 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, } /* - * if the peer is not MR capable, then we should always send to it - * using the first NI in the NET we determined. + * We must use a consistent source address when sending to a + * non-MR peer. However, a non-MR peer can have multiple NIDs + * on multiple networks, and we may even need to talk to this + * peer on multiple networks -- certain types of + * load-balancing configuration do this. + * + * So we need to pick the NI the peer prefers for this + * particular network. */ if (!lnet_peer_is_multi_rail(peer)) { if (!best_lpni) { @@ -1384,10 +1382,26 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, return -EHOSTUNREACH; } - /* best ni could be set because src_nid was provided */ + /* best ni is already set if src_nid was provided */ + if (!best_ni) { + /* Get the target peer_ni */ + peer_net = lnet_peer_get_net_locked( + peer, LNET_NIDNET(best_lpni->lpni_nid)); + list_for_each_entry(lpni, &peer_net->lpn_peer_nis, + lpni_on_peer_net_list) { + if (lpni->lpni_pref_nnids == 0) + continue; + LASSERT(lpni->lpni_pref_nnids == 1); + best_ni = lnet_nid2ni_locked( + lpni->lpni_pref.nid, cpt); + break; + } + } + /* if best_ni is still not set just pick one */ if (!best_ni) { best_ni = lnet_net2ni_locked( best_lpni->lpni_net->net_id, cpt); + /* If there is no best_ni we don't have a route */ if (!best_ni) { lnet_net_unlock(cpt); CERROR("no path to %s from net %s\n", @@ -1395,7 +1409,13 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, libcfs_net2str(best_lpni->lpni_net->net_id)); return -EHOSTUNREACH; } + lpni = list_entry(peer_net->lpn_peer_nis.next, + struct lnet_peer_ni, + lpni_on_peer_net_list); } + /* Set preferred NI if necessary. */ + if (lpni->lpni_pref_nnids == 0) + lnet_peer_ni_set_non_mr_pref_nid(lpni, best_ni->ni_nid); } /* @@ -1593,7 +1613,8 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, */ if (!lnet_is_peer_ni_healthy_locked(lpni)) continue; - ni_is_pref = lnet_peer_is_ni_pref_locked(lpni, best_ni); + ni_is_pref = lnet_peer_is_pref_nid_locked(lpni, + best_ni->ni_nid); /* if this is a preferred peer use it */ if (!preferred && ni_is_pref) { @@ -2380,7 +2401,7 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid, } lnet_net_lock(cpt); - lpni = lnet_nid2peerni_locked(from_nid, cpt); + lpni = lnet_nid2peerni_locked(from_nid, ni->ni_nid, cpt); if (IS_ERR(lpni)) { lnet_net_unlock(cpt); CERROR("%s, src %s: Dropping %s (error %ld looking up sender)\n", diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index cc2b926b76e4..44a2bf641260 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -617,18 +617,233 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, return lpni; } +/* + * Test whether a ni is a preferred ni for this peer_ni, e.g, whether + * this is a preferred point-to-point path. Call with lnet_net_lock in + * shared mmode. + */ bool -lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, struct lnet_ni *ni) +lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid) { int i; + if (lpni->lpni_pref_nnids == 0) + return false; + if (lpni->lpni_pref_nnids == 1) + return lpni->lpni_pref.nid == nid; for (i = 0; i < lpni->lpni_pref_nnids; i++) { - if (lpni->lpni_pref_nids[i] == ni->ni_nid) + if (lpni->lpni_pref.nids[i] == nid) return true; } return false; } +/* + * Set a single ni as preferred, provided no preferred ni is already + * defined. Only to be used for non-multi-rail peer_ni. + */ +int +lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) +{ + int rc = 0; + + spin_lock(&lpni->lpni_lock); + if (nid == LNET_NID_ANY) { + rc = -EINVAL; + } else if (lpni->lpni_pref_nnids > 0) { + rc = -EPERM; + } else if (lpni->lpni_pref_nnids == 0) { + lpni->lpni_pref.nid = nid; + lpni->lpni_pref_nnids = 1; + lpni->lpni_state |= LNET_PEER_NI_NON_MR_PREF; + } + spin_unlock(&lpni->lpni_lock); + + CDEBUG(D_NET, "peer %s nid %s: %d\n", + libcfs_nid2str(lpni->lpni_nid), libcfs_nid2str(nid), rc); + return rc; +} + +/* + * Clear the preferred NID from a non-multi-rail peer_ni, provided + * this preference was set by lnet_peer_ni_set_non_mr_pref_nid(). + */ +int +lnet_peer_ni_clr_non_mr_pref_nid(struct lnet_peer_ni *lpni) +{ + int rc = 0; + + spin_lock(&lpni->lpni_lock); + if (lpni->lpni_state & LNET_PEER_NI_NON_MR_PREF) { + lpni->lpni_pref_nnids = 0; + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; + } else if (lpni->lpni_pref_nnids == 0) { + rc = -ENOENT; + } else { + rc = -EPERM; + } + spin_unlock(&lpni->lpni_lock); + + CDEBUG(D_NET, "peer %s: %d\n", + libcfs_nid2str(lpni->lpni_nid), rc); + return rc; +} + +/* + * Clear the preferred NIDs from a non-multi-rail peer. + */ +void +lnet_peer_clr_non_mr_pref_nids(struct lnet_peer *lp) +{ + struct lnet_peer_ni *lpni = NULL; + + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) + lnet_peer_ni_clr_non_mr_pref_nid(lpni); +} + +int +lnet_peer_add_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) +{ + lnet_nid_t *nids = NULL; + lnet_nid_t *oldnids = NULL; + struct lnet_peer *lp = lpni->lpni_peer_net->lpn_peer; + int size; + int i; + int rc = 0; + + if (nid == LNET_NID_ANY) { + rc = -EINVAL; + goto out; + } + + if (lpni->lpni_pref_nnids == 1 && lpni->lpni_pref.nid == nid) { + rc = -EEXIST; + goto out; + } + + /* A non-MR node may have only one preferred NI per peer_ni */ + if (lpni->lpni_pref_nnids > 0) { + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + rc = -EPERM; + goto out; + } + } + + if (lpni->lpni_pref_nnids != 0) { + size = sizeof(*nids) * (lpni->lpni_pref_nnids + 1); + nids = kzalloc_cpt(size, GFP_KERNEL, lpni->lpni_cpt); + if (!nids) { + rc = -ENOMEM; + goto out; + } + for (i = 0; i < lpni->lpni_pref_nnids; i++) { + if (lpni->lpni_pref.nids[i] == nid) { + kfree(nids); + rc = -EEXIST; + goto out; + } + nids[i] = lpni->lpni_pref.nids[i]; + } + nids[i] = nid; + } + + lnet_net_lock(LNET_LOCK_EX); + spin_lock(&lpni->lpni_lock); + if (lpni->lpni_pref_nnids == 0) { + lpni->lpni_pref.nid = nid; + } else { + oldnids = lpni->lpni_pref.nids; + lpni->lpni_pref.nids = nids; + } + lpni->lpni_pref_nnids++; + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; + spin_unlock(&lpni->lpni_lock); + lnet_net_unlock(LNET_LOCK_EX); + + kfree(oldnids); +out: + if (rc == -EEXIST && (lpni->lpni_state & LNET_PEER_NI_NON_MR_PREF)) { + spin_lock(&lpni->lpni_lock); + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; + spin_unlock(&lpni->lpni_lock); + } + CDEBUG(D_NET, "peer %s nid %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), rc); + return rc; +} + +int +lnet_peer_del_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) +{ + lnet_nid_t *nids = NULL; + lnet_nid_t *oldnids = NULL; + struct lnet_peer *lp = lpni->lpni_peer_net->lpn_peer; + int size; + int i, j; + int rc = 0; + + if (lpni->lpni_pref_nnids == 0) { + rc = -ENOENT; + goto out; + } + + if (lpni->lpni_pref_nnids == 1) { + if (lpni->lpni_pref.nid != nid) { + rc = -ENOENT; + goto out; + } + } else if (lpni->lpni_pref_nnids == 2) { + if (lpni->lpni_pref.nids[0] != nid && + lpni->lpni_pref.nids[1] != nid) { + rc = -ENOENT; + goto out; + } + } else { + size = sizeof(*nids) * (lpni->lpni_pref_nnids - 1); + nids = kzalloc_cpt(size, GFP_KERNEL, lpni->lpni_cpt); + if (!nids) { + rc = -ENOMEM; + goto out; + } + for (i = 0, j = 0; i < lpni->lpni_pref_nnids; i++) { + if (lpni->lpni_pref.nids[i] != nid) + continue; + nids[j++] = lpni->lpni_pref.nids[i]; + } + /* Check if we actually removed a nid. */ + if (j == lpni->lpni_pref_nnids) { + kfree(nids); + rc = -ENOENT; + goto out; + } + } + + lnet_net_lock(LNET_LOCK_EX); + spin_lock(&lpni->lpni_lock); + if (lpni->lpni_pref_nnids == 1) { + lpni->lpni_pref.nid = LNET_NID_ANY; + } else if (lpni->lpni_pref_nnids == 2) { + oldnids = lpni->lpni_pref.nids; + if (oldnids[0] == nid) + lpni->lpni_pref.nid = oldnids[1]; + else + lpni->lpni_pref.nid = oldnids[2]; + } else { + oldnids = lpni->lpni_pref.nids; + lpni->lpni_pref.nids = nids; + } + lpni->lpni_pref_nnids--; + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; + spin_unlock(&lpni->lpni_lock); + lnet_net_unlock(LNET_LOCK_EX); + + kfree(oldnids); +out: + CDEBUG(D_NET, "peer %s nid %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), rc); + return rc; +} + lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid) { @@ -653,7 +868,7 @@ LNetPrimaryNID(lnet_nid_t nid) int cpt; cpt = lnet_net_lock_current(); - lpni = lnet_nid2peerni_locked(nid, cpt); + lpni = lnet_nid2peerni_locked(nid, LNET_NID_ANY, cpt); if (IS_ERR(lpni)) { rc = PTR_ERR(lpni); goto out_unlock; @@ -802,6 +1017,7 @@ lnet_peer_add(lnet_nid_t nid, bool mr) spin_lock(&lp->lp_lock); if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { /* The mr state is sticky. */ CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", @@ -829,8 +1045,10 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) return -EPERM; } - if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); + } spin_unlock(&lp->lp_lock); lpni = lnet_find_peer_ni_locked(nid); @@ -856,28 +1074,27 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) * lpni creation initiated due to traffic either sending or receiving. */ static int -lnet_peer_ni_traffic_add(lnet_nid_t nid) +lnet_peer_ni_traffic_add(lnet_nid_t nid, lnet_nid_t pref) { struct lnet_peer_ni *lpni; - int rc = 0; + int rc; if (nid == LNET_NID_ANY) return -EINVAL; /* lnet_net_lock is not needed here because ln_api_lock is held */ lpni = lnet_find_peer_ni_locked(nid); - if (lpni) { - /* - * TODO: lnet_update_primary_nid() but not all of it - * only indicate if we're converting this to MR capable - * Can happen due to DD - */ - lnet_peer_ni_decref_locked(lpni); - } else { + if (!lpni) { rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); + if (rc) + return rc; + lpni = lnet_find_peer_ni_locked(nid); } + if (pref != LNET_NID_ANY) + lnet_peer_ni_set_non_mr_pref_nid(lpni, pref); + lnet_peer_ni_decref_locked(lpni); - return rc; + return 0; } /* @@ -984,6 +1201,8 @@ lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) ptable->pt_zombies--; spin_unlock(&ptable->pt_zombie_lock); + if (lpni->lpni_pref_nnids > 1) + kfree(lpni->lpni_pref.nids); kfree(lpni); } @@ -1006,7 +1225,7 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) lnet_net_unlock(cpt); - rc = lnet_peer_ni_traffic_add(nid); + rc = lnet_peer_ni_traffic_add(nid, LNET_NID_ANY); if (rc) { lpni = ERR_PTR(rc); goto out_net_relock; @@ -1022,7 +1241,7 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) } struct lnet_peer_ni * -lnet_nid2peerni_locked(lnet_nid_t nid, int cpt) +lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) { struct lnet_peer_ni *lpni = NULL; int rc; @@ -1061,7 +1280,7 @@ lnet_nid2peerni_locked(lnet_nid_t nid, int cpt) goto out_mutex_unlock; } - rc = lnet_peer_ni_traffic_add(nid); + rc = lnet_peer_ni_traffic_add(nid, pref); if (rc) { lpni = ERR_PTR(rc); goto out_mutex_unlock; @@ -1087,7 +1306,7 @@ lnet_debug_peer(lnet_nid_t nid) cpt = lnet_cpt_of_nid(nid, NULL); lnet_net_lock(cpt); - lp = lnet_nid2peerni_locked(nid, cpt); + lp = lnet_nid2peerni_locked(nid, LNET_NID_ANY, cpt); if (IS_ERR(lp)) { lnet_net_unlock(cpt); CDEBUG(D_WARNING, "No peer %s\n", libcfs_nid2str(nid)); From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 13/24] lustre: lnet: add LNET_PEER_CONFIGURED flag In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437804.16383.1008375422641070080.stgit@noble> From: Olaf Weber Add the LNET_PEER_CONFIGURED flag, which indicates that a peer has been configured by DLC. This is used to enforce that only DLC can modify such a peer. This includes some further refactoring of the code that creates or modifies peers to ensure that the flag is properly passed through, set, and cleared. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25783 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 12 + .../staging/lustre/include/linux/lnet/lib-types.h | 1 drivers/staging/lustre/lnet/lnet/peer.c | 426 +++++++++++++------- 3 files changed, 290 insertions(+), 149 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 2864bd8a403b..563417510722 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -764,4 +764,16 @@ lnet_peer_is_multi_rail(struct lnet_peer *lp) return lp->lp_state & LNET_PEER_MULTI_RAIL; } +static inline bool +lnet_peer_ni_is_configured(struct lnet_peer_ni *lpni) +{ + return lpni->lpni_peer_net->lpn_peer->lp_state & LNET_PEER_CONFIGURED; +} + +static inline bool +lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) +{ + return lpni->lpni_nid == lpni->lpni_peer_net->lpn_peer->lp_primary_nid; +} + #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index eff2aed5e5c1..d1721fd01d93 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -513,6 +513,7 @@ struct lnet_peer { }; #define LNET_PEER_MULTI_RAIL BIT(0) +#define LNET_PEER_CONFIGURED BIT(1) struct lnet_peer_net { /* chain on peer block */ diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 44a2bf641260..09c1b5516f6b 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -191,10 +191,10 @@ lnet_peer_alloc(lnet_nid_t nid) } static void -lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) +lnet_peer_detach_peer_ni(struct lnet_peer_ni *lpni) { - struct lnet_peer_net *peer_net; - struct lnet_peer *peer; + struct lnet_peer_net *lpn; + struct lnet_peer *lp; /* TODO: could the below situation happen? accessing an already * destroyed peer? @@ -203,24 +203,28 @@ lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) !lpni->lpni_peer_net->lpn_peer) return; - peer_net = lpni->lpni_peer_net; - peer = lpni->lpni_peer_net->lpn_peer; + lpn = lpni->lpni_peer_net; + lp = lpni->lpni_peer_net->lpn_peer; + + CDEBUG(D_NET, "peer %s NID %s\n", + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(lpni->lpni_nid)); list_del_init(&lpni->lpni_on_peer_net_list); lpni->lpni_peer_net = NULL; - /* if peer_net is empty, then remove it from the peer */ - if (list_empty(&peer_net->lpn_peer_nis)) { - list_del_init(&peer_net->lpn_on_peer_list); - peer_net->lpn_peer = NULL; - kfree(peer_net); + /* if lpn is empty, then remove it from the peer */ + if (list_empty(&lpn->lpn_peer_nis)) { + list_del_init(&lpn->lpn_on_peer_list); + lpn->lpn_peer = NULL; + kfree(lpn); /* If the peer is empty then remove it from the * the_lnet.ln_peers. */ - if (list_empty(&peer->lp_peer_nets)) { - list_del_init(&peer->lp_on_lnet_peer_list); - kfree(peer); + if (list_empty(&lp->lp_peer_nets)) { + list_del_init(&lp->lp_on_lnet_peer_list); + kfree(lp); } } } @@ -263,10 +267,10 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) ptable->pt_zombies++; spin_unlock(&ptable->pt_zombie_lock); - /* no need to keep this peer on the hierarchy anymore */ - lnet_try_destroy_peer_hierarchy_locked(lpni); + /* no need to keep this peer_ni on the hierarchy anymore */ + lnet_peer_detach_peer_ni(lpni); - /* decrement reference on peer */ + /* decrement reference on peer_ni */ lnet_peer_ni_decref_locked(lpni); return 0; @@ -329,6 +333,8 @@ lnet_peer_del_locked(struct lnet_peer *peer) struct lnet_peer_ni *lpni = NULL, *lpni2; int rc = 0, rc2 = 0; + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(peer->lp_primary_nid)); + lpni = lnet_get_next_peer_ni_locked(peer, NULL, lpni); while (lpni) { lpni2 = lnet_get_next_peer_ni_locked(peer, NULL, lpni); @@ -352,31 +358,36 @@ lnet_peer_del(struct lnet_peer *peer) } /* - * Delete a NID from a peer. - * Implements a few sanity checks. - * Call with ln_api_mutex held. + * Delete a NID from a peer. Call with ln_api_mutex held. + * + * Error codes: + * -EPERM: Non-DLC deletion from DLC-configured peer. + * -ENOENT: No lnet_peer_ni corresponding to the nid. + * -ECHILD: The lnet_peer_ni isn't connected to the peer. + * -EBUSY: The lnet_peer_ni is the primary, and not the only peer_ni. */ static int -lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) +lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) { - struct lnet_peer *lp2; struct lnet_peer_ni *lpni; + lnet_nid_t primary_nid = lp->lp_primary_nid; + int rc = 0; + if (!(flags & LNET_PEER_CONFIGURED)) { + if (lp->lp_state & LNET_PEER_CONFIGURED) { + rc = -EPERM; + goto out; + } + } lpni = lnet_find_peer_ni_locked(nid); if (!lpni) { - CERROR("Cannot remove unknown nid %s from peer %s\n", - libcfs_nid2str(nid), - libcfs_nid2str(lp->lp_primary_nid)); - return -ENOENT; + rc = -ENOENT; + goto out; } lnet_peer_ni_decref_locked(lpni); - lp2 = lpni->lpni_peer_net->lpn_peer; - if (lp2 != lp) { - CERROR("Nid %s is attached to peer %s, not peer %s\n", - libcfs_nid2str(nid), - libcfs_nid2str(lp2->lp_primary_nid), - libcfs_nid2str(lp->lp_primary_nid)); - return -EINVAL; + if (lp != lpni->lpni_peer_net->lpn_peer) { + rc = -ECHILD; + goto out; } /* @@ -384,16 +395,19 @@ lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) * is the only NID. */ if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { - CERROR("Cannot delete primary NID %s from multi-NID peer\n", - libcfs_nid2str(nid)); - return -EINVAL; + rc = -EBUSY; + goto out; } lnet_net_lock(LNET_LOCK_EX); lnet_peer_ni_del_locked(lpni); lnet_net_unlock(LNET_LOCK_EX); - return 0; +out: + CDEBUG(D_NET, "peer %s NID %s flags %#x: %d\n", + libcfs_nid2str(primary_nid), libcfs_nid2str(nid), flags, rc); + + return rc; } static void @@ -895,46 +909,27 @@ lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) return NULL; } +/* + * Always returns 0, but it the last function called from functions + * that do return an int, so returning 0 here allows the compiler to + * do a tail call. + */ static int -lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni - *lpni, - lnet_nid_t nid) +lnet_peer_attach_peer_ni(struct lnet_peer *lp, + struct lnet_peer_net *lpn, + struct lnet_peer_ni *lpni, + unsigned int flags) { - struct lnet_peer_net *lpn = NULL; struct lnet_peer_table *ptable; - u32 net_id = LNET_NIDNET(nid); - - /* - * Create the peer_ni, peer_net, and peer if they don't exist - * yet. - */ - if (lp) { - lpn = lnet_peer_get_net_locked(lp, net_id); - } else { - lp = lnet_peer_alloc(nid); - if (!lp) - goto out_enomem; - } - - if (!lpn) { - lpn = lnet_peer_net_alloc(net_id); - if (!lpn) - goto out_maybe_free_lp; - } - - if (!lpni) { - lpni = lnet_peer_ni_alloc(nid); - if (!lpni) - goto out_maybe_free_lpn; - } /* Install the new peer_ni */ lnet_net_lock(LNET_LOCK_EX); /* Add peer_ni to global peer table hash, if necessary. */ if (list_empty(&lpni->lpni_hashlist)) { + int hash = lnet_nid2peerhash(lpni->lpni_nid); + ptable = the_lnet.ln_peer_tables[lpni->lpni_cpt]; - list_add_tail(&lpni->lpni_hashlist, - &ptable->pt_hash[lnet_nid2peerhash(nid)]); + list_add_tail(&lpni->lpni_hashlist, &ptable->pt_hash[hash]); ptable->pt_version++; atomic_inc(&ptable->pt_number); atomic_inc(&lpni->lpni_refcount); @@ -942,7 +937,7 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni /* Detach the peer_ni from an existing peer, if necessary. */ if (lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer != lp) - lnet_try_destroy_peer_hierarchy_locked(lpni); + lnet_peer_detach_peer_ni(lpni); /* Add peer_ni to peer_net */ lpni->lpni_peer_net = lpn; @@ -957,33 +952,42 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni /* Add peer to global peer list */ if (list_empty(&lp->lp_on_lnet_peer_list)) list_add_tail(&lp->lp_on_lnet_peer_list, &the_lnet.ln_peers); + + /* Update peer state */ + spin_lock(&lp->lp_lock); + if (flags & LNET_PEER_CONFIGURED) { + if (!(lp->lp_state & LNET_PEER_CONFIGURED)) + lp->lp_state |= LNET_PEER_CONFIGURED; + } + if (flags & LNET_PEER_MULTI_RAIL) { + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); + } + } + spin_unlock(&lp->lp_lock); + lnet_net_unlock(LNET_LOCK_EX); - return 0; + CDEBUG(D_NET, "peer %s NID %s flags %#x\n", + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(lpni->lpni_nid), flags); -out_maybe_free_lpn: - if (list_empty(&lpn->lpn_on_peer_list)) - kfree(lpn); -out_maybe_free_lp: - if (list_empty(&lp->lp_on_lnet_peer_list)) - kfree(lp); -out_enomem: - return -ENOMEM; + return 0; } /* * Create a new peer, with nid as its primary nid. * - * It is not an error if the peer already exists, provided that the - * given nid is the primary NID. - * * Call with the lnet_api_mutex held. */ static int -lnet_peer_add(lnet_nid_t nid, bool mr) +lnet_peer_add(lnet_nid_t nid, unsigned int flags) { struct lnet_peer *lp; + struct lnet_peer_net *lpn; struct lnet_peer_ni *lpni; + int rc = 0; LASSERT(nid != LNET_NID_ANY); @@ -992,82 +996,153 @@ lnet_peer_add(lnet_nid_t nid, bool mr) * lnet_api_mutex is held. */ lpni = lnet_find_peer_ni_locked(nid); - if (!lpni) { - int rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); - if (rc != 0) - return rc; - lpni = lnet_find_peer_ni_locked(nid); - LASSERT(lpni); + if (lpni) { + /* A peer with this NID already exists. */ + lp = lpni->lpni_peer_net->lpn_peer; + lnet_peer_ni_decref_locked(lpni); + /* + * This is an error if the peer was configured and the + * primary NID differs or an attempt is made to change + * the Multi-Rail flag. Otherwise the assumption is + * that an existing peer is being modified. + */ + if (lp->lp_state & LNET_PEER_CONFIGURED) { + if (lp->lp_primary_nid != nid) + rc = -EEXIST; + else if ((lp->lp_state ^ flags) & LNET_PEER_MULTI_RAIL) + rc = -EPERM; + goto out; + } + /* Delete and recreate as a configured peer. */ + lnet_peer_del(lp); } - lp = lpni->lpni_peer_net->lpn_peer; - lnet_peer_ni_decref_locked(lpni); - /* A found peer must have this primary NID */ - if (lp->lp_primary_nid != nid) - return -EEXIST; + /* Create peer, peer_net, and peer_ni. */ + rc = -ENOMEM; + lp = lnet_peer_alloc(nid); + if (!lp) + goto out; + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); + if (!lpn) + goto out_free_lp; + lpni = lnet_peer_ni_alloc(nid); + if (!lpni) + goto out_free_lpn; - /* - * If we found an lpni that is not a multi-rail, which could occur - * if lpni is already created as a non-mr lpni or we just created - * it, then make sure you indicate that this lpni is a primary mr - * capable peer. - * - * TODO: update flags if necessary - */ - spin_lock(&lp->lp_lock); - if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { - lp->lp_state |= LNET_PEER_MULTI_RAIL; - lnet_peer_clr_non_mr_pref_nids(lp); - } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { - /* The mr state is sticky. */ - CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", - libcfs_nid2str(nid)); - } - spin_unlock(&lp->lp_lock); + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); - return 0; +out_free_lpn: + kfree(lpn); +out_free_lp: + kfree(lp); +out: + CDEBUG(D_NET, "peer %s NID flags %#x: %d\n", + libcfs_nid2str(nid), flags, rc); + return rc; } +/* + * Add a NID to a peer. Call with ln_api_mutex held. + * + * Error codes: + * -EPERM: Non-DLC addition to a DLC-configured peer. + * -EEXIST: The NID was configured by DLC for a different peer. + * -ENOMEM: Out of memory. + * -ENOTUNIQ: Adding a second peer NID on a single network on a + * non-multi-rail peer. + */ static int -lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) +lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) { + struct lnet_peer_net *lpn; struct lnet_peer_ni *lpni; + int rc = 0; LASSERT(lp); LASSERT(nid != LNET_NID_ANY); - spin_lock(&lp->lp_lock); - if (!mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { - spin_unlock(&lp->lp_lock); - CERROR("Cannot add nid %s to non-multi-rail peer %s\n", - libcfs_nid2str(nid), - libcfs_nid2str(lp->lp_primary_nid)); - return -EPERM; + /* A configured peer can only be updated through configuration. */ + if (!(flags & LNET_PEER_CONFIGURED)) { + if (lp->lp_state & LNET_PEER_CONFIGURED) { + rc = -EPERM; + goto out; + } } - if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { - lp->lp_state |= LNET_PEER_MULTI_RAIL; - lnet_peer_clr_non_mr_pref_nids(lp); + /* + * The MULTI_RAIL flag can be set but not cleared, because + * that would leave the peer struct in an invalid state. + */ + if (flags & LNET_PEER_MULTI_RAIL) { + spin_lock(&lp->lp_lock); + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); + } + spin_unlock(&lp->lp_lock); + } else if (lp->lp_state & LNET_PEER_MULTI_RAIL) { + rc = -EPERM; + goto out; } - spin_unlock(&lp->lp_lock); lpni = lnet_find_peer_ni_locked(nid); - if (!lpni) - return lnet_peer_setup_hierarchy(lp, NULL, nid); + if (lpni) { + /* + * A peer_ni already exists. This is only a problem if + * it is not connected to this peer and was configured + * by DLC. + */ + lnet_peer_ni_decref_locked(lpni); + if (lpni->lpni_peer_net->lpn_peer == lp) + goto out; + if (lnet_peer_ni_is_configured(lpni)) { + rc = -EEXIST; + goto out; + } + /* If this is the primary NID, destroy the peer. */ + if (lnet_peer_ni_is_primary(lpni)) { + lnet_peer_del(lpni->lpni_peer_net->lpn_peer); + lpni = lnet_peer_ni_alloc(nid); + if (!lpni) { + rc = -ENOMEM; + goto out; + } + } + } else { + lpni = lnet_peer_ni_alloc(nid); + if (!lpni) { + rc = -ENOMEM; + goto out; + } + } - if (lpni->lpni_peer_net->lpn_peer != lp) { - struct lnet_peer *lp2 = lpni->lpni_peer_net->lpn_peer; - CERROR("Cannot add NID %s owned by peer %s to peer %s\n", - libcfs_nid2str(lpni->lpni_nid), - libcfs_nid2str(lp2->lp_primary_nid), - libcfs_nid2str(lp->lp_primary_nid)); - return -EEXIST; + /* + * Get the peer_net. Check that we're not adding a second + * peer_ni on a peer_net of a non-multi-rail peer. + */ + lpn = lnet_peer_get_net_locked(lp, LNET_NIDNET(nid)); + if (!lpn) { + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); + if (!lpn) { + rc = -ENOMEM; + goto out_free_lpni; + } + } else if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + rc = -ENOTUNIQ; + goto out_free_lpni; } - CDEBUG(D_NET, "NID %s is already owned by peer %s\n", - libcfs_nid2str(lpni->lpni_nid), - libcfs_nid2str(lp->lp_primary_nid)); - return 0; + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); + +out_free_lpni: + /* If the peer_ni was allocated above its peer_net pointer is NULL */ + if (!lpni->lpni_peer_net) + kfree(lpni); +out: + CDEBUG(D_NET, "peer %s NID %s flags %#x: %d\n", + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), + flags, rc); + return rc; } /* @@ -1076,25 +1151,53 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) static int lnet_peer_ni_traffic_add(lnet_nid_t nid, lnet_nid_t pref) { + struct lnet_peer *lp; + struct lnet_peer_net *lpn; struct lnet_peer_ni *lpni; - int rc; + unsigned int flags = 0; + int rc = 0; - if (nid == LNET_NID_ANY) - return -EINVAL; + if (nid == LNET_NID_ANY) { + rc = -EINVAL; + goto out; + } /* lnet_net_lock is not needed here because ln_api_lock is held */ lpni = lnet_find_peer_ni_locked(nid); - if (!lpni) { - rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); - if (rc) - return rc; - lpni = lnet_find_peer_ni_locked(nid); + if (lpni) { + /* + * We must have raced with another thread. Since we + * know next to nothing about a peer_ni created by + * traffic, we just assume everything is ok and + * return. + */ + lnet_peer_ni_decref_locked(lpni); + goto out; } + + /* Create peer, peer_net, and peer_ni. */ + rc = -ENOMEM; + lp = lnet_peer_alloc(nid); + if (!lp) + goto out; + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); + if (!lpn) + goto out_free_lp; + lpni = lnet_peer_ni_alloc(nid); + if (!lpni) + goto out_free_lpn; if (pref != LNET_NID_ANY) lnet_peer_ni_set_non_mr_pref_nid(lpni, pref); - lnet_peer_ni_decref_locked(lpni); - return 0; + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); + +out_free_lpn: + kfree(lpn); +out_free_lp: + kfree(lp); +out: + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(nid), rc); + return rc; } /* @@ -1114,17 +1217,22 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) { struct lnet_peer *lp = NULL; struct lnet_peer_ni *lpni; + unsigned int flags; /* The prim_nid must always be specified */ if (prim_nid == LNET_NID_ANY) return -EINVAL; + flags = LNET_PEER_CONFIGURED; + if (mr) + flags |= LNET_PEER_MULTI_RAIL; + /* * If nid isn't specified, we must create a new peer with * prim_nid as its primary nid. */ if (nid == LNET_NID_ANY) - return lnet_peer_add(prim_nid, mr); + return lnet_peer_add(prim_nid, flags); /* Look up the prim_nid, which must exist. */ lpni = lnet_find_peer_ni_locked(prim_nid); @@ -1133,6 +1241,14 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) lnet_peer_ni_decref_locked(lpni); lp = lpni->lpni_peer_net->lpn_peer; + /* Peer must have been configured. */ + if (!(lp->lp_state & LNET_PEER_CONFIGURED)) { + CDEBUG(D_NET, "peer %s was not configured\n", + libcfs_nid2str(prim_nid)); + return -ENOENT; + } + + /* Primary NID must match */ if (lp->lp_primary_nid != prim_nid) { CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", libcfs_nid2str(prim_nid), @@ -1140,7 +1256,14 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) return -ENODEV; } - return lnet_peer_add_nid(lp, nid, mr); + /* Multi-Rail flag must match. */ + if ((lp->lp_state ^ flags) & LNET_PEER_MULTI_RAIL) { + CDEBUG(D_NET, "multi-rail state mismatch for peer %s\n", + libcfs_nid2str(prim_nid)); + return -EPERM; + } + + return lnet_peer_add_nid(lp, nid, flags); } /* @@ -1159,6 +1282,7 @@ lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) { struct lnet_peer *lp; struct lnet_peer_ni *lpni; + unsigned int flags; if (prim_nid == LNET_NID_ANY) return -EINVAL; @@ -1179,7 +1303,11 @@ lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) if (nid == LNET_NID_ANY || nid == lp->lp_primary_nid) return lnet_peer_del(lp); - return lnet_peer_del_nid(lp, nid); + flags = LNET_PEER_CONFIGURED; + if (lp->lp_state & LNET_PEER_MULTI_RAIL) + flags |= LNET_PEER_MULTI_RAIL; + + return lnet_peer_del_nid(lp, nid, flags); } void From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 14/24] lustre: lnet: reference counts on lnet_peer/lnet_peer_net In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437808.16383.1725584261522697360.stgit@noble> From: Olaf Weber Peer discovery will be keeping track of lnet_peer structures, so there will be references to an lnet_peer independent of the references implied by lnet_peer_ni structures. Manage this by adding explicit reference counts to lnet_peer_net and lnet_peer. Each lnet_peer_net has a hold on the lnet_peer it links to with its lpn_peer pointer. This hold is only removed when that pointer is assigned a new value or the lnet_peer_net is freed. Just removing an lnet_peer_net from the lp_peer_nets list does not release this hold, it just prevents new lookups of the lnet_peer_net via the lnet_peer. Each lnet_peer_ni has a hold on the lnet_peer_net it links to with its lpni_peer_net pointer. This hold is only removed when that pointer is assigned a new value or the lnet_peer_ni is freed. Just removing an lnet_peer_ni from the lpn_peer_nis list does not release this hold, it just prevents new lookups of the lnet_peer_ni via the lnet_peer_net. This ensures that given a lnet_peer_ni *lpni, we can rely on lpni->lpni_peer_net->lpn_peer pointing to a valid lnet_peer. Keep a count of the total number of lnet_peer_ni attached to an lnet_peer in lp_nnis. Split the global ln_peers list into per-lnet_peer_table lists. The CPT of the peer table in which the lnet_peer is linked is stored in lp_cpt. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25784 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 49 +++-- .../staging/lustre/include/linux/lnet/lib-types.h | 50 ++++- drivers/staging/lustre/lnet/lnet/api-ni.c | 1 drivers/staging/lustre/lnet/lnet/lib-move.c | 8 - drivers/staging/lustre/lnet/lnet/peer.c | 210 ++++++++++++++------ 5 files changed, 227 insertions(+), 91 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 563417510722..aad25eb0011b 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -310,6 +310,36 @@ lnet_handle2me(struct lnet_handle_me *handle) return lh_entry(lh, struct lnet_me, me_lh); } +static inline void +lnet_peer_net_addref_locked(struct lnet_peer_net *lpn) +{ + atomic_inc(&lpn->lpn_refcount); +} + +void lnet_destroy_peer_net_locked(struct lnet_peer_net *lpn); + +static inline void +lnet_peer_net_decref_locked(struct lnet_peer_net *lpn) +{ + if (atomic_dec_and_test(&lpn->lpn_refcount)) + lnet_destroy_peer_net_locked(lpn); +} + +static inline void +lnet_peer_addref_locked(struct lnet_peer *lp) +{ + atomic_inc(&lp->lp_refcount); +} + +void lnet_destroy_peer_locked(struct lnet_peer *lp); + +static inline void +lnet_peer_decref_locked(struct lnet_peer *lp) +{ + if (atomic_dec_and_test(&lp->lp_refcount)) + lnet_destroy_peer_locked(lp); +} + static inline void lnet_peer_ni_addref_locked(struct lnet_peer_ni *lp) { @@ -695,21 +725,6 @@ int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, __u32 *peer_rtr_credits, __u32 *peer_min_rtr_credtis, __u32 *peer_tx_qnob); -static inline __u32 -lnet_get_num_peer_nis(struct lnet_peer *peer) -{ - struct lnet_peer_net *lpn; - struct lnet_peer_ni *lpni; - __u32 count = 0; - - list_for_each_entry(lpn, &peer->lp_peer_nets, lpn_on_peer_list) - list_for_each_entry(lpni, &lpn->lpn_peer_nis, - lpni_on_peer_net_list) - count++; - - return count; -} - static inline bool lnet_is_peer_ni_healthy_locked(struct lnet_peer_ni *lpni) { @@ -728,7 +743,7 @@ lnet_is_peer_net_healthy_locked(struct lnet_peer_net *peer_net) struct lnet_peer_ni *lpni; list_for_each_entry(lpni, &peer_net->lpn_peer_nis, - lpni_on_peer_net_list) { + lpni_peer_nis) { if (lnet_is_peer_ni_healthy_locked(lpni)) return true; } @@ -741,7 +756,7 @@ lnet_is_peer_healthy_locked(struct lnet_peer *peer) { struct lnet_peer_net *peer_net; - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { if (lnet_is_peer_net_healthy_locked(peer_net)) return true; } diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index d1721fd01d93..260619e19bde 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -411,7 +411,8 @@ struct lnet_rc_data { }; struct lnet_peer_ni { - struct list_head lpni_on_peer_net_list; + /* chain on lpn_peer_nis */ + struct list_head lpni_peer_nis; /* chain on remote peer list */ struct list_head lpni_on_remote_peer_ni_list; /* chain on peer hash */ @@ -496,8 +497,8 @@ struct lnet_peer_ni { #define LNET_PEER_NI_NON_MR_PREF BIT(0) struct lnet_peer { - /* chain on global peer list */ - struct list_head lp_on_lnet_peer_list; + /* chain on pt_peer_list */ + struct list_head lp_peer_list; /* list of peer nets */ struct list_head lp_peer_nets; @@ -505,6 +506,15 @@ struct lnet_peer { /* primary NID of the peer */ lnet_nid_t lp_primary_nid; + /* CPT of peer_table */ + int lp_cpt; + + /* number of NIDs on this peer */ + int lp_nnis; + + /* reference count */ + atomic_t lp_refcount; + /* lock protecting peer state flags */ spinlock_t lp_lock; @@ -516,8 +526,8 @@ struct lnet_peer { #define LNET_PEER_CONFIGURED BIT(1) struct lnet_peer_net { - /* chain on peer block */ - struct list_head lpn_on_peer_list; + /* chain on lp_peer_nets */ + struct list_head lpn_peer_nets; /* list of peer_nis on this network */ struct list_head lpn_peer_nis; @@ -527,21 +537,45 @@ struct lnet_peer_net { /* Net ID */ __u32 lpn_net_id; + + /* reference count */ + atomic_t lpn_refcount; }; /* peer hash size */ #define LNET_PEER_HASH_BITS 9 #define LNET_PEER_HASH_SIZE (1 << LNET_PEER_HASH_BITS) -/* peer hash table */ +/* + * peer hash table - one per CPT + * + * protected by lnet_net_lock/EX for update + * pt_version + * pt_number + * pt_hash[...] + * pt_peer_list + * pt_peers + * pt_peer_nnids + * protected by pt_zombie_lock: + * pt_zombie_list + * pt_zombies + * + * pt_zombie lock nests inside lnet_net_lock + */ struct lnet_peer_table { /* /proc validity stamp */ int pt_version; /* # peers extant */ atomic_t pt_number; + /* peers */ + struct list_head pt_peer_list; + /* # peers */ + int pt_peers; + /* # NIDS on listed peers */ + int pt_peer_nnids; /* # zombies to go to deathrow (and not there yet) */ int pt_zombies; - /* zombie peers */ + /* zombie peers_ni */ struct list_head pt_zombie_list; /* protect list and count */ spinlock_t pt_zombie_lock; @@ -785,8 +819,6 @@ struct lnet { struct lnet_msg_container **ln_msg_containers; struct lnet_counters **ln_counters; struct lnet_peer_table **ln_peer_tables; - /* list of configured or discovered peers */ - struct list_head ln_peers; /* list of peer nis not on a local network */ struct list_head ln_remote_peer_ni_list; /* failure simulation */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index d64ae2939abc..c48bcb8722a0 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -625,7 +625,6 @@ lnet_prepare(lnet_pid_t requested_pid) the_lnet.ln_pid = requested_pid; INIT_LIST_HEAD(&the_lnet.ln_test_peers); - INIT_LIST_HEAD(&the_lnet.ln_peers); INIT_LIST_HEAD(&the_lnet.ln_remote_peer_ni_list); INIT_LIST_HEAD(&the_lnet.ln_nets); INIT_LIST_HEAD(&the_lnet.ln_routers); diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 99d8b22356bb..4c1eef907dc7 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -1388,7 +1388,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, peer_net = lnet_peer_get_net_locked( peer, LNET_NIDNET(best_lpni->lpni_nid)); list_for_each_entry(lpni, &peer_net->lpn_peer_nis, - lpni_on_peer_net_list) { + lpni_peer_nis) { if (lpni->lpni_pref_nnids == 0) continue; LASSERT(lpni->lpni_pref_nnids == 1); @@ -1411,7 +1411,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, } lpni = list_entry(peer_net->lpn_peer_nis.next, struct lnet_peer_ni, - lpni_on_peer_net_list); + lpni_peer_nis); } /* Set preferred NI if necessary. */ if (lpni->lpni_pref_nnids == 0) @@ -1443,7 +1443,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, * then the best route is chosen. If all routes are equal then * they are used in round robin. */ - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { if (!lnet_is_peer_net_healthy_locked(peer_net)) continue; @@ -1453,7 +1453,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, lpni = list_entry(peer_net->lpn_peer_nis.next, struct lnet_peer_ni, - lpni_on_peer_net_list); + lpni_peer_nis); net_gw = lnet_find_route_locked(NULL, lpni->lpni_nid, diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 09c1b5516f6b..d7a0a2f3bdd9 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -118,7 +118,7 @@ lnet_peer_ni_alloc(lnet_nid_t nid) INIT_LIST_HEAD(&lpni->lpni_rtrq); INIT_LIST_HEAD(&lpni->lpni_routes); INIT_LIST_HEAD(&lpni->lpni_hashlist); - INIT_LIST_HEAD(&lpni->lpni_on_peer_net_list); + INIT_LIST_HEAD(&lpni->lpni_peer_nis); INIT_LIST_HEAD(&lpni->lpni_on_remote_peer_ni_list); spin_lock_init(&lpni->lpni_lock); @@ -150,7 +150,7 @@ lnet_peer_ni_alloc(lnet_nid_t nid) &the_lnet.ln_remote_peer_ni_list); } - /* TODO: update flags */ + CDEBUG(D_NET, "%p nid %s\n", lpni, libcfs_nid2str(lpni->lpni_nid)); return lpni; } @@ -164,13 +164,32 @@ lnet_peer_net_alloc(u32 net_id) if (!lpn) return NULL; - INIT_LIST_HEAD(&lpn->lpn_on_peer_list); + INIT_LIST_HEAD(&lpn->lpn_peer_nets); INIT_LIST_HEAD(&lpn->lpn_peer_nis); lpn->lpn_net_id = net_id; + CDEBUG(D_NET, "%p net %s\n", lpn, libcfs_net2str(lpn->lpn_net_id)); + return lpn; } +void +lnet_destroy_peer_net_locked(struct lnet_peer_net *lpn) +{ + struct lnet_peer *lp; + + CDEBUG(D_NET, "%p net %s\n", lpn, libcfs_net2str(lpn->lpn_net_id)); + + LASSERT(atomic_read(&lpn->lpn_refcount) == 0); + LASSERT(list_empty(&lpn->lpn_peer_nis)); + LASSERT(list_empty(&lpn->lpn_peer_nets)); + lp = lpn->lpn_peer; + lpn->lpn_peer = NULL; + kfree(lpn); + + lnet_peer_decref_locked(lp); +} + static struct lnet_peer * lnet_peer_alloc(lnet_nid_t nid) { @@ -180,53 +199,73 @@ lnet_peer_alloc(lnet_nid_t nid) if (!lp) return NULL; - INIT_LIST_HEAD(&lp->lp_on_lnet_peer_list); + INIT_LIST_HEAD(&lp->lp_peer_list); INIT_LIST_HEAD(&lp->lp_peer_nets); spin_lock_init(&lp->lp_lock); lp->lp_primary_nid = nid; + lp->lp_cpt = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); - /* TODO: update flags */ + CDEBUG(D_NET, "%p nid %s\n", lp, libcfs_nid2str(lp->lp_primary_nid)); return lp; } +void +lnet_destroy_peer_locked(struct lnet_peer *lp) +{ + CDEBUG(D_NET, "%p nid %s\n", lp, libcfs_nid2str(lp->lp_primary_nid)); + + LASSERT(atomic_read(&lp->lp_refcount) == 0); + LASSERT(list_empty(&lp->lp_peer_nets)); + LASSERT(list_empty(&lp->lp_peer_list)); + + kfree(lp); +} + +/* + * Detach a peer_ni from its peer_net. If this was the last peer_ni on + * that peer_net, detach the peer_net from the peer. + * + * Call with lnet_net_lock/EX held + */ static void -lnet_peer_detach_peer_ni(struct lnet_peer_ni *lpni) +lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) { + struct lnet_peer_table *ptable; struct lnet_peer_net *lpn; struct lnet_peer *lp; - /* TODO: could the below situation happen? accessing an already - * destroyed peer? + /* + * Belts and suspenders: gracefully handle teardown of a + * partially connected peer_ni. */ - if (!lpni->lpni_peer_net || - !lpni->lpni_peer_net->lpn_peer) - return; - lpn = lpni->lpni_peer_net; - lp = lpni->lpni_peer_net->lpn_peer; - CDEBUG(D_NET, "peer %s NID %s\n", - libcfs_nid2str(lp->lp_primary_nid), - libcfs_nid2str(lpni->lpni_nid)); - - list_del_init(&lpni->lpni_on_peer_net_list); - lpni->lpni_peer_net = NULL; + list_del_init(&lpni->lpni_peer_nis); + /* + * If there are no lpni's left, we detach lpn from + * lp_peer_nets, so it cannot be found anymore. + */ + if (list_empty(&lpn->lpn_peer_nis)) + list_del_init(&lpn->lpn_peer_nets); - /* if lpn is empty, then remove it from the peer */ - if (list_empty(&lpn->lpn_peer_nis)) { - list_del_init(&lpn->lpn_on_peer_list); - lpn->lpn_peer = NULL; - kfree(lpn); + /* Update peer NID count. */ + lp = lpn->lpn_peer; + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; + lp->lp_nnis--; + ptable->pt_peer_nnids--; - /* If the peer is empty then remove it from the - * the_lnet.ln_peers. - */ - if (list_empty(&lp->lp_peer_nets)) { - list_del_init(&lp->lp_on_lnet_peer_list); - kfree(lp); - } + /* + * If there are no more peer nets, make the peer unfindable + * via the peer_tables. + */ + if (list_empty(&lp->lp_peer_nets)) { + list_del_init(&lp->lp_peer_list); + ptable->pt_peers--; } + CDEBUG(D_NET, "peer %s NID %s\n", + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(lpni->lpni_nid)); } /* called with lnet_net_lock LNET_LOCK_EX held */ @@ -268,9 +307,9 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) spin_unlock(&ptable->pt_zombie_lock); /* no need to keep this peer_ni on the hierarchy anymore */ - lnet_peer_detach_peer_ni(lpni); + lnet_peer_detach_peer_ni_locked(lpni); - /* decrement reference on peer_ni */ + /* remove hashlist reference on peer_ni */ lnet_peer_ni_decref_locked(lpni); return 0; @@ -319,6 +358,8 @@ lnet_peer_tables_create(void) spin_lock_init(&ptable->pt_zombie_lock); INIT_LIST_HEAD(&ptable->pt_zombie_list); + INIT_LIST_HEAD(&ptable->pt_peer_list); + for (j = 0; j < LNET_PEER_HASH_SIZE; j++) INIT_LIST_HEAD(&hash[j]); ptable->pt_hash = hash; /* sign of initialization */ @@ -394,7 +435,7 @@ lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) * This function only allows deletion of the primary NID if it * is the only NID. */ - if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { + if (nid == lp->lp_primary_nid && lp->lp_nnis != 1) { rc = -EBUSY; goto out; } @@ -560,15 +601,34 @@ struct lnet_peer_ni * lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, struct lnet_peer **lp) { + struct lnet_peer_table *ptable; struct lnet_peer_ni *lpni; + int lncpt; + int cpt; + + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); - list_for_each_entry((*lp), &the_lnet.ln_peers, lp_on_lnet_peer_list) { + for (cpt = 0; cpt < lncpt; cpt++) { + ptable = the_lnet.ln_peer_tables[cpt]; + if (ptable->pt_peer_nnids > idx) + break; + idx -= ptable->pt_peer_nnids; + } + if (cpt >= lncpt) + return NULL; + + list_for_each_entry((*lp), &ptable->pt_peer_list, lp_peer_list) { + if ((*lp)->lp_nnis <= idx) { + idx -= (*lp)->lp_nnis; + continue; + } list_for_each_entry((*lpn), &((*lp)->lp_peer_nets), - lpn_on_peer_list) { + lpn_peer_nets) { list_for_each_entry(lpni, &((*lpn)->lpn_peer_nis), - lpni_on_peer_net_list) + lpni_peer_nis) { if (idx-- == 0) return lpni; + } } } @@ -584,18 +644,21 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, struct lnet_peer_net *net = peer_net; if (!prev) { - if (!net) + if (!net) { + if (list_empty(&peer->lp_peer_nets)) + return NULL; + net = list_entry(peer->lp_peer_nets.next, struct lnet_peer_net, - lpn_on_peer_list); + lpn_peer_nets); + } lpni = list_entry(net->lpn_peer_nis.next, struct lnet_peer_ni, - lpni_on_peer_net_list); + lpni_peer_nis); return lpni; } - if (prev->lpni_on_peer_net_list.next == - &prev->lpni_peer_net->lpn_peer_nis) { + if (prev->lpni_peer_nis.next == &prev->lpni_peer_net->lpn_peer_nis) { /* * if you reached the end of the peer ni list and the peer * net is specified then there are no more peer nis in that @@ -608,25 +671,25 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, * we reached the end of this net ni list. move to the * next net */ - if (prev->lpni_peer_net->lpn_on_peer_list.next == + if (prev->lpni_peer_net->lpn_peer_nets.next == &peer->lp_peer_nets) /* no more nets and no more NIs. */ return NULL; /* get the next net */ - net = list_entry(prev->lpni_peer_net->lpn_on_peer_list.next, + net = list_entry(prev->lpni_peer_net->lpn_peer_nets.next, struct lnet_peer_net, - lpn_on_peer_list); + lpn_peer_nets); /* get the ni on it */ lpni = list_entry(net->lpn_peer_nis.next, struct lnet_peer_ni, - lpni_on_peer_net_list); + lpni_peer_nis); return lpni; } /* there are more nis left */ - lpni = list_entry(prev->lpni_on_peer_net_list.next, - struct lnet_peer_ni, lpni_on_peer_net_list); + lpni = list_entry(prev->lpni_peer_nis.next, + struct lnet_peer_ni, lpni_peer_nis); return lpni; } @@ -902,7 +965,7 @@ struct lnet_peer_net * lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) { struct lnet_peer_net *peer_net; - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { if (peer_net->lpn_net_id == net_id) return peer_net; } @@ -910,15 +973,20 @@ lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) } /* - * Always returns 0, but it the last function called from functions + * Attach a peer_ni to a peer_net and peer. This function assumes + * peer_ni is not already attached to the peer_net/peer. The peer_ni + * may be attached to a different peer, in which case it will be + * properly detached first. The whole operation is done atomically. + * + * Always returns 0. This is the last function called from functions * that do return an int, so returning 0 here allows the compiler to * do a tail call. */ static int lnet_peer_attach_peer_ni(struct lnet_peer *lp, - struct lnet_peer_net *lpn, - struct lnet_peer_ni *lpni, - unsigned int flags) + struct lnet_peer_net *lpn, + struct lnet_peer_ni *lpni, + unsigned int flags) { struct lnet_peer_table *ptable; @@ -932,26 +1000,38 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, list_add_tail(&lpni->lpni_hashlist, &ptable->pt_hash[hash]); ptable->pt_version++; atomic_inc(&ptable->pt_number); + /* This is the 1st refcount on lpni. */ atomic_inc(&lpni->lpni_refcount); } /* Detach the peer_ni from an existing peer, if necessary. */ - if (lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer != lp) - lnet_peer_detach_peer_ni(lpni); + if (lpni->lpni_peer_net) { + LASSERT(lpni->lpni_peer_net != lpn); + LASSERT(lpni->lpni_peer_net->lpn_peer != lp); + lnet_peer_detach_peer_ni_locked(lpni); + lnet_peer_net_decref_locked(lpni->lpni_peer_net); + lpni->lpni_peer_net = NULL; + } /* Add peer_ni to peer_net */ lpni->lpni_peer_net = lpn; - list_add_tail(&lpni->lpni_on_peer_net_list, &lpn->lpn_peer_nis); + list_add_tail(&lpni->lpni_peer_nis, &lpn->lpn_peer_nis); + lnet_peer_net_addref_locked(lpn); /* Add peer_net to peer */ if (!lpn->lpn_peer) { lpn->lpn_peer = lp; - list_add_tail(&lpn->lpn_on_peer_list, &lp->lp_peer_nets); + list_add_tail(&lpn->lpn_peer_nets, &lp->lp_peer_nets); + lnet_peer_addref_locked(lp); + } + + /* Add peer to global peer list, if necessary */ + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; + if (list_empty(&lp->lp_peer_list)) { + list_add_tail(&lp->lp_peer_list, &ptable->pt_peer_list); + ptable->pt_peers++; } - /* Add peer to global peer list */ - if (list_empty(&lp->lp_on_lnet_peer_list)) - list_add_tail(&lp->lp_on_lnet_peer_list, &the_lnet.ln_peers); /* Update peer state */ spin_lock(&lp->lp_lock); @@ -967,6 +1047,8 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, } spin_unlock(&lp->lp_lock); + lp->lp_nnis++; + the_lnet.ln_peer_tables[lp->lp_cpt]->pt_peer_nnids++; lnet_net_unlock(LNET_LOCK_EX); CDEBUG(D_NET, "peer %s NID %s flags %#x\n", @@ -1314,12 +1396,17 @@ void lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) { struct lnet_peer_table *ptable; + struct lnet_peer_net *lpn; + + CDEBUG(D_NET, "%p nid %s\n", lpni, libcfs_nid2str(lpni->lpni_nid)); LASSERT(atomic_read(&lpni->lpni_refcount) == 0); LASSERT(lpni->lpni_rtr_refcount == 0); LASSERT(list_empty(&lpni->lpni_txq)); LASSERT(lpni->lpni_txqnob == 0); + lpn = lpni->lpni_peer_net; + lpni->lpni_peer_net = NULL; lpni->lpni_net = NULL; /* remove the peer ni from the zombie list */ @@ -1332,6 +1419,8 @@ lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) if (lpni->lpni_pref_nnids > 1) kfree(lpni->lpni_pref.nids); kfree(lpni); + + lnet_peer_net_decref_locked(lpn); } struct lnet_peer_ni * @@ -1518,6 +1607,7 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, return found ? 0 : -ENOENT; } +/* ln_api_mutex is held, which keeps the peer list stable */ int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, bool *mr, struct lnet_peer_ni_credit_info __user *peer_ni_info, From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 15/24] lustre: lnet: add msg_type to lnet_event In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437812.16383.7373974293282162856.stgit@noble> From: Olaf Weber Add a msg_type field to the lnet_event structure. This makes it possible for an event handler to tell whether LNET_EVENT_SEND corresponds to a GET or a PUT message. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25785 Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../lustre/include/uapi/linux/lnet/lnet-types.h | 5 +++++ drivers/staging/lustre/lnet/lnet/lib-msg.c | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h index e0e4fd259795..1ecf18e4a278 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h @@ -650,6 +650,11 @@ struct lnet_event { * \see LNetPut */ __u64 hdr_data; + /** + * The message type, to ensure a handler for LNET_EVENT_SEND can + * distinguish between LNET_MSG_GET and LNET_MSG_PUT. + */ + __u32 msg_type; /** * Indicates the completion status of the operation. It's 0 for * successful operations, otherwise it's an error code. diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c index 1817e54a16a5..db13d01d366f 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c @@ -63,6 +63,7 @@ lnet_build_msg_event(struct lnet_msg *msg, enum lnet_event_kind ev_type) LASSERT(!msg->msg_routing); ev->type = ev_type; + ev->msg_type = msg->msg_type; if (ev_type == LNET_EVENT_SEND) { /* event for active message */ From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 16/24] lustre: lnet: add discovery thread In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437816.16383.10343171262123774566.stgit@noble> From: Olaf Weber Add the discovery thread, which will be used to handle peer discovery. This change adds the thread and the infrastructure that starts and stops it. The thread itself does trivial work. Peer Discovery gets its own event queue (ln_dc_eqh), a queue for peers that are to be discovered (ln_dc_request), a queue for peers waiting for an event (ln_dc_working), a wait queue head so the thread can sleep (ln_dc_waitq), and start/stop state (ln_dc_state). Peer discovery is started from lnet_select_pathway(), for GET and PUT messages not sent to the LNET_RESERVED_PORTAL. This criterion means that discovery will not be triggered by the messages used in discovery, and neither will an LNet ping trigger it. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Signed-off-by: Amir Shehata Reviewed-on: https://review.whamcloud.com/25786 Reviewed-by: Olaf Weber Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 6 .../staging/lustre/include/linux/lnet/lib-types.h | 71 ++++ drivers/staging/lustre/lnet/lnet/api-ni.c | 31 ++ drivers/staging/lustre/lnet/lnet/lib-move.c | 45 ++- drivers/staging/lustre/lnet/lnet/peer.c | 325 ++++++++++++++++++++ 5 files changed, 468 insertions(+), 10 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index aad25eb0011b..848d622911a4 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -438,6 +438,7 @@ bool lnet_is_ni_healthy_locked(struct lnet_ni *ni); struct lnet_net *lnet_get_net_locked(u32 net_id); extern unsigned int lnet_numa_range; +extern unsigned int lnet_peer_discovery_disabled; extern int portal_rotor; int lnet_lib_init(void); @@ -704,6 +705,9 @@ struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); void lnet_peer_net_added(struct lnet_net *net); lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); +int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt); +int lnet_peer_discovery_start(void); +void lnet_peer_discovery_stop(void); void lnet_peer_tables_cleanup(struct lnet_net *net); void lnet_peer_uninit(void); int lnet_peer_tables_create(void); @@ -791,4 +795,6 @@ lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) return lpni->lpni_nid == lpni->lpni_peer_net->lpn_peer->lp_primary_nid; } +bool lnet_peer_is_uptodate(struct lnet_peer *lp); + #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 260619e19bde..6394a3af50b7 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -520,10 +520,61 @@ struct lnet_peer { /* peer state flags */ unsigned int lp_state; + + /* link on discovery-related lists */ + struct list_head lp_dc_list; + + /* tasks waiting on discovery of this peer */ + wait_queue_head_t lp_dc_waitq; }; -#define LNET_PEER_MULTI_RAIL BIT(0) -#define LNET_PEER_CONFIGURED BIT(1) +/* + * The status flags in lp_state. Their semantics have chosen so that + * lp_state can be zero-initialized. + * + * A peer is marked MULTI_RAIL in two cases: it was configured using DLC + * as multi-rail aware, or the LNET_PING_FEAT_MULTI_RAIL bit was set. + * + * A peer is marked NO_DISCOVERY if the LNET_PING_FEAT_DISCOVERY bit was + * NOT set when the peer was pinged by discovery. + */ +#define LNET_PEER_MULTI_RAIL BIT(0) /* Multi-rail aware */ +#define LNET_PEER_NO_DISCOVERY BIT(1) /* Peer disabled discovery */ +/* + * A peer is marked CONFIGURED if it was configured by DLC. + * + * In addition, a peer is marked DISCOVERED if it has fully passed + * through Peer Discovery. + * + * When Peer Discovery is disabled, the discovery thread will mark + * peers REDISCOVER to indicate that they should be re-examined if + * discovery is (re)enabled on the node. + * + * A peer that was created as the result of inbound traffic will not + * be marked at all. + */ +#define LNET_PEER_CONFIGURED BIT(2) /* Configured via DLC */ +#define LNET_PEER_DISCOVERED BIT(3) /* Peer was discovered */ +#define LNET_PEER_REDISCOVER BIT(4) /* Discovery was disabled */ +/* + * A peer is marked DISCOVERING when discovery is in progress. + * The other flags below correspond to stages of discovery. + */ +#define LNET_PEER_DISCOVERING BIT(5) /* Discovering */ +#define LNET_PEER_DATA_PRESENT BIT(6) /* Remote peer data present */ +#define LNET_PEER_NIDS_UPTODATE BIT(7) /* Remote peer info uptodate */ +#define LNET_PEER_PING_SENT BIT(8) /* Waiting for REPLY to Ping */ +#define LNET_PEER_PUSH_SENT BIT(9) /* Waiting for ACK of Push */ +#define LNET_PEER_PING_FAILED BIT(10) /* Ping send failure */ +#define LNET_PEER_PUSH_FAILED BIT(11) /* Push send failure */ +/* + * A ping can be forced as a way to fix up state, or as a manual + * intervention by an admin. + * A push can be forced in circumstances that would normally not + * allow for one to happen. + */ +#define LNET_PEER_FORCE_PING BIT(12) /* Forced Ping */ +#define LNET_PEER_FORCE_PUSH BIT(13) /* Forced Push */ struct lnet_peer_net { /* chain on lp_peer_nets */ @@ -775,6 +826,11 @@ struct lnet_msg_container { void **msc_finalizers; }; +/* Peer Discovery states */ +#define LNET_DC_STATE_SHUTDOWN 0 /* not started */ +#define LNET_DC_STATE_RUNNING 1 /* started up OK */ +#define LNET_DC_STATE_STOPPING 2 /* telling thread to stop */ + /* Router Checker states */ enum lnet_rc_state { LNET_RC_STATE_SHUTDOWN, /* not started */ @@ -856,6 +912,17 @@ struct lnet { struct lnet_ping_buffer *ln_ping_target; atomic_t ln_ping_target_seqno; + /* discovery event queue handle */ + struct lnet_handle_eq ln_dc_eqh; + /* discovery requests */ + struct list_head ln_dc_request; + /* discovery working list */ + struct list_head ln_dc_working; + /* discovery thread wait queue */ + wait_queue_head_t ln_dc_waitq; + /* discovery startup/shutdown state */ + int ln_dc_state; + /* router checker startup/shutdown state */ enum lnet_rc_state ln_rc_state; /* router checker's event queue */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index c48bcb8722a0..dccfd5bcc459 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -78,6 +78,13 @@ module_param_call(lnet_interfaces_max, intf_max_set, param_get_int, MODULE_PARM_DESC(lnet_interfaces_max, "Maximum number of interfaces in a node."); +unsigned int lnet_peer_discovery_disabled; +static int discovery_set(const char *val, const struct kernel_param *kp); +module_param_call(lnet_peer_discovery_disabled, discovery_set, param_get_int, + &lnet_peer_discovery_disabled, 0644); +MODULE_PARM_DESC(lnet_peer_discovery_disabled, + "Set to 1 to disable peer discovery on this node."); + /* * This sequence number keeps track of how many times DLC was used to * update the local NIs. It is incremented when a NI is added or @@ -90,6 +97,23 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); static int lnet_ping(struct lnet_process_id id, signed long timeout, struct lnet_process_id __user *ids, int n_ids); +static int +discovery_set(const char *val, const struct kernel_param *kp) +{ + int rc; + unsigned long value; + + rc = kstrtoul(val, 0, &value); + if (rc) { + CERROR("Invalid module parameter value for 'lnet_peer_discovery_disabled'\n"); + return rc; + } + + *(unsigned int *)kp->arg = !!value; + + return 0; +} + static int intf_max_set(const char *val, const struct kernel_param *kp) { @@ -1921,6 +1945,10 @@ LNetNIInit(lnet_pid_t requested_pid) if (rc) goto err_stop_ping; + rc = lnet_peer_discovery_start(); + if (rc != 0) + goto err_stop_router_checker; + lnet_fault_init(); lnet_router_debugfs_init(); @@ -1928,6 +1956,8 @@ LNetNIInit(lnet_pid_t requested_pid) return 0; +err_stop_router_checker: + lnet_router_checker_stop(); err_stop_ping: lnet_ping_target_fini(); err_acceptor_stop: @@ -1976,6 +2006,7 @@ LNetNIFini(void) lnet_fault_fini(); lnet_router_debugfs_fini(); + lnet_peer_discovery_stop(); lnet_router_checker_stop(); lnet_ping_target_fini(); diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 4c1eef907dc7..4773180cc7b3 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -1208,6 +1208,27 @@ lnet_get_best_ni(struct lnet_net *local_net, struct lnet_ni *cur_ni, return best_ni; } +/* + * Traffic to the LNET_RESERVED_PORTAL may not trigger peer discovery, + * because such traffic is required to perform discovery. We therefore + * exclude all GET and PUT on that portal. We also exclude all ACK and + * REPLY traffic, but that is because the portal is not tracked in the + * message structure for these message types. We could restrict this + * further by also checking for LNET_PROTO_PING_MATCHBITS. + */ +static bool +lnet_msg_discovery(struct lnet_msg *msg) +{ + if (msg->msg_type == LNET_MSG_PUT) { + if (msg->msg_hdr.msg.put.ptl_index != LNET_RESERVED_PORTAL) + return true; + } else if (msg->msg_type == LNET_MSG_GET) { + if (msg->msg_hdr.msg.get.ptl_index != LNET_RESERVED_PORTAL) + return true; + } + return false; +} + static int lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid) @@ -1220,7 +1241,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, struct lnet_peer *peer; struct lnet_peer_net *peer_net; struct lnet_net *local_net; - __u32 seq; int cpt, cpt2, rc; bool routing; bool routing2; @@ -1255,13 +1275,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, routing2 = false; local_found = false; - seq = lnet_get_dlc_seq_locked(); - - if (the_lnet.ln_state != LNET_STATE_RUNNING) { - lnet_net_unlock(cpt); - return -ESHUTDOWN; - } - /* * lnet_nid2peerni_locked() is the path that will find an * existing peer_ni, or create one and mark it as having been @@ -1272,7 +1285,22 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, lnet_net_unlock(cpt); return PTR_ERR(lpni); } + /* + * Now that we have a peer_ni, check if we want to discover + * the peer. Traffic to the LNET_RESERVED_PORTAL should not + * trigger discovery. + */ peer = lpni->lpni_peer_net->lpn_peer; + if (lnet_msg_discovery(msg) && !lnet_peer_is_uptodate(peer)) { + rc = lnet_discover_peer_locked(lpni, cpt); + if (rc) { + lnet_peer_ni_decref_locked(lpni); + lnet_net_unlock(cpt); + return rc; + } + /* The peer may have changed. */ + peer = lpni->lpni_peer_net->lpn_peer; + } lnet_peer_ni_decref_locked(lpni); /* If peer is not healthy then can not send anything to it */ @@ -1701,6 +1729,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, */ cpt2 = lnet_cpt_of_nid_locked(best_lpni->lpni_nid, best_ni); if (cpt != cpt2) { + __u32 seq = lnet_get_dlc_seq_locked(); lnet_net_unlock(cpt); cpt = cpt2; lnet_net_lock(cpt); diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index d7a0a2f3bdd9..038b58414ce0 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -201,6 +201,8 @@ lnet_peer_alloc(lnet_nid_t nid) INIT_LIST_HEAD(&lp->lp_peer_list); INIT_LIST_HEAD(&lp->lp_peer_nets); + INIT_LIST_HEAD(&lp->lp_dc_list); + init_waitqueue_head(&lp->lp_dc_waitq); spin_lock_init(&lp->lp_lock); lp->lp_primary_nid = nid; lp->lp_cpt = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); @@ -1457,6 +1459,10 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) return lpni; } +/* + * Get a peer_ni for the given nid, create it if necessary. Takes a + * hold on the peer_ni. + */ struct lnet_peer_ni * lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) { @@ -1510,9 +1516,326 @@ lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) mutex_unlock(&the_lnet.ln_api_mutex); lnet_net_lock(cpt); + /* Lock has been dropped, check again for shutdown. */ + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { + if (!IS_ERR(lpni)) + lnet_peer_ni_decref_locked(lpni); + lpni = ERR_PTR(-ESHUTDOWN); + } + return lpni; } +/* + * Peer Discovery + */ + +/* + * Is a peer uptodate from the point of view of discovery? + * + * If it is currently being processed, obviously not. + * A forced Ping or Push is also handled by the discovery thread. + * + * Otherwise look at whether the peer needs rediscovering. + */ +bool +lnet_peer_is_uptodate(struct lnet_peer *lp) +{ + bool rc; + + spin_lock(&lp->lp_lock); + if (lp->lp_state & (LNET_PEER_DISCOVERING | + LNET_PEER_FORCE_PING | + LNET_PEER_FORCE_PUSH)) { + rc = false; + } else if (lp->lp_state & LNET_PEER_REDISCOVER) { + if (lnet_peer_discovery_disabled) + rc = true; + else + rc = false; + } else if (lp->lp_state & LNET_PEER_DISCOVERED) { + if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) + rc = true; + else + rc = false; + } else { + rc = false; + } + spin_unlock(&lp->lp_lock); + + return rc; +} + +/* + * Queue a peer for the attention of the discovery thread. Call with + * lnet_net_lock/EX held. Returns 0 if the peer was queued, and + * -EALREADY if the peer was already queued. + */ +static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) +{ + int rc; + + spin_lock(&lp->lp_lock); + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) + lp->lp_state |= LNET_PEER_DISCOVERING; + spin_unlock(&lp->lp_lock); + if (list_empty(&lp->lp_dc_list)) { + lnet_peer_addref_locked(lp); + list_add_tail(&lp->lp_dc_list, &the_lnet.ln_dc_request); + wake_up(&the_lnet.ln_dc_waitq); + rc = 0; + } else { + rc = -EALREADY; + } + + return rc; +} + +/* + * Discovery of a peer is complete. Wake all waiters on the peer. + * Call with lnet_net_lock/EX held. + */ +static void lnet_peer_discovery_complete(struct lnet_peer *lp) +{ + list_del_init(&lp->lp_dc_list); + wake_up_all(&lp->lp_dc_waitq); + lnet_peer_decref_locked(lp); +} + +/* + * Peer discovery slow path. The ln_api_mutex is held on entry, and + * dropped/retaken within this function. An lnet_peer_ni is passed in + * because discovery could tear down an lnet_peer. + */ +int +lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) +{ + DEFINE_WAIT(wait); + struct lnet_peer *lp; + int rc = 0; + +again: + lnet_net_unlock(cpt); + lnet_net_lock(LNET_LOCK_EX); + + /* We're willing to be interrupted. */ + for (;;) { + lp = lpni->lpni_peer_net->lpn_peer; + prepare_to_wait(&lp->lp_dc_waitq, &wait, TASK_INTERRUPTIBLE); + if (signal_pending(current)) + break; + if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) + break; + if (lnet_peer_is_uptodate(lp)) + break; + lnet_peer_queue_for_discovery(lp); + lnet_peer_addref_locked(lp); + lnet_net_unlock(LNET_LOCK_EX); + schedule(); + finish_wait(&lp->lp_dc_waitq, &wait); + lnet_net_lock(LNET_LOCK_EX); + lnet_peer_decref_locked(lp); + /* Do not use lp beyond this point. */ + } + finish_wait(&lp->lp_dc_waitq, &wait); + + lnet_net_unlock(LNET_LOCK_EX); + lnet_net_lock(cpt); + + if (signal_pending(current)) + rc = -EINTR; + else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) + rc = -ESHUTDOWN; + else if (!lnet_peer_is_uptodate(lp)) + goto again; + + return rc; +} + +/* + * Event handler for the discovery EQ. + * + * Called with lnet_res_lock(cpt) held. The cpt is the + * lnet_cpt_of_cookie() of the md handle cookie. + */ +static void lnet_discovery_event_handler(struct lnet_event *event) +{ + wake_up(&the_lnet.ln_dc_waitq); +} + +/* + * Wait for work to be queued or some other change that must be + * attended to. Returns non-zero if the discovery thread should shut + * down. + */ +static int lnet_peer_discovery_wait_for_work(void) +{ + int cpt; + int rc = 0; + + DEFINE_WAIT(wait); + + cpt = lnet_net_lock_current(); + for (;;) { + prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, + TASK_IDLE); + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + break; + if (!list_empty(&the_lnet.ln_dc_request)) + break; + lnet_net_unlock(cpt); + schedule(); + finish_wait(&the_lnet.ln_dc_waitq, &wait); + cpt = lnet_net_lock_current(); + } + finish_wait(&the_lnet.ln_dc_waitq, &wait); + + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + rc = -ESHUTDOWN; + + lnet_net_unlock(cpt); + + CDEBUG(D_NET, "woken: %d\n", rc); + + return rc; +} + +/* The discovery thread. */ +static int lnet_peer_discovery(void *arg) +{ + struct lnet_peer *lp; + + CDEBUG(D_NET, "started\n"); + + for (;;) { + if (lnet_peer_discovery_wait_for_work()) + break; + + lnet_net_lock(LNET_LOCK_EX); + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + break; + while (!list_empty(&the_lnet.ln_dc_request)) { + lp = list_first_entry(&the_lnet.ln_dc_request, + struct lnet_peer, lp_dc_list); + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_working); + lnet_net_unlock(LNET_LOCK_EX); + + /* Just tag and release for now. */ + spin_lock(&lp->lp_lock); + if (lnet_peer_discovery_disabled) { + lp->lp_state |= LNET_PEER_REDISCOVER; + lp->lp_state &= ~(LNET_PEER_DISCOVERED | + LNET_PEER_NIDS_UPTODATE | + LNET_PEER_DISCOVERING); + } else { + lp->lp_state |= (LNET_PEER_DISCOVERED | + LNET_PEER_NIDS_UPTODATE); + lp->lp_state &= ~(LNET_PEER_REDISCOVER | + LNET_PEER_DISCOVERING); + } + spin_unlock(&lp->lp_lock); + + lnet_net_lock(LNET_LOCK_EX); + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) + lnet_peer_discovery_complete(lp); + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + break; + } + lnet_net_unlock(LNET_LOCK_EX); + } + + CDEBUG(D_NET, "stopping\n"); + /* + * Clean up before telling lnet_peer_discovery_stop() that + * we're done. Use wake_up() below to somewhat reduce the + * size of the thundering herd if there are multiple threads + * waiting on discovery of a single peer. + */ + LNetEQFree(the_lnet.ln_dc_eqh); + LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); + + lnet_net_lock(LNET_LOCK_EX); + list_for_each_entry(lp, &the_lnet.ln_dc_request, lp_dc_list) { + spin_lock(&lp->lp_lock); + lp->lp_state |= LNET_PEER_REDISCOVER; + lp->lp_state &= ~(LNET_PEER_DISCOVERED | + LNET_PEER_DISCOVERING | + LNET_PEER_NIDS_UPTODATE); + spin_unlock(&lp->lp_lock); + lnet_peer_discovery_complete(lp); + } + list_for_each_entry(lp, &the_lnet.ln_dc_working, lp_dc_list) { + spin_lock(&lp->lp_lock); + lp->lp_state |= LNET_PEER_REDISCOVER; + lp->lp_state &= ~(LNET_PEER_DISCOVERED | + LNET_PEER_DISCOVERING | + LNET_PEER_NIDS_UPTODATE); + spin_unlock(&lp->lp_lock); + lnet_peer_discovery_complete(lp); + } + lnet_net_unlock(LNET_LOCK_EX); + + the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; + wake_up(&the_lnet.ln_dc_waitq); + + CDEBUG(D_NET, "stopped\n"); + + return 0; +} + +/* ln_api_mutex is held on entry. */ +int lnet_peer_discovery_start(void) +{ + struct task_struct *task; + int rc; + + if (the_lnet.ln_dc_state != LNET_DC_STATE_SHUTDOWN) + return -EALREADY; + + INIT_LIST_HEAD(&the_lnet.ln_dc_request); + INIT_LIST_HEAD(&the_lnet.ln_dc_working); + init_waitqueue_head(&the_lnet.ln_dc_waitq); + + rc = LNetEQAlloc(0, lnet_discovery_event_handler, &the_lnet.ln_dc_eqh); + if (rc != 0) { + CERROR("Can't allocate discovery EQ: %d\n", rc); + return rc; + } + + the_lnet.ln_dc_state = LNET_DC_STATE_RUNNING; + task = kthread_run(lnet_peer_discovery, NULL, "lnet_discovery"); + if (IS_ERR(task)) { + rc = PTR_ERR(task); + CERROR("Can't start peer discovery thread: %d\n", rc); + + LNetEQFree(the_lnet.ln_dc_eqh); + LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); + + the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; + } + + return rc; +} + +/* ln_api_mutex is held on entry. */ +void lnet_peer_discovery_stop(void) +{ + if (the_lnet.ln_dc_state == LNET_DC_STATE_SHUTDOWN) + return; + + LASSERT(the_lnet.ln_dc_state == LNET_DC_STATE_RUNNING); + the_lnet.ln_dc_state = LNET_DC_STATE_STOPPING; + wake_up(&the_lnet.ln_dc_waitq); + + wait_event(the_lnet.ln_dc_waitq, + the_lnet.ln_dc_state == LNET_DC_STATE_SHUTDOWN); + + LASSERT(list_empty(&the_lnet.ln_dc_request)); + LASSERT(list_empty(&the_lnet.ln_dc_working)); +} + +/* Debugging */ + void lnet_debug_peer(lnet_nid_t nid) { @@ -1544,6 +1867,8 @@ lnet_debug_peer(lnet_nid_t nid) lnet_net_unlock(cpt); } +/* Gathering information for userspace. */ + int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, char aliveness[LNET_MAX_STR_LEN], From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 17/24] lustre: lnet: add the Push target In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437820.16383.6069246179655761617.stgit@noble> From: Olaf Weber Peer Discovery will send a Push message (same format as an LNet Ping) to Multi-Rail capable peers to give the peer the list of local interfaces. Set up a target buffer for these pushes in the_lnet. The size of this buffer defaults to LNET_MIN_INTERFACES, but it is resized if required. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25788 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 8 + .../staging/lustre/include/linux/lnet/lib-types.h | 25 +++ drivers/staging/lustre/lnet/lnet/api-ni.c | 150 ++++++++++++++++++++ drivers/staging/lustre/lnet/lnet/peer.c | 5 + 4 files changed, 187 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 848d622911a4..5632e5aadf41 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -686,6 +686,14 @@ static inline int lnet_ping_buffer_numref(struct lnet_ping_buffer *pbuf) return atomic_read(&pbuf->pb_refcnt); } +static inline int lnet_push_target_resize_needed(void) +{ + return the_lnet.ln_push_target->pb_nnis < the_lnet.ln_push_target_nnis; +} + +int lnet_push_target_resize(void); +void lnet_peer_push_event(struct lnet_event *ev); + int lnet_parse_ip2nets(char **networksp, char *ip2nets); int lnet_parse_routes(char *route_str, int *im_a_router); int lnet_parse_networks(struct list_head *nilist, char *networks, diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 6394a3af50b7..e00c13355d43 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -521,6 +521,18 @@ struct lnet_peer { /* peer state flags */ unsigned int lp_state; + /* buffer for data pushed by peer */ + struct lnet_ping_buffer *lp_data; + + /* number of NIDs for sizing push data */ + int lp_data_nnis; + + /* NI config sequence number of peer */ + __u32 lp_peer_seqno; + + /* Local NI config sequence number peer knows */ + __u32 lp_node_seqno; + /* link on discovery-related lists */ struct list_head lp_dc_list; @@ -912,6 +924,19 @@ struct lnet { struct lnet_ping_buffer *ln_ping_target; atomic_t ln_ping_target_seqno; + /* + * Push Target + * + * ln_push_nnis contains the desired size of the push target. + * The lnet_net_lock is used to handle update races. The old + * buffer may linger a while after it has been unlinked, in + * which case the event handler cleans up. + */ + struct lnet_handle_eq ln_push_target_eq; + struct lnet_handle_md ln_push_target_md; + struct lnet_ping_buffer *ln_push_target; + int ln_push_target_nnis; + /* discovery event queue handle */ struct lnet_handle_eq ln_dc_eqh; /* discovery requests */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index dccfd5bcc459..e6bc54e9de71 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -1268,6 +1268,147 @@ lnet_ping_target_fini(void) lnet_ping_target_destroy(); } +/* Resize the push target. */ +int lnet_push_target_resize(void) +{ + struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY }; + struct lnet_md md = { NULL }; + struct lnet_handle_me meh; + struct lnet_handle_md mdh; + struct lnet_handle_md old_mdh; + struct lnet_ping_buffer *pbuf; + struct lnet_ping_buffer *old_pbuf; + int nnis = the_lnet.ln_push_target_nnis; + int rc; + + if (nnis <= 0) { + rc = -EINVAL; + goto fail_return; + } +again: + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); + if (!pbuf) { + rc = -ENOMEM; + goto fail_return; + } + + rc = LNetMEAttach(LNET_RESERVED_PORTAL, id, + LNET_PROTO_PING_MATCHBITS, 0, + LNET_UNLINK, LNET_INS_AFTER, + &meh); + if (rc) { + CERROR("Can't create push target ME: %d\n", rc); + goto fail_decref_pbuf; + } + + /* initialize md content */ + md.start = &pbuf->pb_info; + md.length = LNET_PING_INFO_SIZE(nnis); + md.threshold = LNET_MD_THRESH_INF; + md.max_size = 0; + md.options = LNET_MD_OP_PUT | LNET_MD_TRUNCATE | + LNET_MD_MANAGE_REMOTE; + md.user_ptr = pbuf; + md.eq_handle = the_lnet.ln_push_target_eq; + + rc = LNetMDAttach(meh, md, LNET_RETAIN, &mdh); + if (rc) { + CERROR("Can't attach push MD: %d\n", rc); + goto fail_unlink_meh; + } + lnet_ping_buffer_addref(pbuf); + + lnet_net_lock(LNET_LOCK_EX); + old_pbuf = the_lnet.ln_push_target; + old_mdh = the_lnet.ln_push_target_md; + the_lnet.ln_push_target = pbuf; + the_lnet.ln_push_target_md = mdh; + lnet_net_unlock(LNET_LOCK_EX); + + if (old_pbuf) { + LNetMDUnlink(old_mdh); + lnet_ping_buffer_decref(old_pbuf); + } + + if (nnis < the_lnet.ln_push_target_nnis) + goto again; + + CDEBUG(D_NET, "nnis %d success\n", nnis); + + return 0; + +fail_unlink_meh: + LNetMEUnlink(meh); +fail_decref_pbuf: + lnet_ping_buffer_decref(pbuf); +fail_return: + CDEBUG(D_NET, "nnis %d error %d\n", nnis, rc); + return rc; +} + +static void lnet_push_target_event_handler(struct lnet_event *ev) +{ + struct lnet_ping_buffer *pbuf = ev->md.user_ptr; + + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) + lnet_swap_pinginfo(pbuf); + + if (ev->unlinked) + lnet_ping_buffer_decref(pbuf); +} + +/* Initialize the push target. */ +static int lnet_push_target_init(void) +{ + int rc; + + if (the_lnet.ln_push_target) + return -EALREADY; + + rc = LNetEQAlloc(0, lnet_push_target_event_handler, + &the_lnet.ln_push_target_eq); + if (rc) { + CERROR("Can't allocated push target EQ: %d\n", rc); + return rc; + } + + /* Start at the required minimum, we'll enlarge if required. */ + the_lnet.ln_push_target_nnis = LNET_INTERFACES_MIN; + + rc = lnet_push_target_resize(); + + if (rc) { + LNetEQFree(the_lnet.ln_push_target_eq); + LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq); + } + + return rc; +} + +/* Clean up the push target. */ +static void lnet_push_target_fini(void) +{ + if (!the_lnet.ln_push_target) + return; + + /* Unlink and invalidate to prevent new references. */ + LNetMDUnlink(the_lnet.ln_push_target_md); + LNetInvalidateMDHandle(&the_lnet.ln_push_target_md); + + /* Wait for the unlink to complete. */ + while (lnet_ping_buffer_numref(the_lnet.ln_push_target) > 1) { + CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n"); + schedule_timeout_uninterruptible(HZ); + } + + lnet_ping_buffer_decref(the_lnet.ln_push_target); + the_lnet.ln_push_target = NULL; + the_lnet.ln_push_target_nnis = 0; + + LNetEQFree(the_lnet.ln_push_target_eq); + LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq); +} + static int lnet_ni_tq_credits(struct lnet_ni *ni) { @@ -1945,10 +2086,14 @@ LNetNIInit(lnet_pid_t requested_pid) if (rc) goto err_stop_ping; - rc = lnet_peer_discovery_start(); + rc = lnet_push_target_init(); if (rc != 0) goto err_stop_router_checker; + rc = lnet_peer_discovery_start(); + if (rc != 0) + goto err_destroy_push_target; + lnet_fault_init(); lnet_router_debugfs_init(); @@ -1956,6 +2101,8 @@ LNetNIInit(lnet_pid_t requested_pid) return 0; +err_destroy_push_target: + lnet_push_target_fini(); err_stop_router_checker: lnet_router_checker_stop(); err_stop_ping: @@ -2007,6 +2154,7 @@ LNetNIFini(void) lnet_fault_fini(); lnet_router_debugfs_fini(); lnet_peer_discovery_stop(); + lnet_push_target_fini(); lnet_router_checker_stop(); lnet_ping_target_fini(); diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 038b58414ce0..b78f99c354de 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -1681,6 +1681,8 @@ static int lnet_peer_discovery_wait_for_work(void) TASK_IDLE); if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) break; + if (lnet_push_target_resize_needed()) + break; if (!list_empty(&the_lnet.ln_dc_request)) break; lnet_net_unlock(cpt); @@ -1711,6 +1713,9 @@ static int lnet_peer_discovery(void *arg) if (lnet_peer_discovery_wait_for_work()) break; + if (lnet_push_target_resize_needed()) + lnet_push_target_resize(); + lnet_net_lock(LNET_LOCK_EX); if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) break; From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 18/24] lustre: lnet: implement Peer Discovery In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437824.16383.8664465506271547759.stgit@noble> From: Olaf Weber Implement Peer Discovery. A peer is queued for discovery by lnet_peer_queue_for_discovery(). This set LNET_PEER_DISCOVERING, to indicate that discovery is in progress. The discovery thread lnet_peer_discovery() checks the peer and updates its state as appropriate. If LNET_PEER_DATA_PRESENT is set, then a valid Push message or Ping reply has been received. The peer is updated in accordance with the data, and LNET_PEER_NIDS_UPTODATE is set. If LNET_PEER_PING_FAILED is set, then an attempt to send a Ping message failed, and peer state is updated accordingly. The discovery thread can do some cleanup like unlinking an MD that cannot be done from the message event handler. If LNET_PEER_PUSH_FAILED is set, then an attempt to send a Push message failed, and peer state is updated accordingly. The discovery thread can do some cleanup like unlinking an MD that cannot be done from the message event handler. If LNET_PEER_PING_REQUIRED is set, we must Ping the peer in order to correctly update our knowledge of it. This is set, for example, if we receive a Push message for a peer, but cannot handle it because the Push target was too small. In such a case we know that the state of the peer is incorrect, but need to do extra work to obtain the required information. If discovery is not enabled, then the discovery process stops here and the peer is marked with LNET_PEER_UNDISCOVERED. This tells the discovery process that it doesn't need to revisit the peer while discovery remains disabled. If LNET_PEER_NIDS_UPTODATE is not set, then we have reason to think the lnet_peer is not up to date, and will Ping it. The peer needs a Push if it is multi-rail and the ping buffer sequence number for this node is newer than the sequence number it has acknowledged receiving by sending an Ack of a Push. If none of the above is true, then discovery has completed its work on the peer. Discovery signals that it is done with a peer by clearing the LNET_PEER_DISCOVERING flag, and setting LNET_PEER_DISCOVERED or LNET_PEER_UNDISCOVERED as appropriate. It then dequeues the peer and clears the LNET_PEER_QUEUED flag. When the local node is discovered via the loopback network, the peer structure that is created will have an lnet_peer_ni for the local loopback interface. Subsequent traffic from this node to itself will use the loopback net. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25789 Reviewed-by: Olaf Weber Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 20 .../staging/lustre/include/linux/lnet/lib-types.h | 39 + drivers/staging/lustre/lnet/lnet/api-ni.c | 59 + drivers/staging/lustre/lnet/lnet/lib-move.c | 18 drivers/staging/lustre/lnet/lnet/peer.c | 1499 +++++++++++++++++++- 5 files changed, 1543 insertions(+), 92 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 5632e5aadf41..f82a699371f2 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -76,6 +76,9 @@ extern struct lnet the_lnet; /* THE network */ #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 +/* Discovery timeout - same as default peer_timeout */ +#define DISCOVERY_TIMEOUT 180 + static inline int lnet_is_route_alive(struct lnet_route *route) { /* gateway is down */ @@ -713,9 +716,10 @@ struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); void lnet_peer_net_added(struct lnet_net *net); lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); -int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt); +int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block); int lnet_peer_discovery_start(void); void lnet_peer_discovery_stop(void); +void lnet_push_update_to_peers(int force); void lnet_peer_tables_cleanup(struct lnet_net *net); void lnet_peer_uninit(void); int lnet_peer_tables_create(void); @@ -805,4 +809,18 @@ lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) bool lnet_peer_is_uptodate(struct lnet_peer *lp); +static inline bool +lnet_peer_needs_push(struct lnet_peer *lp) +{ + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) + return false; + if (lp->lp_state & LNET_PEER_FORCE_PUSH) + return true; + if (lp->lp_state & LNET_PEER_NO_DISCOVERY) + return false; + if (lp->lp_node_seqno < atomic_read(&the_lnet.ln_ping_target_seqno)) + return true; + return false; +} + #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index e00c13355d43..07baa86e61ab 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -67,6 +67,13 @@ struct lnet_msg { lnet_nid_t msg_from; __u32 msg_type; + /* + * hold parameters in case message is with held due + * to discovery + */ + lnet_nid_t msg_src_nid_param; + lnet_nid_t msg_rtr_nid_param; + /* committed for sending */ unsigned int msg_tx_committed:1; /* CPT # this message committed for sending */ @@ -395,6 +402,8 @@ struct lnet_ping_buffer { #define LNET_PING_BUFFER_LONI(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_nid) #define LNET_PING_BUFFER_SEQNO(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_status) +#define LNET_PING_INFO_TO_BUFFER(PINFO) \ + container_of((PINFO), struct lnet_ping_buffer, pb_info) /* router checker data, per router */ struct lnet_rc_data { @@ -503,6 +512,9 @@ struct lnet_peer { /* list of peer nets */ struct list_head lp_peer_nets; + /* list of messages pending discovery*/ + struct list_head lp_dc_pendq; + /* primary NID of the peer */ lnet_nid_t lp_primary_nid; @@ -524,15 +536,36 @@ struct lnet_peer { /* buffer for data pushed by peer */ struct lnet_ping_buffer *lp_data; + /* MD handle for ping in progress */ + struct lnet_handle_md lp_ping_mdh; + + /* MD handle for push in progress */ + struct lnet_handle_md lp_push_mdh; + /* number of NIDs for sizing push data */ int lp_data_nnis; /* NI config sequence number of peer */ __u32 lp_peer_seqno; - /* Local NI config sequence number peer knows */ + /* Local NI config sequence number acked by peer */ __u32 lp_node_seqno; + /* Local NI config sequence number sent to peer */ + __u32 lp_node_seqno_sent; + + /* Ping error encountered during discovery. */ + int lp_ping_error; + + /* Push error encountered during discovery. */ + int lp_push_error; + + /* Error encountered during discovery. */ + int lp_dc_error; + + /* time it was put on the ln_dc_working queue */ + time64_t lp_last_queued; + /* link on discovery-related lists */ struct list_head lp_dc_list; @@ -691,6 +724,8 @@ struct lnet_remotenet { #define LNET_CREDIT_OK 0 /** lnet message is waiting for credit */ #define LNET_CREDIT_WAIT 1 +/** lnet message is waiting for discovery */ +#define LNET_DC_WAIT 2 struct lnet_rtrbufpool { struct list_head rbp_bufs; /* my free buffer pool */ @@ -943,6 +978,8 @@ struct lnet { struct list_head ln_dc_request; /* discovery working list */ struct list_head ln_dc_working; + /* discovery expired list */ + struct list_head ln_dc_expired; /* discovery thread wait queue */ wait_queue_head_t ln_dc_waitq; /* discovery startup/shutdown state */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index e6bc54e9de71..955d1711eda4 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -41,7 +41,14 @@ #define D_LNI D_CONSOLE -struct lnet the_lnet; /* THE state of the network */ +/* + * initialize ln_api_mutex statically, since it needs to be used in + * discovery_set callback. That module parameter callback can be called + * before module init completes. The mutex needs to be ready for use then. + */ +struct lnet the_lnet = { + .ln_api_mutex = __MUTEX_INITIALIZER(the_lnet.ln_api_mutex), +}; /* THE state of the network */ EXPORT_SYMBOL(the_lnet); static char *ip2nets = ""; @@ -101,7 +108,9 @@ static int discovery_set(const char *val, const struct kernel_param *kp) { int rc; + unsigned int *discovery = (unsigned int *)kp->arg; unsigned long value; + struct lnet_ping_buffer *pbuf; rc = kstrtoul(val, 0, &value); if (rc) { @@ -109,7 +118,38 @@ discovery_set(const char *val, const struct kernel_param *kp) return rc; } - *(unsigned int *)kp->arg = !!value; + value = !!value; + + /* + * The purpose of locking the api_mutex here is to ensure that + * the correct value ends up stored properly. + */ + mutex_lock(&the_lnet.ln_api_mutex); + + if (value == *discovery) { + mutex_unlock(&the_lnet.ln_api_mutex); + return 0; + } + + *discovery = value; + + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { + mutex_unlock(&the_lnet.ln_api_mutex); + return 0; + } + + /* tell peers that discovery setting has changed */ + lnet_net_lock(LNET_LOCK_EX); + pbuf = the_lnet.ln_ping_target; + if (value) + pbuf->pb_info.pi_features &= ~LNET_PING_FEAT_DISCOVERY; + else + pbuf->pb_info.pi_features |= LNET_PING_FEAT_DISCOVERY; + lnet_net_unlock(LNET_LOCK_EX); + + lnet_push_update_to_peers(1); + + mutex_unlock(&the_lnet.ln_api_mutex); return 0; } @@ -171,7 +211,6 @@ lnet_init_locks(void) init_waitqueue_head(&the_lnet.ln_eq_waitq); init_waitqueue_head(&the_lnet.ln_rc_waitq); mutex_init(&the_lnet.ln_lnd_mutex); - mutex_init(&the_lnet.ln_api_mutex); } static int @@ -654,6 +693,10 @@ lnet_prepare(lnet_pid_t requested_pid) INIT_LIST_HEAD(&the_lnet.ln_routers); INIT_LIST_HEAD(&the_lnet.ln_drop_rules); INIT_LIST_HEAD(&the_lnet.ln_delay_rules); + INIT_LIST_HEAD(&the_lnet.ln_dc_request); + INIT_LIST_HEAD(&the_lnet.ln_dc_working); + INIT_LIST_HEAD(&the_lnet.ln_dc_expired); + init_waitqueue_head(&the_lnet.ln_dc_waitq); rc = lnet_create_remote_nets_table(); if (rc) @@ -998,7 +1041,8 @@ lnet_ping_target_create(int nnis) pbuf->pb_info.pi_nnis = nnis; pbuf->pb_info.pi_pid = the_lnet.ln_pid; pbuf->pb_info.pi_magic = LNET_PROTO_PING_MAGIC; - pbuf->pb_info.pi_features = LNET_PING_FEAT_NI_STATUS; + pbuf->pb_info.pi_features = + LNET_PING_FEAT_NI_STATUS | LNET_PING_FEAT_MULTI_RAIL; return pbuf; } @@ -1231,6 +1275,8 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, if (!the_lnet.ln_routing) pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; + if (!lnet_peer_discovery_disabled) + pbuf->pb_info.pi_features |= LNET_PING_FEAT_DISCOVERY; /* Ensure only known feature bits have been set. */ LASSERT(pbuf->pb_info.pi_features & LNET_PING_FEAT_BITS); @@ -1252,6 +1298,8 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, lnet_ping_md_unlink(old_pbuf, &old_ping_md); lnet_ping_buffer_decref(old_pbuf); } + + lnet_push_update_to_peers(0); } static void @@ -1353,6 +1401,7 @@ static void lnet_push_target_event_handler(struct lnet_event *ev) if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) lnet_swap_pinginfo(pbuf); + lnet_peer_push_event(ev); if (ev->unlinked) lnet_ping_buffer_decref(pbuf); } @@ -1910,8 +1959,6 @@ int lnet_lib_init(void) lnet_assert_wire_constants(); - memset(&the_lnet, 0, sizeof(the_lnet)); - /* refer to global cfs_cpt_tab for now */ the_lnet.ln_cpt_table = cfs_cpt_tab; the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_tab); diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 4773180cc7b3..2ff329bf91ba 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -444,6 +444,8 @@ lnet_prep_send(struct lnet_msg *msg, int type, struct lnet_process_id target, memset(&msg->msg_hdr, 0, sizeof(msg->msg_hdr)); msg->msg_hdr.type = cpu_to_le32(type); + /* dest_nid will be overwritten by lnet_select_pathway() */ + msg->msg_hdr.dest_nid = cpu_to_le64(target.nid); msg->msg_hdr.dest_pid = cpu_to_le32(target.pid); /* src_nid will be set later */ msg->msg_hdr.src_pid = cpu_to_le32(the_lnet.ln_pid); @@ -1292,7 +1294,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, */ peer = lpni->lpni_peer_net->lpn_peer; if (lnet_msg_discovery(msg) && !lnet_peer_is_uptodate(peer)) { - rc = lnet_discover_peer_locked(lpni, cpt); + rc = lnet_discover_peer_locked(lpni, cpt, false); if (rc) { lnet_peer_ni_decref_locked(lpni); lnet_net_unlock(cpt); @@ -1300,6 +1302,18 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, } /* The peer may have changed. */ peer = lpni->lpni_peer_net->lpn_peer; + /* queue message and return */ + msg->msg_src_nid_param = src_nid; + msg->msg_rtr_nid_param = rtr_nid; + msg->msg_sending = 0; + list_add_tail(&msg->msg_list, &peer->lp_dc_pendq); + lnet_peer_ni_decref_locked(lpni); + lnet_net_unlock(cpt); + + CDEBUG(D_NET, "%s pending discovery\n", + libcfs_nid2str(peer->lp_primary_nid)); + + return LNET_DC_WAIT; } lnet_peer_ni_decref_locked(lpni); @@ -1840,7 +1854,7 @@ lnet_send(lnet_nid_t src_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid) if (rc == LNET_CREDIT_OK) lnet_ni_send(msg->msg_txni, msg); - /* rc == LNET_CREDIT_OK or LNET_CREDIT_WAIT */ + /* rc == LNET_CREDIT_OK or LNET_CREDIT_WAIT or LNET_DC_WAIT */ return 0; } diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index b78f99c354de..1ef4a44e752e 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -38,6 +38,11 @@ #include #include +/* Value indicating that recovery needs to re-check a peer immediately. */ +#define LNET_REDISCOVER_PEER (1) + +static int lnet_peer_queue_for_discovery(struct lnet_peer *lp); + static void lnet_peer_remove_from_remote_list(struct lnet_peer_ni *lpni) { @@ -202,6 +207,7 @@ lnet_peer_alloc(lnet_nid_t nid) INIT_LIST_HEAD(&lp->lp_peer_list); INIT_LIST_HEAD(&lp->lp_peer_nets); INIT_LIST_HEAD(&lp->lp_dc_list); + INIT_LIST_HEAD(&lp->lp_dc_pendq); init_waitqueue_head(&lp->lp_dc_waitq); spin_lock_init(&lp->lp_lock); lp->lp_primary_nid = nid; @@ -220,6 +226,10 @@ lnet_destroy_peer_locked(struct lnet_peer *lp) LASSERT(atomic_read(&lp->lp_refcount) == 0); LASSERT(list_empty(&lp->lp_peer_nets)); LASSERT(list_empty(&lp->lp_peer_list)); + LASSERT(list_empty(&lp->lp_dc_list)); + + if (lp->lp_data) + lnet_ping_buffer_decref(lp->lp_data); kfree(lp); } @@ -260,10 +270,19 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) /* * If there are no more peer nets, make the peer unfindable * via the peer_tables. + * + * Otherwise, if the peer is DISCOVERED, tell discovery to + * take another look at it. This is a no-op if discovery for + * this peer did the detaching. */ if (list_empty(&lp->lp_peer_nets)) { list_del_init(&lp->lp_peer_list); ptable->pt_peers--; + } else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) { + /* Discovery isn't running, nothing to do here. */ + } else if (lp->lp_state & LNET_PEER_DISCOVERED) { + lnet_peer_queue_for_discovery(lp); + wake_up(&the_lnet.ln_dc_waitq); } CDEBUG(D_NET, "peer %s NID %s\n", libcfs_nid2str(lp->lp_primary_nid), @@ -599,6 +618,25 @@ lnet_find_peer_ni_locked(lnet_nid_t nid) return lpni; } +struct lnet_peer * +lnet_find_peer(lnet_nid_t nid) +{ + struct lnet_peer_ni *lpni; + struct lnet_peer *lp = NULL; + int cpt; + + cpt = lnet_net_lock_current(); + lpni = lnet_find_peer_ni_locked(nid); + if (lpni) { + lp = lpni->lpni_peer_net->lpn_peer; + lnet_peer_addref_locked(lp); + lnet_peer_ni_decref_locked(lpni); + } + lnet_net_unlock(cpt); + + return lp; +} + struct lnet_peer_ni * lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, struct lnet_peer **lp) @@ -696,6 +734,37 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, return lpni; } +/* + * Start pushes to peers that need to be updated for a configuration + * change on this node. + */ +void +lnet_push_update_to_peers(int force) +{ + struct lnet_peer_table *ptable; + struct lnet_peer *lp; + int lncpt; + int cpt; + + lnet_net_lock(LNET_LOCK_EX); + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); + for (cpt = 0; cpt < lncpt; cpt++) { + ptable = the_lnet.ln_peer_tables[cpt]; + list_for_each_entry(lp, &ptable->pt_peer_list, lp_peer_list) { + if (force) { + spin_lock(&lp->lp_lock); + if (lp->lp_state & LNET_PEER_MULTI_RAIL) + lp->lp_state |= LNET_PEER_FORCE_PUSH; + spin_unlock(&lp->lp_lock); + } + if (lnet_peer_needs_push(lp)) + lnet_peer_queue_for_discovery(lp); + } + } + lnet_net_unlock(LNET_LOCK_EX); + wake_up(&the_lnet.ln_dc_waitq); +} + /* * Test whether a ni is a preferred ni for this peer_ni, e.g, whether * this is a preferred point-to-point path. Call with lnet_net_lock in @@ -941,6 +1010,7 @@ lnet_peer_primary_nid_locked(lnet_nid_t nid) lnet_nid_t LNetPrimaryNID(lnet_nid_t nid) { + struct lnet_peer *lp; struct lnet_peer_ni *lpni; lnet_nid_t primary_nid = nid; int rc = 0; @@ -952,7 +1022,15 @@ LNetPrimaryNID(lnet_nid_t nid) rc = PTR_ERR(lpni); goto out_unlock; } - primary_nid = lpni->lpni_peer_net->lpn_peer->lp_primary_nid; + lp = lpni->lpni_peer_net->lpn_peer; + while (!lnet_peer_is_uptodate(lp)) { + rc = lnet_discover_peer_locked(lpni, cpt, true); + if (rc) + goto out_decref; + lp = lpni->lpni_peer_net->lpn_peer; + } + primary_nid = lp->lp_primary_nid; +out_decref: lnet_peer_ni_decref_locked(lpni); out_unlock: lnet_net_unlock(cpt); @@ -1229,6 +1307,30 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) return rc; } +/* + * Update the primary NID of a peer, if possible. + * + * Call with the lnet_api_mutex held. + */ +static int +lnet_peer_set_primary_nid(struct lnet_peer *lp, lnet_nid_t nid, + unsigned int flags) +{ + lnet_nid_t old = lp->lp_primary_nid; + int rc = 0; + + if (lp->lp_primary_nid == nid) + goto out; + rc = lnet_peer_add_nid(lp, nid, flags); + if (rc) + goto out; + lp->lp_primary_nid = nid; +out: + CDEBUG(D_NET, "peer %s NID %s: %d\n", + libcfs_nid2str(old), libcfs_nid2str(nid), rc); + return rc; +} + /* * lpni creation initiated due to traffic either sending or receiving. */ @@ -1548,11 +1650,15 @@ lnet_peer_is_uptodate(struct lnet_peer *lp) LNET_PEER_FORCE_PING | LNET_PEER_FORCE_PUSH)) { rc = false; + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { + rc = true; } else if (lp->lp_state & LNET_PEER_REDISCOVER) { if (lnet_peer_discovery_disabled) rc = true; else rc = false; + } else if (lnet_peer_needs_push(lp)) { + rc = false; } else if (lp->lp_state & LNET_PEER_DISCOVERED) { if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) rc = true; @@ -1588,6 +1694,9 @@ static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) rc = -EALREADY; } + CDEBUG(D_NET, "Queue peer %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), rc); + return rc; } @@ -1597,9 +1706,252 @@ static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) */ static void lnet_peer_discovery_complete(struct lnet_peer *lp) { + struct lnet_msg *msg = NULL; + int rc = 0; + struct list_head pending_msgs; + + INIT_LIST_HEAD(&pending_msgs); + + CDEBUG(D_NET, "Discovery complete. Dequeue peer %s\n", + libcfs_nid2str(lp->lp_primary_nid)); + list_del_init(&lp->lp_dc_list); + list_splice_init(&lp->lp_dc_pendq, &pending_msgs); wake_up_all(&lp->lp_dc_waitq); + + lnet_net_unlock(LNET_LOCK_EX); + + /* iterate through all pending messages and send them again */ + list_for_each_entry(msg, &pending_msgs, msg_list) { + if (lp->lp_dc_error) { + lnet_finalize(msg, lp->lp_dc_error); + continue; + } + + CDEBUG(D_NET, "sending pending message %s to target %s\n", + lnet_msgtyp2str(msg->msg_type), + libcfs_id2str(msg->msg_target)); + rc = lnet_send(msg->msg_src_nid_param, msg, + msg->msg_rtr_nid_param); + if (rc < 0) { + CNETERR("Error sending %s to %s: %d\n", + lnet_msgtyp2str(msg->msg_type), + libcfs_id2str(msg->msg_target), rc); + lnet_finalize(msg, rc); + } + } + lnet_net_lock(LNET_LOCK_EX); + lnet_peer_decref_locked(lp); +} + +/* + * Handle inbound push. + * Like any event handler, called with lnet_res_lock/CPT held. + */ +void lnet_peer_push_event(struct lnet_event *ev) +{ + struct lnet_ping_buffer *pbuf = ev->md.user_ptr; + struct lnet_peer *lp; + + /* lnet_find_peer() adds a refcount */ + lp = lnet_find_peer(ev->source.nid); + if (!lp) { + CERROR("Push Put from unknown %s (source %s)\n", + libcfs_nid2str(ev->initiator.nid), + libcfs_nid2str(ev->source.nid)); + return; + } + + /* Ensure peer state remains consistent while we modify it. */ + spin_lock(&lp->lp_lock); + + /* + * If some kind of error happened the contents of the message + * cannot be used. Clear the NIDS_UPTODATE and set the + * FORCE_PING flag to trigger a ping. + */ + if (ev->status) { + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + lp->lp_state |= LNET_PEER_FORCE_PING; + CDEBUG(D_NET, "Push Put error %d from %s (source %s)\n", + ev->status, + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(ev->source.nid)); + goto out; + } + + /* + * A push with invalid or corrupted info. Clear the UPTODATE + * flag to trigger a ping. + */ + if (lnet_ping_info_validate(&pbuf->pb_info)) { + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + lp->lp_state |= LNET_PEER_FORCE_PING; + CDEBUG(D_NET, "Corrupted Push from %s\n", + libcfs_nid2str(lp->lp_primary_nid)); + goto out; + } + + /* + * Make sure we'll allocate the correct size ping buffer when + * pinging the peer. + */ + if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis) + lp->lp_data_nnis = pbuf->pb_info.pi_nnis; + + /* + * A non-Multi-Rail peer is not supposed to be capable of + * sending a push. + */ + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL)) { + CERROR("Push from non-Multi-Rail peer %s dropped\n", + libcfs_nid2str(lp->lp_primary_nid)); + goto out; + } + + /* + * Check the MULTIRAIL flag. Complain if the peer was DLC + * configured without it. + */ + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + if (lp->lp_state & LNET_PEER_CONFIGURED) { + CERROR("Push says %s is Multi-Rail, DLC says not\n", + libcfs_nid2str(lp->lp_primary_nid)); + } else { + lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); + } + } + + /* + * The peer may have discovery disabled at its end. Set + * NO_DISCOVERY as appropriate. + */ + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_DISCOVERY)) { + CDEBUG(D_NET, "Peer %s has discovery disabled\n", + libcfs_nid2str(lp->lp_primary_nid)); + lp->lp_state |= LNET_PEER_NO_DISCOVERY; + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { + CDEBUG(D_NET, "Peer %s has discovery enabled\n", + libcfs_nid2str(lp->lp_primary_nid)); + lp->lp_state &= ~LNET_PEER_NO_DISCOVERY; + } + + /* + * Check for truncation of the Put message. Clear the + * NIDS_UPTODATE flag and set FORCE_PING to trigger a ping, + * and tell discovery to allocate a bigger buffer. + */ + if (pbuf->pb_nnis < pbuf->pb_info.pi_nnis) { + if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis) + the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis; + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + lp->lp_state |= LNET_PEER_FORCE_PING; + CDEBUG(D_NET, "Truncated Push from %s (%d nids)\n", + libcfs_nid2str(lp->lp_primary_nid), + pbuf->pb_info.pi_nnis); + goto out; + } + + /* + * Check whether the Put data is stale. Stale data can just be + * dropped. + */ + if (pbuf->pb_info.pi_nnis > 1 && + lp->lp_primary_nid == pbuf->pb_info.pi_ni[1].ns_nid && + LNET_PING_BUFFER_SEQNO(pbuf) < lp->lp_peer_seqno) { + CDEBUG(D_NET, "Stale Push from %s: got %u have %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf), + lp->lp_peer_seqno); + goto out; + } + + /* + * Check whether the Put data is new, in which case we clear + * the UPTODATE flag and prepare to process it. + * + * If the Put data is current, and the peer is UPTODATE then + * we assome everything is all right and drop the data as + * stale. + */ + if (LNET_PING_BUFFER_SEQNO(pbuf) > lp->lp_peer_seqno) { + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + } else if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) { + CDEBUG(D_NET, "Stale Push from %s: got %u have %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf), + lp->lp_peer_seqno); + goto out; + } + + /* + * If there is data present that hasn't been processed yet, + * we'll replace it if the Put contained newer data and it + * fits. We're racing with a Ping or earlier Push in this + * case. + */ + if (lp->lp_state & LNET_PEER_DATA_PRESENT) { + if (LNET_PING_BUFFER_SEQNO(pbuf) > + LNET_PING_BUFFER_SEQNO(lp->lp_data) && + pbuf->pb_info.pi_nnis <= lp->lp_data->pb_nnis) { + memcpy(&lp->lp_data->pb_info, &pbuf->pb_info, + LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis)); + CDEBUG(D_NET, "Ping/Push race from %s: %u vs %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf), + LNET_PING_BUFFER_SEQNO(lp->lp_data)); + } + goto out; + } + + /* + * Allocate a buffer to copy the data. On a failure we drop + * the Push and set FORCE_PING to force the discovery + * thread to fix the problem by pinging the peer. + */ + lp->lp_data = lnet_ping_buffer_alloc(lp->lp_data_nnis, GFP_ATOMIC); + if (!lp->lp_data) { + lp->lp_state |= LNET_PEER_FORCE_PING; + CDEBUG(D_NET, "Cannot allocate Push buffer for %s %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf)); + goto out; + } + + /* Success */ + memcpy(&lp->lp_data->pb_info, &pbuf->pb_info, + LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis)); + lp->lp_state |= LNET_PEER_DATA_PRESENT; + CDEBUG(D_NET, "Received Push %s %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf)); + +out: + /* + * Queue the peer for discovery, and wake the discovery thread + * if the peer was already queued, because its status changed. + */ + spin_unlock(&lp->lp_lock); + lnet_net_lock(LNET_LOCK_EX); + if (lnet_peer_queue_for_discovery(lp)) + wake_up(&the_lnet.ln_dc_waitq); + /* Drop refcount from lookup */ lnet_peer_decref_locked(lp); + lnet_net_unlock(LNET_LOCK_EX); +} + +/* + * Clear the discovery error state, unless we're already discovering + * this peer, in which case the error is current. + */ +static void lnet_peer_clear_discovery_error(struct lnet_peer *lp) +{ + spin_lock(&lp->lp_lock); + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) + lp->lp_dc_error = 0; + spin_unlock(&lp->lp_lock); } /* @@ -1608,7 +1960,7 @@ static void lnet_peer_discovery_complete(struct lnet_peer *lp) * because discovery could tear down an lnet_peer. */ int -lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) +lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) { DEFINE_WAIT(wait); struct lnet_peer *lp; @@ -1617,25 +1969,40 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) again: lnet_net_unlock(cpt); lnet_net_lock(LNET_LOCK_EX); + lp = lpni->lpni_peer_net->lpn_peer; + lnet_peer_clear_discovery_error(lp); - /* We're willing to be interrupted. */ + /* + * We're willing to be interrupted. The lpni can become a + * zombie if we race with DLC, so we must check for that. + */ for (;;) { - lp = lpni->lpni_peer_net->lpn_peer; prepare_to_wait(&lp->lp_dc_waitq, &wait, TASK_INTERRUPTIBLE); if (signal_pending(current)) break; if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) break; + if (lp->lp_dc_error) + break; if (lnet_peer_is_uptodate(lp)) break; lnet_peer_queue_for_discovery(lp); lnet_peer_addref_locked(lp); + /* + * if caller requested a non-blocking operation then + * return immediately. Once discovery is complete then the + * peer ref will be decremented and any pending messages + * that were stopped due to discovery will be transmitted. + */ + if (!block) + break; lnet_net_unlock(LNET_LOCK_EX); schedule(); finish_wait(&lp->lp_dc_waitq, &wait); lnet_net_lock(LNET_LOCK_EX); lnet_peer_decref_locked(lp); - /* Do not use lp beyond this point. */ + /* Peer may have changed */ + lp = lpni->lpni_peer_net->lpn_peer; } finish_wait(&lp->lp_dc_waitq, &wait); @@ -1646,71 +2013,969 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) rc = -EINTR; else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) rc = -ESHUTDOWN; + else if (lp->lp_dc_error) + rc = lp->lp_dc_error; + else if (!block) + CDEBUG(D_NET, "non-blocking discovery\n"); else if (!lnet_peer_is_uptodate(lp)) goto again; + CDEBUG(D_NET, "peer %s NID %s: %d. %s\n", + (lp ? libcfs_nid2str(lp->lp_primary_nid) : "(none)"), + libcfs_nid2str(lpni->lpni_nid), rc, + (!block) ? "pending discovery" : "discovery complete"); + return rc; } -/* - * Event handler for the discovery EQ. - * - * Called with lnet_res_lock(cpt) held. The cpt is the - * lnet_cpt_of_cookie() of the md handle cookie. - */ -static void lnet_discovery_event_handler(struct lnet_event *event) +/* Handle an incoming ack for a push. */ +static void +lnet_discovery_event_ack(struct lnet_peer *lp, struct lnet_event *ev) { - wake_up(&the_lnet.ln_dc_waitq); + struct lnet_ping_buffer *pbuf; + + pbuf = LNET_PING_INFO_TO_BUFFER(ev->md.start); + spin_lock(&lp->lp_lock); + lp->lp_state &= ~LNET_PEER_PUSH_SENT; + lp->lp_push_error = ev->status; + if (ev->status) + lp->lp_state |= LNET_PEER_PUSH_FAILED; + else + lp->lp_node_seqno = LNET_PING_BUFFER_SEQNO(pbuf); + spin_unlock(&lp->lp_lock); + + CDEBUG(D_NET, "peer %s ev->status %d\n", + libcfs_nid2str(lp->lp_primary_nid), ev->status); } -/* - * Wait for work to be queued or some other change that must be - * attended to. Returns non-zero if the discovery thread should shut - * down. - */ -static int lnet_peer_discovery_wait_for_work(void) +/* Handle a Reply message. This is the reply to a Ping message. */ +static void +lnet_discovery_event_reply(struct lnet_peer *lp, struct lnet_event *ev) { - int cpt; - int rc = 0; + struct lnet_ping_buffer *pbuf; + int rc; - DEFINE_WAIT(wait); + spin_lock(&lp->lp_lock); - cpt = lnet_net_lock_current(); - for (;;) { - prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, - TASK_IDLE); - if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) - break; - if (lnet_push_target_resize_needed()) - break; - if (!list_empty(&the_lnet.ln_dc_request)) - break; - lnet_net_unlock(cpt); - schedule(); - finish_wait(&the_lnet.ln_dc_waitq, &wait); - cpt = lnet_net_lock_current(); + /* + * If some kind of error happened the contents of message + * cannot be used. Set PING_FAILED to trigger a retry. + */ + if (ev->status) { + lp->lp_state |= LNET_PEER_PING_FAILED; + lp->lp_ping_error = ev->status; + CDEBUG(D_NET, "Ping Reply error %d from %s (source %s)\n", + ev->status, + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(ev->source.nid)); + goto out; } - finish_wait(&the_lnet.ln_dc_waitq, &wait); - - if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) - rc = -ESHUTDOWN; - lnet_net_unlock(cpt); + pbuf = LNET_PING_INFO_TO_BUFFER(ev->md.start); + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) + lnet_swap_pinginfo(pbuf); - CDEBUG(D_NET, "woken: %d\n", rc); + /* + * A reply with invalid or corrupted info. Set PING_FAILED to + * trigger a retry. + */ + rc = lnet_ping_info_validate(&pbuf->pb_info); + if (rc) { + lp->lp_state |= LNET_PEER_PING_FAILED; + lp->lp_ping_error = 0; + CDEBUG(D_NET, "Corrupted Ping Reply from %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), rc); + goto out; + } - return rc; -} + /* + * Update the MULTI_RAIL flag based on the reply. If the peer + * was configured with DLC then the setting should match what + * DLC put in. + */ + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) { + if (lp->lp_state & LNET_PEER_MULTI_RAIL) { + /* Everything's fine */ + } else if (lp->lp_state & LNET_PEER_CONFIGURED) { + CWARN("Reply says %s is Multi-Rail, DLC says not\n", + libcfs_nid2str(lp->lp_primary_nid)); + } else { + lp->lp_state |= LNET_PEER_MULTI_RAIL; + lnet_peer_clr_non_mr_pref_nids(lp); + } + } else if (lp->lp_state & LNET_PEER_MULTI_RAIL) { + if (lp->lp_state & LNET_PEER_CONFIGURED) { + CWARN("DLC says %s is Multi-Rail, Reply says not\n", + libcfs_nid2str(lp->lp_primary_nid)); + } else { + CERROR("Multi-Rail state vanished from %s\n", + libcfs_nid2str(lp->lp_primary_nid)); + lp->lp_state &= ~LNET_PEER_MULTI_RAIL; + } + } -/* The discovery thread. */ -static int lnet_peer_discovery(void *arg) -{ - struct lnet_peer *lp; + /* + * Make sure we'll allocate the correct size ping buffer when + * pinging the peer. + */ + if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis) + lp->lp_data_nnis = pbuf->pb_info.pi_nnis; - CDEBUG(D_NET, "started\n"); + /* + * The peer may have discovery disabled at its end. Set + * NO_DISCOVERY as appropriate. + */ + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_DISCOVERY)) { + CDEBUG(D_NET, "Peer %s has discovery disabled\n", + libcfs_nid2str(lp->lp_primary_nid)); + lp->lp_state |= LNET_PEER_NO_DISCOVERY; + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { + CDEBUG(D_NET, "Peer %s has discovery enabled\n", + libcfs_nid2str(lp->lp_primary_nid)); + lp->lp_state &= ~LNET_PEER_NO_DISCOVERY; + } - for (;;) { - if (lnet_peer_discovery_wait_for_work()) + /* + * Check for truncation of the Reply. Clear PING_SENT and set + * PING_FAILED to trigger a retry. + */ + if (pbuf->pb_nnis < pbuf->pb_info.pi_nnis) { + if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis) + the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis; + lp->lp_state |= LNET_PEER_PING_FAILED; + lp->lp_ping_error = 0; + CDEBUG(D_NET, "Truncated Reply from %s (%d nids)\n", + libcfs_nid2str(lp->lp_primary_nid), + pbuf->pb_info.pi_nnis); + goto out; + } + + /* + * Check the sequence numbers in the reply. These are only + * available if the reply came from a Multi-Rail peer. + */ + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL && + pbuf->pb_info.pi_nnis > 1 && + lp->lp_primary_nid == pbuf->pb_info.pi_ni[1].ns_nid) { + if (LNET_PING_BUFFER_SEQNO(pbuf) < lp->lp_peer_seqno) { + CDEBUG(D_NET, "Stale Reply from %s: got %u have %u\n", + libcfs_nid2str(lp->lp_primary_nid), + LNET_PING_BUFFER_SEQNO(pbuf), + lp->lp_peer_seqno); + goto out; + } + + if (LNET_PING_BUFFER_SEQNO(pbuf) > lp->lp_peer_seqno) + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); + } + + /* We're happy with the state of the data in the buffer. */ + CDEBUG(D_NET, "peer %s data present %u\n", + libcfs_nid2str(lp->lp_primary_nid), lp->lp_peer_seqno); + if (lp->lp_state & LNET_PEER_DATA_PRESENT) + lnet_ping_buffer_decref(lp->lp_data); + else + lp->lp_state |= LNET_PEER_DATA_PRESENT; + lnet_ping_buffer_addref(pbuf); + lp->lp_data = pbuf; +out: + lp->lp_state &= ~LNET_PEER_PING_SENT; + spin_unlock(&lp->lp_lock); +} + +/* + * Send event handling. Only matters for error cases, where we clean + * up state on the peer and peer_ni that would otherwise be updated in + * the REPLY event handler for a successful Ping, and the ACK event + * handler for a successful Push. + */ +static int +lnet_discovery_event_send(struct lnet_peer *lp, struct lnet_event *ev) +{ + int rc = 0; + + if (!ev->status) + goto out; + + spin_lock(&lp->lp_lock); + if (ev->msg_type == LNET_MSG_GET) { + lp->lp_state &= ~LNET_PEER_PING_SENT; + lp->lp_state |= LNET_PEER_PING_FAILED; + lp->lp_ping_error = ev->status; + } else { /* ev->msg_type == LNET_MSG_PUT */ + lp->lp_state &= ~LNET_PEER_PUSH_SENT; + lp->lp_state |= LNET_PEER_PUSH_FAILED; + lp->lp_push_error = ev->status; + } + spin_unlock(&lp->lp_lock); + rc = LNET_REDISCOVER_PEER; +out: + CDEBUG(D_NET, "%s Send to %s: %d\n", + (ev->msg_type == LNET_MSG_GET ? "Ping" : "Push"), + libcfs_nid2str(ev->target.nid), rc); + return rc; +} + +/* + * Unlink event handling. This event is only seen if a call to + * LNetMDUnlink() caused the event to be unlinked. If this call was + * made after the event was set up in LNetGet() or LNetPut() then we + * assume the Ping or Push timed out. + */ +static void +lnet_discovery_event_unlink(struct lnet_peer *lp, struct lnet_event *ev) +{ + spin_lock(&lp->lp_lock); + /* We've passed through LNetGet() */ + if (lp->lp_state & LNET_PEER_PING_SENT) { + lp->lp_state &= ~LNET_PEER_PING_SENT; + lp->lp_state |= LNET_PEER_PING_FAILED; + lp->lp_ping_error = -ETIMEDOUT; + CDEBUG(D_NET, "Ping Unlink for message to peer %s\n", + libcfs_nid2str(lp->lp_primary_nid)); + } + /* We've passed through LNetPut() */ + if (lp->lp_state & LNET_PEER_PUSH_SENT) { + lp->lp_state &= ~LNET_PEER_PUSH_SENT; + lp->lp_state |= LNET_PEER_PUSH_FAILED; + lp->lp_push_error = -ETIMEDOUT; + CDEBUG(D_NET, "Push Unlink for message to peer %s\n", + libcfs_nid2str(lp->lp_primary_nid)); + } + spin_unlock(&lp->lp_lock); +} + +/* + * Event handler for the discovery EQ. + * + * Called with lnet_res_lock(cpt) held. The cpt is the + * lnet_cpt_of_cookie() of the md handle cookie. + */ +static void lnet_discovery_event_handler(struct lnet_event *event) +{ + struct lnet_peer *lp = event->md.user_ptr; + struct lnet_ping_buffer *pbuf; + int rc; + + /* discovery needs to take another look */ + rc = LNET_REDISCOVER_PEER; + + CDEBUG(D_NET, "Received event: %d\n", event->type); + + switch (event->type) { + case LNET_EVENT_ACK: + lnet_discovery_event_ack(lp, event); + break; + case LNET_EVENT_REPLY: + lnet_discovery_event_reply(lp, event); + break; + case LNET_EVENT_SEND: + /* Only send failure triggers a retry. */ + rc = lnet_discovery_event_send(lp, event); + break; + case LNET_EVENT_UNLINK: + /* LNetMDUnlink() was called */ + lnet_discovery_event_unlink(lp, event); + break; + default: + /* Invalid events. */ + LBUG(); + } + lnet_net_lock(LNET_LOCK_EX); + if (event->unlinked) { + pbuf = LNET_PING_INFO_TO_BUFFER(event->md.start); + lnet_ping_buffer_decref(pbuf); + lnet_peer_decref_locked(lp); + } + if (rc == LNET_REDISCOVER_PEER) { + list_move_tail(&lp->lp_dc_list, &the_lnet.ln_dc_request); + wake_up(&the_lnet.ln_dc_waitq); + } + lnet_net_unlock(LNET_LOCK_EX); +} + +/* + * Build a peer from incoming data. + * + * The NIDs in the incoming data are supposed to be structured as follows: + * - loopback + * - primary NID + * - other NIDs in same net + * - NIDs in second net + * - NIDs in third net + * - ... + * This due to the way the list of NIDs in the data is created. + * + * Note that this function will mark the peer uptodate unless an + * ENOMEM is encontered. All other errors are due to a conflict + * between the DLC configuration and what discovery sees. We treat DLC + * as binding, and therefore set the NIDS_UPTODATE flag to prevent the + * peer from becoming stuck in discovery. + */ +static int lnet_peer_merge_data(struct lnet_peer *lp, + struct lnet_ping_buffer *pbuf) +{ + struct lnet_peer_ni *lpni; + lnet_nid_t *curnis = NULL; + lnet_nid_t *addnis = NULL; + lnet_nid_t *delnis = NULL; + unsigned int flags; + int ncurnis; + int naddnis; + int ndelnis; + int nnis = 0; + int i; + int j; + int rc; + + flags = LNET_PEER_DISCOVERED; + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) + flags |= LNET_PEER_MULTI_RAIL; + + nnis = max_t(int, lp->lp_nnis, pbuf->pb_info.pi_nnis); + curnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); + addnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); + delnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); + if (!curnis || !addnis || !delnis) { + rc = -ENOMEM; + goto out; + } + ncurnis = 0; + naddnis = 0; + ndelnis = 0; + + /* Construct the list of NIDs present in peer. */ + lpni = NULL; + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) + curnis[ncurnis++] = lpni->lpni_nid; + + /* + * Check for NIDs in pbuf not present in curnis[]. + * The loop starts at 1 to skip the loopback NID. + */ + for (i = 1; i < pbuf->pb_info.pi_nnis; i++) { + for (j = 0; j < ncurnis; j++) + if (pbuf->pb_info.pi_ni[i].ns_nid == curnis[j]) + break; + if (j == ncurnis) + addnis[naddnis++] = pbuf->pb_info.pi_ni[i].ns_nid; + } + /* + * Check for NIDs in curnis[] not present in pbuf. + * The nested loop starts at 1 to skip the loopback NID. + * + * But never add the loopback NID to delnis[]: if it is + * present in curnis[] then this peer is for this node. + */ + for (i = 0; i < ncurnis; i++) { + if (LNET_NETTYP(LNET_NIDNET(curnis[i])) == LOLND) + continue; + for (j = 1; j < pbuf->pb_info.pi_nnis; j++) + if (curnis[i] == pbuf->pb_info.pi_ni[j].ns_nid) + break; + if (j == pbuf->pb_info.pi_nnis) + delnis[ndelnis++] = curnis[i]; + } + + for (i = 0; i < naddnis; i++) { + rc = lnet_peer_add_nid(lp, addnis[i], flags); + if (rc) { + CERROR("Error adding NID %s to peer %s: %d\n", + libcfs_nid2str(addnis[i]), + libcfs_nid2str(lp->lp_primary_nid), rc); + if (rc == -ENOMEM) + goto out; + } + } + for (i = 0; i < ndelnis; i++) { + rc = lnet_peer_del_nid(lp, delnis[i], flags); + if (rc) { + CERROR("Error deleting NID %s from peer %s: %d\n", + libcfs_nid2str(delnis[i]), + libcfs_nid2str(lp->lp_primary_nid), rc); + if (rc == -ENOMEM) + goto out; + } + } + /* + * Errors other than -ENOMEM are due to peers having been + * configured with DLC. Ignore these because DLC overrides + * Discovery. + */ + rc = 0; +out: + kfree(curnis); + kfree(addnis); + kfree(delnis); + lnet_ping_buffer_decref(pbuf); + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); + + if (rc) { + spin_lock(&lp->lp_lock); + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + lp->lp_state |= LNET_PEER_FORCE_PING; + spin_unlock(&lp->lp_lock); + } + return rc; +} + +/* + * The data in pbuf says lp is its primary peer, but the data was + * received by a different peer. Try to update lp with the data. + */ +static int +lnet_peer_set_primary_data(struct lnet_peer *lp, struct lnet_ping_buffer *pbuf) +{ + struct lnet_handle_md mdh; + + /* Queue lp for discovery, and force it on the request queue. */ + lnet_net_lock(LNET_LOCK_EX); + if (lnet_peer_queue_for_discovery(lp)) + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_request); + lnet_net_unlock(LNET_LOCK_EX); + + LNetInvalidateMDHandle(&mdh); + + /* + * Decide whether we can move the peer to the DATA_PRESENT state. + * + * We replace stale data for a multi-rail peer, repair PING_FAILED + * status, and preempt FORCE_PING. + * + * If after that we have DATA_PRESENT, we merge it into this peer. + */ + spin_lock(&lp->lp_lock); + if (lp->lp_state & LNET_PEER_MULTI_RAIL) { + if (lp->lp_peer_seqno < LNET_PING_BUFFER_SEQNO(pbuf)) { + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); + } else if (lp->lp_state & LNET_PEER_DATA_PRESENT) { + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; + lnet_ping_buffer_decref(pbuf); + pbuf = lp->lp_data; + lp->lp_data = NULL; + } + } + if (lp->lp_state & LNET_PEER_DATA_PRESENT) { + lnet_ping_buffer_decref(lp->lp_data); + lp->lp_data = NULL; + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; + } + if (lp->lp_state & LNET_PEER_PING_FAILED) { + mdh = lp->lp_ping_mdh; + LNetInvalidateMDHandle(&lp->lp_ping_mdh); + lp->lp_state &= ~LNET_PEER_PING_FAILED; + lp->lp_ping_error = 0; + } + if (lp->lp_state & LNET_PEER_FORCE_PING) + lp->lp_state &= ~LNET_PEER_FORCE_PING; + lp->lp_state |= LNET_PEER_NIDS_UPTODATE; + spin_unlock(&lp->lp_lock); + + if (!LNetMDHandleIsInvalid(mdh)) + LNetMDUnlink(mdh); + + if (pbuf) + return lnet_peer_merge_data(lp, pbuf); + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + return 0; +} + +/* + * Update a peer using the data received. + */ +static int lnet_peer_data_present(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + struct lnet_ping_buffer *pbuf; + struct lnet_peer_ni *lpni; + lnet_nid_t nid = LNET_NID_ANY; + unsigned int flags; + int rc = 0; + + pbuf = lp->lp_data; + lp->lp_data = NULL; + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; + lp->lp_state |= LNET_PEER_NIDS_UPTODATE; + spin_unlock(&lp->lp_lock); + + /* + * Modifications of peer structures are done while holding the + * ln_api_mutex. A global lock is required because we may be + * modifying multiple peer structures, and a mutex greatly + * simplifies memory management. + * + * The actual changes to the data structures must also protect + * against concurrent lookups, for which the lnet_net_lock in + * LNET_LOCK_EX mode is used. + */ + mutex_lock(&the_lnet.ln_api_mutex); + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { + rc = -ESHUTDOWN; + goto out; + } + + /* + * If this peer is not on the peer list then it is being torn + * down, and our reference count may be all that is keeping it + * alive. Don't do any work on it. + */ + if (list_empty(&lp->lp_peer_list)) + goto out; + + flags = LNET_PEER_DISCOVERED; + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) + flags |= LNET_PEER_MULTI_RAIL; + + /* + * Check whether the primary NID in the message matches the + * primary NID of the peer. If it does, update the peer, if + * it it does not, check whether there is already a peer with + * that primary NID. If no such peer exists, try to update + * the primary NID of the current peer (allowed if it was + * created due to message traffic) and complete the update. + * If the peer did exist, hand off the data to it. + * + * The peer for the loopback interface is a special case: this + * is the peer for the local node, and we want to set its + * primary NID to the correct value here. + */ + if (pbuf->pb_info.pi_nnis > 1) + nid = pbuf->pb_info.pi_ni[1].ns_nid; + if (LNET_NETTYP(LNET_NIDNET(lp->lp_primary_nid)) == LOLND) { + rc = lnet_peer_set_primary_nid(lp, nid, flags); + if (!rc) + rc = lnet_peer_merge_data(lp, pbuf); + } else if (lp->lp_primary_nid == nid) { + rc = lnet_peer_merge_data(lp, pbuf); + } else { + lpni = lnet_find_peer_ni_locked(nid); + if (!lpni) { + rc = lnet_peer_set_primary_nid(lp, nid, flags); + if (rc) { + CERROR("Primary NID error %s versus %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), + libcfs_nid2str(nid), rc); + } else { + rc = lnet_peer_merge_data(lp, pbuf); + } + } else { + rc = lnet_peer_set_primary_data( + lpni->lpni_peer_net->lpn_peer, pbuf); + lnet_peer_ni_decref_locked(lpni); + } + } +out: + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); + mutex_unlock(&the_lnet.ln_api_mutex); + + spin_lock(&lp->lp_lock); + /* Tell discovery to re-check the peer immediately. */ + if (!rc) + rc = LNET_REDISCOVER_PEER; + return rc; +} + +/* + * A ping failed. Clear the PING_FAILED state and set the + * FORCE_PING state, to ensure a retry even if discovery is + * disabled. This avoids being left with incorrect state. + */ +static int lnet_peer_ping_failed(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + struct lnet_handle_md mdh; + int rc; + + mdh = lp->lp_ping_mdh; + LNetInvalidateMDHandle(&lp->lp_ping_mdh); + lp->lp_state &= ~LNET_PEER_PING_FAILED; + lp->lp_state |= LNET_PEER_FORCE_PING; + rc = lp->lp_ping_error; + lp->lp_ping_error = 0; + spin_unlock(&lp->lp_lock); + + if (!LNetMDHandleIsInvalid(mdh)) + LNetMDUnlink(mdh); + + CDEBUG(D_NET, "peer %s:%d\n", + libcfs_nid2str(lp->lp_primary_nid), rc); + + spin_lock(&lp->lp_lock); + return rc ? rc : LNET_REDISCOVER_PEER; +} + +/* + * Select NID to send a Ping or Push to. + */ +static lnet_nid_t lnet_peer_select_nid(struct lnet_peer *lp) +{ + struct lnet_peer_ni *lpni; + + /* Look for a direct-connected NID for this peer. */ + lpni = NULL; + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { + if (!lnet_is_peer_ni_healthy_locked(lpni)) + continue; + if (!lnet_get_net_locked(lpni->lpni_peer_net->lpn_net_id)) + continue; + break; + } + if (lpni) + return lpni->lpni_nid; + + /* Look for a routed-connected NID for this peer. */ + lpni = NULL; + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { + if (!lnet_is_peer_ni_healthy_locked(lpni)) + continue; + if (!lnet_find_rnet_locked(lpni->lpni_peer_net->lpn_net_id)) + continue; + break; + } + if (lpni) + return lpni->lpni_nid; + + return LNET_NID_ANY; +} + +/* Active side of ping. */ +static int lnet_peer_send_ping(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + struct lnet_md md = { NULL }; + struct lnet_process_id id; + struct lnet_ping_buffer *pbuf; + int nnis; + int rc; + int cpt; + + lp->lp_state |= LNET_PEER_PING_SENT; + lp->lp_state &= ~LNET_PEER_FORCE_PING; + spin_unlock(&lp->lp_lock); + + nnis = max_t(int, lp->lp_data_nnis, LNET_INTERFACES_MIN); + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); + if (!pbuf) { + rc = -ENOMEM; + goto fail_error; + } + + /* initialize md content */ + md.start = &pbuf->pb_info; + md.length = LNET_PING_INFO_SIZE(nnis); + md.threshold = 2; /* GET/REPLY */ + md.max_size = 0; + md.options = LNET_MD_TRUNCATE; + md.user_ptr = lp; + md.eq_handle = the_lnet.ln_dc_eqh; + + rc = LNetMDBind(md, LNET_UNLINK, &lp->lp_ping_mdh); + if (rc != 0) { + lnet_ping_buffer_decref(pbuf); + CERROR("Can't bind MD: %d\n", rc); + goto fail_error; + } + cpt = lnet_net_lock_current(); + /* Refcount for MD. */ + lnet_peer_addref_locked(lp); + id.pid = LNET_PID_LUSTRE; + id.nid = lnet_peer_select_nid(lp); + lnet_net_unlock(cpt); + + if (id.nid == LNET_NID_ANY) { + rc = -EHOSTUNREACH; + goto fail_unlink_md; + } + + rc = LNetGet(LNET_NID_ANY, lp->lp_ping_mdh, id, + LNET_RESERVED_PORTAL, + LNET_PROTO_PING_MATCHBITS, 0); + + if (rc) + goto fail_unlink_md; + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + + spin_lock(&lp->lp_lock); + return 0; + +fail_unlink_md: + LNetMDUnlink(lp->lp_ping_mdh); + LNetInvalidateMDHandle(&lp->lp_ping_mdh); +fail_error: + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); + /* + * The errors that get us here are considered hard errors and + * cause Discovery to terminate. So we clear PING_SENT, but do + * not set either PING_FAILED or FORCE_PING. In fact we need + * to clear PING_FAILED, because the unlink event handler will + * have set it if we called LNetMDUnlink() above. + */ + spin_lock(&lp->lp_lock); + lp->lp_state &= ~(LNET_PEER_PING_SENT | LNET_PEER_PING_FAILED); + return rc; +} + +/* + * This function exists because you cannot call LNetMDUnlink() from an + * event handler. + */ +static int lnet_peer_push_failed(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + struct lnet_handle_md mdh; + int rc; + + mdh = lp->lp_push_mdh; + LNetInvalidateMDHandle(&lp->lp_push_mdh); + lp->lp_state &= ~LNET_PEER_PUSH_FAILED; + rc = lp->lp_push_error; + lp->lp_push_error = 0; + spin_unlock(&lp->lp_lock); + + if (!LNetMDHandleIsInvalid(mdh)) + LNetMDUnlink(mdh); + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + spin_lock(&lp->lp_lock); + return rc ? rc : LNET_REDISCOVER_PEER; +} + +/* Active side of push. */ +static int lnet_peer_send_push(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + struct lnet_ping_buffer *pbuf; + struct lnet_process_id id; + struct lnet_md md; + int cpt; + int rc; + + /* Don't push to a non-multi-rail peer. */ + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { + lp->lp_state &= ~LNET_PEER_FORCE_PUSH; + return 0; + } + + lp->lp_state |= LNET_PEER_PUSH_SENT; + lp->lp_state &= ~LNET_PEER_FORCE_PUSH; + spin_unlock(&lp->lp_lock); + + cpt = lnet_net_lock_current(); + pbuf = the_lnet.ln_ping_target; + lnet_ping_buffer_addref(pbuf); + lnet_net_unlock(cpt); + + /* Push source MD */ + md.start = &pbuf->pb_info; + md.length = LNET_PING_INFO_SIZE(pbuf->pb_nnis); + md.threshold = 2; /* Put/Ack */ + md.max_size = 0; + md.options = 0; + md.eq_handle = the_lnet.ln_dc_eqh; + md.user_ptr = lp; + + rc = LNetMDBind(md, LNET_UNLINK, &lp->lp_push_mdh); + if (rc) { + lnet_ping_buffer_decref(pbuf); + CERROR("Can't bind push source MD: %d\n", rc); + goto fail_error; + } + cpt = lnet_net_lock_current(); + /* Refcount for MD. */ + lnet_peer_addref_locked(lp); + id.pid = LNET_PID_LUSTRE; + id.nid = lnet_peer_select_nid(lp); + lnet_net_unlock(cpt); + + if (id.nid == LNET_NID_ANY) { + rc = -EHOSTUNREACH; + goto fail_unlink; + } + + rc = LNetPut(LNET_NID_ANY, lp->lp_push_mdh, + LNET_ACK_REQ, id, LNET_RESERVED_PORTAL, + LNET_PROTO_PING_MATCHBITS, 0, 0); + + if (rc) + goto fail_unlink; + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + + spin_lock(&lp->lp_lock); + return 0; + +fail_unlink: + LNetMDUnlink(lp->lp_push_mdh); + LNetInvalidateMDHandle(&lp->lp_push_mdh); +fail_error: + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); + /* + * The errors that get us here are considered hard errors and + * cause Discovery to terminate. So we clear PUSH_SENT, but do + * not set PUSH_FAILED. In fact we need to clear PUSH_FAILED, + * because the unlink event handler will have set it if we + * called LNetMDUnlink() above. + */ + spin_lock(&lp->lp_lock); + lp->lp_state &= ~(LNET_PEER_PUSH_SENT | LNET_PEER_PUSH_FAILED); + return rc; +} + +/* + * An unrecoverable error was encountered during discovery. + * Set error status in peer and abort discovery. + */ +static void lnet_peer_discovery_error(struct lnet_peer *lp, int error) +{ + CDEBUG(D_NET, "Discovery error %s: %d\n", + libcfs_nid2str(lp->lp_primary_nid), error); + + spin_lock(&lp->lp_lock); + lp->lp_dc_error = error; + lp->lp_state &= ~LNET_PEER_DISCOVERING; + lp->lp_state |= LNET_PEER_REDISCOVER; + spin_unlock(&lp->lp_lock); +} + +/* + * Mark the peer as discovered. + */ +static int lnet_peer_discovered(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + lp->lp_state |= LNET_PEER_DISCOVERED; + lp->lp_state &= ~(LNET_PEER_DISCOVERING | + LNET_PEER_REDISCOVER); + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + + return 0; +} + +/* + * Mark the peer as to be rediscovered. + */ +static int lnet_peer_rediscover(struct lnet_peer *lp) +__must_hold(&lp->lp_lock) +{ + lp->lp_state |= LNET_PEER_REDISCOVER; + lp->lp_state &= ~LNET_PEER_DISCOVERING; + + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); + + return 0; +} + +/* + * Returns the first peer on the ln_dc_working queue if its timeout + * has expired. Takes the current time as an argument so as to not + * obsessively re-check the clock. The oldest discovery request will + * be at the head of the queue. + */ +static struct lnet_peer *lnet_peer_dc_timed_out(time64_t now) +{ + struct lnet_peer *lp; + + if (list_empty(&the_lnet.ln_dc_working)) + return NULL; + lp = list_first_entry(&the_lnet.ln_dc_working, + struct lnet_peer, lp_dc_list); + if (now < lp->lp_last_queued + DISCOVERY_TIMEOUT) + return NULL; + return lp; +} + +/* + * Discovering this peer is taking too long. Cancel any Ping or Push + * that discovery is waiting on by unlinking the relevant MDs. The + * lnet_discovery_event_handler() will proceed from here and complete + * the cleanup. + */ +static void lnet_peer_discovery_timeout(struct lnet_peer *lp) +{ + struct lnet_handle_md ping_mdh; + struct lnet_handle_md push_mdh; + + LNetInvalidateMDHandle(&ping_mdh); + LNetInvalidateMDHandle(&push_mdh); + + spin_lock(&lp->lp_lock); + if (lp->lp_state & LNET_PEER_PING_SENT) { + ping_mdh = lp->lp_ping_mdh; + LNetInvalidateMDHandle(&lp->lp_ping_mdh); + } + if (lp->lp_state & LNET_PEER_PUSH_SENT) { + push_mdh = lp->lp_push_mdh; + LNetInvalidateMDHandle(&lp->lp_push_mdh); + } + spin_unlock(&lp->lp_lock); + + if (!LNetMDHandleIsInvalid(ping_mdh)) + LNetMDUnlink(ping_mdh); + if (!LNetMDHandleIsInvalid(push_mdh)) + LNetMDUnlink(push_mdh); +} + +/* + * Wait for work to be queued or some other change that must be + * attended to. Returns non-zero if the discovery thread should shut + * down. + */ +static int lnet_peer_discovery_wait_for_work(void) +{ + int cpt; + int rc = 0; + + DEFINE_WAIT(wait); + + cpt = lnet_net_lock_current(); + for (;;) { + prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, + TASK_IDLE); + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + break; + if (lnet_push_target_resize_needed()) + break; + if (!list_empty(&the_lnet.ln_dc_request)) + break; + if (lnet_peer_dc_timed_out(ktime_get_real_seconds())) + break; + lnet_net_unlock(cpt); + + /* + * wakeup max every second to check if there are peers that + * have been stuck on the working queue for greater than + * the peer timeout. + */ + schedule_timeout(HZ); + finish_wait(&the_lnet.ln_dc_waitq, &wait); + cpt = lnet_net_lock_current(); + } + finish_wait(&the_lnet.ln_dc_waitq, &wait); + + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) + rc = -ESHUTDOWN; + + lnet_net_unlock(cpt); + + CDEBUG(D_NET, "woken: %d\n", rc); + + return rc; +} + +/* The discovery thread. */ +static int lnet_peer_discovery(void *arg) +{ + struct lnet_peer *lp; + time64_t now; + int rc; + + CDEBUG(D_NET, "started\n"); + + for (;;) { + if (lnet_peer_discovery_wait_for_work()) break; if (lnet_push_target_resize_needed()) @@ -1719,33 +2984,97 @@ static int lnet_peer_discovery(void *arg) lnet_net_lock(LNET_LOCK_EX); if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) break; + + /* + * Process all incoming discovery work requests. When + * discovery must wait on a peer to change state, it + * is added to the tail of the ln_dc_working queue. A + * timestamp keeps track of when the peer was added, + * so we can time out discovery requests that take too + * long. + */ while (!list_empty(&the_lnet.ln_dc_request)) { lp = list_first_entry(&the_lnet.ln_dc_request, struct lnet_peer, lp_dc_list); list_move(&lp->lp_dc_list, &the_lnet.ln_dc_working); + /* + * set the time the peer was put on the dc_working + * queue. It shouldn't remain on the queue + * forever, in case the GET message (for ping) + * doesn't get a REPLY or the PUT message (for + * push) doesn't get an ACK. + * + * TODO: LNet Health will deal with this scenario + * in a generic way. + */ + lp->lp_last_queued = ktime_get_real_seconds(); lnet_net_unlock(LNET_LOCK_EX); - /* Just tag and release for now. */ + /* + * Select an action depending on the state of + * the peer and whether discovery is disabled. + * The check whether discovery is disabled is + * done after the code that handles processing + * for arrived data, cleanup for failures, and + * forcing a Ping or Push. + */ spin_lock(&lp->lp_lock); - if (lnet_peer_discovery_disabled) { - lp->lp_state |= LNET_PEER_REDISCOVER; - lp->lp_state &= ~(LNET_PEER_DISCOVERED | - LNET_PEER_NIDS_UPTODATE | - LNET_PEER_DISCOVERING); - } else { - lp->lp_state |= (LNET_PEER_DISCOVERED | - LNET_PEER_NIDS_UPTODATE); - lp->lp_state &= ~(LNET_PEER_REDISCOVER | - LNET_PEER_DISCOVERING); - } + CDEBUG(D_NET, "peer %s state %#x\n", + libcfs_nid2str(lp->lp_primary_nid), + lp->lp_state); + if (lp->lp_state & LNET_PEER_DATA_PRESENT) + rc = lnet_peer_data_present(lp); + else if (lp->lp_state & LNET_PEER_PING_FAILED) + rc = lnet_peer_ping_failed(lp); + else if (lp->lp_state & LNET_PEER_PUSH_FAILED) + rc = lnet_peer_push_failed(lp); + else if (lp->lp_state & LNET_PEER_FORCE_PING) + rc = lnet_peer_send_ping(lp); + else if (lp->lp_state & LNET_PEER_FORCE_PUSH) + rc = lnet_peer_send_push(lp); + else if (lnet_peer_discovery_disabled) + rc = lnet_peer_rediscover(lp); + else if (!(lp->lp_state & LNET_PEER_NIDS_UPTODATE)) + rc = lnet_peer_send_ping(lp); + else if (lnet_peer_needs_push(lp)) + rc = lnet_peer_send_push(lp); + else + rc = lnet_peer_discovered(lp); + CDEBUG(D_NET, "peer %s state %#x rc %d\n", + libcfs_nid2str(lp->lp_primary_nid), + lp->lp_state, rc); spin_unlock(&lp->lp_lock); lnet_net_lock(LNET_LOCK_EX); + if (rc == LNET_REDISCOVER_PEER) { + list_move(&lp->lp_dc_list, + &the_lnet.ln_dc_request); + } else if (rc) { + lnet_peer_discovery_error(lp, rc); + } if (!(lp->lp_state & LNET_PEER_DISCOVERING)) lnet_peer_discovery_complete(lp); if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) break; } + + /* + * Now that the ln_dc_request queue has been emptied + * check the ln_dc_working queue for peers that are + * taking too long. Move all that are found to the + * ln_dc_expired queue and time out any pending + * Ping or Push. We have to drop the lnet_net_lock + * in the loop because lnet_peer_discovery_timeout() + * calls LNetMDUnlink(). + */ + now = ktime_get_real_seconds(); + while ((lp = lnet_peer_dc_timed_out(now)) != NULL) { + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_expired); + lnet_net_unlock(LNET_LOCK_EX); + lnet_peer_discovery_timeout(lp); + lnet_net_lock(LNET_LOCK_EX); + } + lnet_net_unlock(LNET_LOCK_EX); } @@ -1759,23 +3088,28 @@ static int lnet_peer_discovery(void *arg) LNetEQFree(the_lnet.ln_dc_eqh); LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); + /* Queue cleanup 1: stop all pending pings and pushes. */ lnet_net_lock(LNET_LOCK_EX); - list_for_each_entry(lp, &the_lnet.ln_dc_request, lp_dc_list) { - spin_lock(&lp->lp_lock); - lp->lp_state |= LNET_PEER_REDISCOVER; - lp->lp_state &= ~(LNET_PEER_DISCOVERED | - LNET_PEER_DISCOVERING | - LNET_PEER_NIDS_UPTODATE); - spin_unlock(&lp->lp_lock); - lnet_peer_discovery_complete(lp); + while (!list_empty(&the_lnet.ln_dc_working)) { + lp = list_first_entry(&the_lnet.ln_dc_working, + struct lnet_peer, lp_dc_list); + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_expired); + lnet_net_unlock(LNET_LOCK_EX); + lnet_peer_discovery_timeout(lp); + lnet_net_lock(LNET_LOCK_EX); } - list_for_each_entry(lp, &the_lnet.ln_dc_working, lp_dc_list) { - spin_lock(&lp->lp_lock); - lp->lp_state |= LNET_PEER_REDISCOVER; - lp->lp_state &= ~(LNET_PEER_DISCOVERED | - LNET_PEER_DISCOVERING | - LNET_PEER_NIDS_UPTODATE); - spin_unlock(&lp->lp_lock); + lnet_net_unlock(LNET_LOCK_EX); + + /* Queue cleanup 2: wait for the expired queue to clear. */ + while (!list_empty(&the_lnet.ln_dc_expired)) + schedule_timeout_uninterruptible(HZ); + + /* Queue cleanup 3: clear the request queue. */ + lnet_net_lock(LNET_LOCK_EX); + while (!list_empty(&the_lnet.ln_dc_request)) { + lp = list_first_entry(&the_lnet.ln_dc_request, + struct lnet_peer, lp_dc_list); + lnet_peer_discovery_error(lp, -ESHUTDOWN); lnet_peer_discovery_complete(lp); } lnet_net_unlock(LNET_LOCK_EX); @@ -1797,10 +3131,6 @@ int lnet_peer_discovery_start(void) if (the_lnet.ln_dc_state != LNET_DC_STATE_SHUTDOWN) return -EALREADY; - INIT_LIST_HEAD(&the_lnet.ln_dc_request); - INIT_LIST_HEAD(&the_lnet.ln_dc_working); - init_waitqueue_head(&the_lnet.ln_dc_waitq); - rc = LNetEQAlloc(0, lnet_discovery_event_handler, &the_lnet.ln_dc_eqh); if (rc != 0) { CERROR("Can't allocate discovery EQ: %d\n", rc); @@ -1819,6 +3149,8 @@ int lnet_peer_discovery_start(void) the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; } + CDEBUG(D_NET, "discovery start: %d\n", rc); + return rc; } @@ -1837,6 +3169,9 @@ void lnet_peer_discovery_stop(void) LASSERT(list_empty(&the_lnet.ln_dc_request)); LASSERT(list_empty(&the_lnet.ln_dc_working)); + LASSERT(list_empty(&the_lnet.ln_dc_expired)); + + CDEBUG(D_NET, "discovery stopped\n"); } /* Debugging */ From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 19/24] lustre: lnet: add "lnetctl peer list" In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437828.16383.14376327105039832285.stgit@noble> From: Olaf Weber Add IOC_LIBCFS_GET_PEER_LIST to obtain a list of the primary NIDs of all peers known to the system. The list is written into a userspace buffer by the kernel. The typical usage is to make a first call to determine the required buffer size, then a second call to obtain the list. Extend the "lnetctl peer" set of commands with a "list" subcommand that uses this interface. Modify the IOC_LIBCFS_GET_PEER_NI ioctl (which is new in the Multi-Rail code) to use a NID to indicate the peer to look up, and then pass out the data for all NIDs of that peer. Re-implement "lnetctl peer show" to obtain the list of NIDs using IOC_LIBCFS_GET_PEER_LIST followed by one or more IOC_LIBCFS_GET_PEER_NI calls to get information for each peer. Make sure to copy the structure from kernel space to user space even if the ioctl handler returns an error. This is needed because if the buffer passed in by the user space is not big enough to copy the data, we want to pass the requested size to user space in the structure passed in. The return code in this case is -E2BIG. WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25790 Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 9 - .../staging/lustre/include/linux/lnet/lib-types.h | 3 .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 3 drivers/staging/lustre/lnet/lnet/api-ni.c | 30 ++- drivers/staging/lustre/lnet/lnet/peer.c | 222 +++++++++++++------- 5 files changed, 169 insertions(+), 98 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index f82a699371f2..58e3a9c4e39f 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -462,6 +462,8 @@ int lnet_get_rtr_pool_cfg(int idx, struct lnet_ioctl_pool_cfg *pool_cfg); struct lnet_ni *lnet_get_next_ni_locked(struct lnet_net *mynet, struct lnet_ni *prev); struct lnet_ni *lnet_get_ni_idx_locked(int idx); +int lnet_get_peer_list(__u32 *countp, __u32 *sizep, + struct lnet_process_id __user *ids); void lnet_router_debugfs_init(void); void lnet_router_debugfs_fini(void); @@ -730,10 +732,9 @@ bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); -int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, - bool *mr, - struct lnet_peer_ni_credit_info __user *peer_ni_info, - struct lnet_ioctl_element_stats __user *peer_ni_stats); +int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nid, + __u32 *nnis, bool *mr, __u32 *sizep, + void __user *bulk); int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, char alivness[LNET_MAX_STR_LEN], __u32 *cpt_iter, __u32 *refcount, diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 07baa86e61ab..8543a67420d7 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -651,7 +651,6 @@ struct lnet_peer_net { * pt_hash[...] * pt_peer_list * pt_peers - * pt_peer_nnids * protected by pt_zombie_lock: * pt_zombie_list * pt_zombies @@ -667,8 +666,6 @@ struct lnet_peer_table { struct list_head pt_peer_list; /* # peers */ int pt_peers; - /* # NIDS on listed peers */ - int pt_peer_nnids; /* # zombies to go to deathrow (and not there yet) */ int pt_zombies; /* zombie peers_ni */ diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h index 2a9beed23985..2607620e8ef8 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h @@ -144,6 +144,7 @@ struct libcfs_debug_ioctl_data { #define IOC_LIBCFS_GET_LOCAL_NI _IOWR(IOC_LIBCFS_TYPE, 97, IOCTL_CONFIG_SIZE) #define IOC_LIBCFS_SET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE) #define IOC_LIBCFS_GET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 99, IOCTL_CONFIG_SIZE) -#define IOC_LIBCFS_MAX_NR 99 +#define IOC_LIBCFS_GET_PEER_LIST _IOWR(IOC_LIBCFS_TYPE, 100, IOCTL_CONFIG_SIZE) +#define IOC_LIBCFS_MAX_NR 100 #endif /* __LIBCFS_IOCTL_H__ */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 955d1711eda4..f624abe7db80 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -3117,21 +3117,31 @@ LNetCtl(unsigned int cmd, void *arg) case IOC_LIBCFS_GET_PEER_NI: { struct lnet_ioctl_peer_cfg *cfg = arg; - struct lnet_peer_ni_credit_info __user *lpni_cri; - struct lnet_ioctl_element_stats __user *lpni_stats; - size_t usr_size = sizeof(*lpni_cri) + sizeof(*lpni_stats); - if ((cfg->prcfg_hdr.ioc_len != sizeof(*cfg)) || - (cfg->prcfg_size != usr_size)) + if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) return -EINVAL; - lpni_cri = cfg->prcfg_bulk; - lpni_stats = cfg->prcfg_bulk + sizeof(*lpni_cri); + mutex_lock(&the_lnet.ln_api_mutex); + rc = lnet_get_peer_info(&cfg->prcfg_prim_nid, + &cfg->prcfg_cfg_nid, + &cfg->prcfg_count, + &cfg->prcfg_mr, + &cfg->prcfg_size, + (void __user *)cfg->prcfg_bulk); + mutex_unlock(&the_lnet.ln_api_mutex); + return rc; + } + + case IOC_LIBCFS_GET_PEER_LIST: { + struct lnet_ioctl_peer_cfg *cfg = arg; + + if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) + return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_get_peer_info(cfg->prcfg_count, &cfg->prcfg_prim_nid, - &cfg->prcfg_cfg_nid, &cfg->prcfg_mr, - lpni_cri, lpni_stats); + rc = lnet_get_peer_list(&cfg->prcfg_count, &cfg->prcfg_size, + (struct lnet_process_id __user *) + cfg->prcfg_bulk); mutex_unlock(&the_lnet.ln_api_mutex); return rc; } diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 1ef4a44e752e..8dff3b767577 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -263,9 +263,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) /* Update peer NID count. */ lp = lpn->lpn_peer; - ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; lp->lp_nnis--; - ptable->pt_peer_nnids--; /* * If there are no more peer nets, make the peer unfindable @@ -277,6 +275,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) */ if (list_empty(&lp->lp_peer_nets)) { list_del_init(&lp->lp_peer_list); + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; ptable->pt_peers--; } else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) { /* Discovery isn't running, nothing to do here. */ @@ -637,44 +636,6 @@ lnet_find_peer(lnet_nid_t nid) return lp; } -struct lnet_peer_ni * -lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, - struct lnet_peer **lp) -{ - struct lnet_peer_table *ptable; - struct lnet_peer_ni *lpni; - int lncpt; - int cpt; - - lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); - - for (cpt = 0; cpt < lncpt; cpt++) { - ptable = the_lnet.ln_peer_tables[cpt]; - if (ptable->pt_peer_nnids > idx) - break; - idx -= ptable->pt_peer_nnids; - } - if (cpt >= lncpt) - return NULL; - - list_for_each_entry((*lp), &ptable->pt_peer_list, lp_peer_list) { - if ((*lp)->lp_nnis <= idx) { - idx -= (*lp)->lp_nnis; - continue; - } - list_for_each_entry((*lpn), &((*lp)->lp_peer_nets), - lpn_peer_nets) { - list_for_each_entry(lpni, &((*lpn)->lpn_peer_nis), - lpni_peer_nis) { - if (idx-- == 0) - return lpni; - } - } - } - - return NULL; -} - struct lnet_peer_ni * lnet_get_next_peer_ni_locked(struct lnet_peer *peer, struct lnet_peer_net *peer_net, @@ -734,6 +695,69 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, return lpni; } +/* Call with the ln_api_mutex held */ +int +lnet_get_peer_list(__u32 *countp, __u32 *sizep, + struct lnet_process_id __user *ids) +{ + struct lnet_process_id id; + struct lnet_peer_table *ptable; + struct lnet_peer *lp; + __u32 count = 0; + __u32 size = 0; + int lncpt; + int cpt; + __u32 i; + int rc; + + rc = -ESHUTDOWN; + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) + goto done; + + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); + + /* + * Count the number of peers, and return E2BIG if the buffer + * is too small. We'll also return the desired size. + */ + rc = -E2BIG; + for (cpt = 0; cpt < lncpt; cpt++) { + ptable = the_lnet.ln_peer_tables[cpt]; + count += ptable->pt_peers; + } + size = count * sizeof(*ids); + if (size > *sizep) + goto done; + + /* + * Walk the peer lists and copy out the primary nids. + * This is safe because the peer lists are only modified + * while the ln_api_mutex is held. So we don't need to + * hold the lnet_net_lock as well, and can therefore + * directly call copy_to_user(). + */ + rc = -EFAULT; + memset(&id, 0, sizeof(id)); + id.pid = LNET_PID_LUSTRE; + i = 0; + for (cpt = 0; cpt < lncpt; cpt++) { + ptable = the_lnet.ln_peer_tables[cpt]; + list_for_each_entry(lp, &ptable->pt_peer_list, lp_peer_list) { + if (i >= count) + goto done; + id.nid = lp->lp_primary_nid; + if (copy_to_user(&ids[i], &id, sizeof(id))) + goto done; + i++; + } + } + rc = 0; +done: + *countp = count; + *sizep = size; + return rc; +} + /* * Start pushes to peers that need to be updated for a configuration * change on this node. @@ -1128,7 +1152,6 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, spin_unlock(&lp->lp_lock); lp->lp_nnis++; - the_lnet.ln_peer_tables[lp->lp_cpt]->pt_peer_nnids++; lnet_net_unlock(LNET_LOCK_EX); CDEBUG(D_NET, "peer %s NID %s flags %#x\n", @@ -3273,55 +3296,94 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, } /* ln_api_mutex is held, which keeps the peer list stable */ -int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, - bool *mr, - struct lnet_peer_ni_credit_info __user *peer_ni_info, - struct lnet_ioctl_element_stats __user *peer_ni_stats) +int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, + __u32 *nnis, bool *mr, __u32 *sizep, + void __user *bulk) { - struct lnet_ioctl_element_stats ni_stats; - struct lnet_peer_ni_credit_info ni_info; - struct lnet_peer_ni *lpni = NULL; - struct lnet_peer_net *lpn = NULL; - struct lnet_peer *lp = NULL; + struct lnet_ioctl_element_stats *lpni_stats; + struct lnet_peer_ni_credit_info *lpni_info; + struct lnet_peer_ni *lpni; + struct lnet_peer *lp; + lnet_nid_t nid; + __u32 size; int rc; - lpni = lnet_get_peer_ni_idx_locked(idx, &lpn, &lp); + lp = lnet_find_peer(*primary_nid); - if (!lpni) - return -ENOENT; + if (!lp) { + rc = -ENOENT; + goto out; + } + + size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats); + size *= lp->lp_nnis; + if (size > *sizep) { + *sizep = size; + rc = -E2BIG; + goto out_lp_decref; + } *primary_nid = lp->lp_primary_nid; *mr = lnet_peer_is_multi_rail(lp); - *nid = lpni->lpni_nid; - snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, "NA"); - if (lnet_isrouter(lpni) || - lnet_peer_aliveness_enabled(lpni)) - snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, - lpni->lpni_alive ? "up" : "down"); - - ni_info.cr_refcount = atomic_read(&lpni->lpni_refcount); - ni_info.cr_ni_peer_tx_credits = lpni->lpni_net ? - lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0; - ni_info.cr_peer_tx_credits = lpni->lpni_txcredits; - ni_info.cr_peer_rtr_credits = lpni->lpni_rtrcredits; - ni_info.cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits; - ni_info.cr_peer_min_tx_credits = lpni->lpni_mintxcredits; - ni_info.cr_peer_tx_qnob = lpni->lpni_txqnob; - - ni_stats.iel_send_count = atomic_read(&lpni->lpni_stats.send_count); - ni_stats.iel_recv_count = atomic_read(&lpni->lpni_stats.recv_count); - ni_stats.iel_drop_count = atomic_read(&lpni->lpni_stats.drop_count); - - /* If copy_to_user fails */ - rc = -EFAULT; - if (copy_to_user(peer_ni_info, &ni_info, sizeof(ni_info))) - goto copy_failed; + *nidp = lp->lp_primary_nid; + *nnis = lp->lp_nnis; + *sizep = size; - if (copy_to_user(peer_ni_stats, &ni_stats, sizeof(ni_stats))) - goto copy_failed; + /* Allocate helper buffers. */ + rc = -ENOMEM; + lpni_info = kzalloc(sizeof(*lpni_info), GFP_KERNEL); + if (!lpni_info) + goto out_lp_decref; + lpni_stats = kzalloc(sizeof(*lpni_stats), GFP_KERNEL); + if (!lpni_stats) + goto out_free_info; + lpni = NULL; + rc = -EFAULT; + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { + nid = lpni->lpni_nid; + if (copy_to_user(bulk, &nid, sizeof(nid))) + goto out_free_stats; + bulk += sizeof(nid); + + memset(lpni_info, 0, sizeof(*lpni_info)); + snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN, "NA"); + if (lnet_isrouter(lpni) || + lnet_peer_aliveness_enabled(lpni)) + snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN, + lpni->lpni_alive ? "up" : "down"); + + lpni_info->cr_refcount = atomic_read(&lpni->lpni_refcount); + lpni_info->cr_ni_peer_tx_credits = lpni->lpni_net ? + lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0; + lpni_info->cr_peer_tx_credits = lpni->lpni_txcredits; + lpni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits; + lpni_info->cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits; + lpni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits; + lpni_info->cr_peer_tx_qnob = lpni->lpni_txqnob; + if (copy_to_user(bulk, lpni_info, sizeof(*lpni_info))) + goto out_free_stats; + bulk += sizeof(*lpni_info); + + memset(lpni_stats, 0, sizeof(*lpni_stats)); + lpni_stats->iel_send_count = + atomic_read(&lpni->lpni_stats.send_count); + lpni_stats->iel_recv_count = + atomic_read(&lpni->lpni_stats.recv_count); + lpni_stats->iel_drop_count = + atomic_read(&lpni->lpni_stats.drop_count); + if (copy_to_user(bulk, lpni_stats, sizeof(*lpni_stats))) + goto out_free_stats; + bulk += sizeof(*lpni_stats); + } rc = 0; -copy_failed: +out_free_stats: + kfree(lpni_stats); +out_free_info: + kfree(lpni_info); +out_lp_decref: + lnet_peer_decref_locked(lp); +out: return rc; } From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 20/24] lustre: lnet: add "lnetctl ping" command In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437832.16383.822062330627071137.stgit@noble> From: Olaf Weber Adds function jt_ping() in lnetctl.c and lustre_lnet_ping_nid() in liblnetconfig.c file. The output of "lnetctl ping" is similar to "lnetctl peer show". Function jt_ping() in lnetctl.c calls lustre_lnet_ping_nid() to implement "lnetctl ping". Adds a function infra_ping_nid() to be later reused for the ping similar lnetctl commands. Uses a new ioctl call, IOC_LIBCFS_PING_PEER for "lnetctl ping". With "lnetctl ping", multiple nids can be pinged. Uses a new struct(lnet_ioctl_ping_data in lib-dlc.h) to pass the data from kernel to user space for ping. Also changes lnet_ping() function and its input parameters in drivers/staging/lustre/lnet/lnet/api-ni.c WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Sonia Sharma Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25791 Reviewed-by: Amir Shehata Tested-by: Amir Shehata Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 5 +- .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 2 - .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 2 - .../lustre/lnet/klnds/socklnd/socklnd_modparams.c | 2 - drivers/staging/lustre/lnet/lnet/api-ni.c | 55 +++++++++++++++----- drivers/staging/lustre/lnet/lnet/peer.c | 2 - 6 files changed, 47 insertions(+), 21 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 58e3a9c4e39f..adb4d0551ef5 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -76,8 +76,8 @@ extern struct lnet the_lnet; /* THE network */ #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 -/* Discovery timeout - same as default peer_timeout */ -#define DISCOVERY_TIMEOUT 180 +/* default timeout */ +#define DEFAULT_PEER_TIMEOUT 180 static inline int lnet_is_route_alive(struct lnet_route *route) { @@ -716,6 +716,7 @@ struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt); struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); +struct lnet_peer *lnet_find_peer(lnet_nid_t nid); void lnet_peer_net_added(struct lnet_net *net); lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block); diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h index 2607620e8ef8..3d89202bd396 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h @@ -102,7 +102,7 @@ struct libcfs_debug_ioctl_data { #define IOC_LIBCFS_CONFIGURE _IOWR('e', 59, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_TESTPROTOCOMPAT _IOWR('e', 60, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_PING _IOWR('e', 61, IOCTL_LIBCFS_TYPE) -/* IOC_LIBCFS_DEBUG_PEER _IOWR('e', 62, IOCTL_LIBCFS_TYPE) */ +#define IOC_LIBCFS_PING_PEER _IOWR('e', 62, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_LNETST _IOWR('e', 63, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_LNET_FAULT _IOWR('e', 64, IOCTL_LIBCFS_TYPE) /* lnd ioctls */ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index 0f2ad9110dc9..13b19f3eabf0 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -83,7 +83,7 @@ static int peer_buffer_credits; module_param(peer_buffer_credits, int, 0444); MODULE_PARM_DESC(peer_buffer_credits, "# per-peer router buffer credits"); -static int peer_timeout = 180; +static int peer_timeout = DEFAULT_PEER_TIMEOUT; module_param(peer_timeout, int, 0444); MODULE_PARM_DESC(peer_timeout, "Seconds without aliveness news to declare peer dead (<=0 to disable)"); diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c index 5663a4ca94d4..da5910049fc1 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c @@ -35,7 +35,7 @@ static int peer_buffer_credits; module_param(peer_buffer_credits, int, 0444); MODULE_PARM_DESC(peer_buffer_credits, "# per-peer router buffer credits"); -static int peer_timeout = 180; +static int peer_timeout = DEFAULT_PEER_TIMEOUT; module_param(peer_timeout, int, 0444); MODULE_PARM_DESC(peer_timeout, "Seconds without aliveness news to declare peer dead (<=0 to disable)"); diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index f624abe7db80..37f47bd1511f 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -3181,24 +3181,50 @@ LNetCtl(unsigned int cmd, void *arg) id.nid = data->ioc_nid; id.pid = data->ioc_u32[0]; - /* Don't block longer than 2 minutes */ - if (data->ioc_u32[1] > 120 * MSEC_PER_SEC) - return -EINVAL; - - /* If timestamp is negative then disable timeout */ - if ((s32)data->ioc_u32[1] < 0) - timeout = MAX_SCHEDULE_TIMEOUT; + /* If timeout is negative then set default of 3 minutes */ + if (((s32)data->ioc_u32[1] <= 0) || + data->ioc_u32[1] > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC)) + timeout = DEFAULT_PEER_TIMEOUT * HZ; else timeout = msecs_to_jiffies(data->ioc_u32[1]); rc = lnet_ping(id, timeout, data->ioc_pbuf1, data->ioc_plen1 / sizeof(struct lnet_process_id)); + if (rc < 0) return rc; + data->ioc_count = rc; return 0; } + case IOC_LIBCFS_PING_PEER: { + struct lnet_ioctl_ping_data *ping = arg; + struct lnet_peer *lp; + signed long timeout; + + /* If timeout is negative then set default of 3 minutes */ + if (((s32)ping->op_param) <= 0 || + ping->op_param > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC)) + timeout = DEFAULT_PEER_TIMEOUT * HZ; + else + timeout = msecs_to_jiffies(ping->op_param); + + rc = lnet_ping(ping->ping_id, timeout, + ping->ping_buf, + ping->ping_count); + if (rc < 0) + return rc; + + lp = lnet_find_peer(ping->ping_id.nid); + if (lp) { + ping->ping_id.nid = lp->lp_primary_nid; + ping->mr_info = lnet_peer_is_multi_rail(lp); + } + ping->ping_count = rc; + return 0; + } + default: ni = lnet_net2ni_addref(data->ioc_net); if (!ni) @@ -3301,7 +3327,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, /* initialize md content */ md.start = &pbuf->pb_info; md.length = LNET_PING_INFO_SIZE(n_ids); - md.threshold = 2; /*GET/REPLY*/ + md.threshold = 2; /* GET/REPLY */ md.max_size = 0; md.options = LNET_MD_TRUNCATE; md.user_ptr = NULL; @@ -3319,7 +3345,6 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, if (rc) { /* Don't CERROR; this could be deliberate! */ - rc2 = LNetMDUnlink(mdh); LASSERT(!rc2); @@ -3363,7 +3388,6 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, replied = 1; rc = event.mlength; } - } while (rc2 <= 0 || !event.unlinked); if (!replied) { @@ -3377,10 +3401,9 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, nob = rc; LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids)); - rc = -EPROTO; /* if I can't parse... */ + rc = -EPROTO; /* if I can't parse... */ if (nob < 8) { - /* can't check magic/version */ CERROR("%s: ping info too short %d\n", libcfs_id2str(id), nob); goto fail_free_eq; @@ -3401,7 +3424,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, } if (nob < LNET_PING_INFO_SIZE(0)) { - CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), + CERROR("%s: Short reply %d(%d min)\n", + libcfs_id2str(id), nob, (int)LNET_PING_INFO_SIZE(0)); goto fail_free_eq; } @@ -3410,12 +3434,13 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, n_ids = pbuf->pb_info.pi_nnis; if (nob < LNET_PING_INFO_SIZE(n_ids)) { - CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), + CERROR("%s: Short reply %d(%d expected)\n", + libcfs_id2str(id), nob, (int)LNET_PING_INFO_SIZE(n_ids)); goto fail_free_eq; } - rc = -EFAULT; /* If I SEGV... */ + rc = -EFAULT; /* if I segv in copy_to_user()... */ memset(&tmpid, 0, sizeof(tmpid)); for (i = 0; i < n_ids; i++) { diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 8dff3b767577..95f72ae39a89 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -2905,7 +2905,7 @@ static struct lnet_peer *lnet_peer_dc_timed_out(time64_t now) return NULL; lp = list_first_entry(&the_lnet.ln_dc_working, struct lnet_peer, lp_dc_list); - if (now < lp->lp_last_queued + DISCOVERY_TIMEOUT) + if (now < lp->lp_last_queued + DEFAULT_PEER_TIMEOUT) return NULL; return lp; } From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 21/24] lustre: lnet: add "lnetctl discover" In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437836.16383.17797958097457714365.stgit@noble> From: Sonia Sharma Add a "discover" subcommand to lnetctl jt_discover() in lnetctl.c calls lustre_lnet_discover_nid() to implement "lnetctl discover". The output is similar to "lnetctl ping" command. This patch also does some clean up in linlnetconfig.c For parameters under global settings, the common code for them is pulled in functions ioctl_set_value() and ioctl_show_global_values(). WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Sonia Sharma Signed-off-by: Amir Shehata Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25793 Signed-off-by: NeilBrown --- .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 2 drivers/staging/lustre/lnet/lnet/api-ni.c | 100 ++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h index 3d89202bd396..60bc9713923e 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h @@ -113,7 +113,7 @@ struct libcfs_debug_ioctl_data { #define IOC_LIBCFS_DEL_PEER _IOWR('e', 74, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_ADD_PEER _IOWR('e', 75, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_GET_PEER _IOWR('e', 76, IOCTL_LIBCFS_TYPE) -/* ioctl 77 is free for use */ +#define IOC_LIBCFS_DISCOVER _IOWR('e', 77, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_ADD_INTERFACE _IOWR('e', 78, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_DEL_INTERFACE _IOWR('e', 79, IOCTL_LIBCFS_TYPE) #define IOC_LIBCFS_GET_INTERFACE _IOWR('e', 80, IOCTL_LIBCFS_TYPE) diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 37f47bd1511f..0511c6acb9b1 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -104,6 +104,9 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); static int lnet_ping(struct lnet_process_id id, signed long timeout, struct lnet_process_id __user *ids, int n_ids); +static int lnet_discover(struct lnet_process_id id, __u32 force, + struct lnet_process_id __user *ids, int n_ids); + static int discovery_set(const char *val, const struct kernel_param *kp) { @@ -3225,6 +3228,25 @@ LNetCtl(unsigned int cmd, void *arg) return 0; } + case IOC_LIBCFS_DISCOVER: { + struct lnet_ioctl_ping_data *discover = arg; + struct lnet_peer *lp; + + rc = lnet_discover(discover->ping_id, discover->op_param, + discover->ping_buf, + discover->ping_count); + if (rc < 0) + return rc; + lp = lnet_find_peer(discover->ping_id.nid); + if (lp) { + discover->ping_id.nid = lp->lp_primary_nid; + discover->mr_info = lnet_peer_is_multi_rail(lp); + } + + discover->ping_count = rc; + return 0; + } + default: ni = lnet_net2ni_addref(data->ioc_net); if (!ni) @@ -3461,3 +3483,81 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, lnet_ping_buffer_decref(pbuf); return rc; } + +static int +lnet_discover(struct lnet_process_id id, __u32 force, + struct lnet_process_id __user *ids, + int n_ids) +{ + struct lnet_peer_ni *lpni; + struct lnet_peer_ni *p; + struct lnet_peer *lp; + struct lnet_process_id *buf; + int cpt; + int i; + int rc; + int max_intf = lnet_interfaces_max; + + if (n_ids <= 0 || + id.nid == LNET_NID_ANY || + n_ids > max_intf) + return -EINVAL; + + if (id.pid == LNET_PID_ANY) + id.pid = LNET_PID_LUSTRE; + + buf = kcalloc(n_ids, sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + cpt = lnet_net_lock_current(); + lpni = lnet_nid2peerni_locked(id.nid, LNET_NID_ANY, cpt); + if (IS_ERR(lpni)) { + rc = PTR_ERR(lpni); + goto out; + } + + /* + * Clearing the NIDS_UPTODATE flag ensures the peer will + * be discovered, provided discovery has not been disabled. + */ + lp = lpni->lpni_peer_net->lpn_peer; + spin_lock(&lp->lp_lock); + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; + /* If the force flag is set, force a PING and PUSH as well. */ + if (force) + lp->lp_state |= LNET_PEER_FORCE_PING | LNET_PEER_FORCE_PUSH; + spin_unlock(&lp->lp_lock); + rc = lnet_discover_peer_locked(lpni, cpt, true); + if (rc) + goto out_decref; + + /* Peer may have changed. */ + lp = lpni->lpni_peer_net->lpn_peer; + if (lp->lp_nnis < n_ids) + n_ids = lp->lp_nnis; + + i = 0; + p = NULL; + while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) { + buf[i].pid = id.pid; + buf[i].nid = p->lpni_nid; + if (++i >= n_ids) + break; + } + + lnet_net_unlock(cpt); + + rc = -EFAULT; + if (copy_to_user(ids, buf, n_ids * sizeof(*buf))) + goto out_relock; + rc = n_ids; +out_relock: + lnet_net_lock(cpt); +out_decref: + lnet_peer_ni_decref_locked(lpni); +out: + lnet_net_unlock(cpt); + kfree(buf); + return rc; +} From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 22/24] lustre: lnet: add enhanced statistics In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437840.16383.11395842984054958152.stgit@noble> From: Amir Shehata Added statistics to track the different types of LNet messages which are sent/received/dropped WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Amir Shehata Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/25795 Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 12 ++ .../staging/lustre/include/linux/lnet/lib-types.h | 20 +++ .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 3 - drivers/staging/lustre/lnet/lnet/api-ni.c | 45 +++++++- drivers/staging/lustre/lnet/lnet/lib-move.c | 116 +++++++++++++++++++- drivers/staging/lustre/lnet/lnet/lib-msg.c | 16 ++- drivers/staging/lustre/lnet/lnet/net_fault.c | 3 - drivers/staging/lustre/lnet/lnet/peer.c | 26 +++- 8 files changed, 217 insertions(+), 24 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index adb4d0551ef5..91980f60a50d 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -575,7 +575,7 @@ void lnet_set_reply_msg_len(struct lnet_ni *ni, struct lnet_msg *msg, void lnet_finalize(struct lnet_msg *msg, int rc); void lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, - unsigned int nob); + unsigned int nob, __u32 msg_type); void lnet_drop_delayed_msg_list(struct list_head *head, char *reason); void lnet_recv_delayed_msg_list(struct list_head *head); @@ -825,4 +825,14 @@ lnet_peer_needs_push(struct lnet_peer *lp) return false; } +void lnet_incr_stats(struct lnet_element_stats *stats, + enum lnet_msg_type msg_type, + enum lnet_stats_type stats_type); + +__u32 lnet_sum_stats(struct lnet_element_stats *stats, + enum lnet_stats_type stats_type); + +void lnet_usr_translate_stats(struct lnet_ioctl_element_msg_stats *msg_stats, + struct lnet_element_stats *stats); + #endif diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 8543a67420d7..19f7b11a1e44 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -279,10 +279,24 @@ enum lnet_ni_state { LNET_NI_STATE_DELETING }; +enum lnet_stats_type { + LNET_STATS_TYPE_SEND = 0, + LNET_STATS_TYPE_RECV, + LNET_STATS_TYPE_DROP +}; + +struct lnet_comm_count { + atomic_t co_get_count; + atomic_t co_put_count; + atomic_t co_reply_count; + atomic_t co_ack_count; + atomic_t co_hello_count; +}; + struct lnet_element_stats { - atomic_t send_count; - atomic_t recv_count; - atomic_t drop_count; + struct lnet_comm_count el_send_stats; + struct lnet_comm_count el_recv_stats; + struct lnet_comm_count el_drop_stats; }; struct lnet_net { diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h index 60bc9713923e..4590f65c333f 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h @@ -145,6 +145,7 @@ struct libcfs_debug_ioctl_data { #define IOC_LIBCFS_SET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE) #define IOC_LIBCFS_GET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 99, IOCTL_CONFIG_SIZE) #define IOC_LIBCFS_GET_PEER_LIST _IOWR(IOC_LIBCFS_TYPE, 100, IOCTL_CONFIG_SIZE) -#define IOC_LIBCFS_MAX_NR 100 +#define IOC_LIBCFS_GET_LOCAL_NI_MSG_STATS _IOWR(IOC_LIBCFS_TYPE, 101, IOCTL_CONFIG_SIZE) +#define IOC_LIBCFS_MAX_NR 101 #endif /* __LIBCFS_IOCTL_H__ */ diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 0511c6acb9b1..0852118bf803 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -2263,8 +2263,12 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni, memcpy(&tun->lt_cmn, &ni->ni_net->net_tunables, sizeof(tun->lt_cmn)); if (stats) { - stats->iel_send_count = atomic_read(&ni->ni_stats.send_count); - stats->iel_recv_count = atomic_read(&ni->ni_stats.recv_count); + stats->iel_send_count = lnet_sum_stats(&ni->ni_stats, + LNET_STATS_TYPE_SEND); + stats->iel_recv_count = lnet_sum_stats(&ni->ni_stats, + LNET_STATS_TYPE_RECV); + stats->iel_drop_count = lnet_sum_stats(&ni->ni_stats, + LNET_STATS_TYPE_DROP); } /* @@ -2491,6 +2495,29 @@ lnet_get_ni_config(struct lnet_ioctl_config_ni *cfg_ni, return rc; } +int lnet_get_ni_stats(struct lnet_ioctl_element_msg_stats *msg_stats) +{ + struct lnet_ni *ni; + int cpt; + int rc = -ENOENT; + + if (!msg_stats) + return -EINVAL; + + cpt = lnet_net_lock_current(); + + ni = lnet_get_ni_idx_locked(msg_stats->im_idx); + + if (ni) { + lnet_usr_translate_stats(msg_stats, &ni->ni_stats); + rc = 0; + } + + lnet_net_unlock(cpt); + + return rc; +} + static int lnet_add_net_common(struct lnet_net *net, struct lnet_ioctl_config_lnd_tunables *tun) { @@ -2956,6 +2983,7 @@ LNetCtl(unsigned int cmd, void *arg) __u32 tun_size; cfg_ni = arg; + /* get the tunables if they are available */ if (cfg_ni->lic_cfg_hdr.ioc_len < sizeof(*cfg_ni) + sizeof(*stats) + sizeof(*tun)) @@ -2975,6 +3003,19 @@ LNetCtl(unsigned int cmd, void *arg) return rc; } + case IOC_LIBCFS_GET_LOCAL_NI_MSG_STATS: { + struct lnet_ioctl_element_msg_stats *msg_stats = arg; + + if (msg_stats->im_hdr.ioc_len != sizeof(*msg_stats)) + return -EINVAL; + + mutex_lock(&the_lnet.ln_api_mutex); + rc = lnet_get_ni_stats(msg_stats); + mutex_unlock(&the_lnet.ln_api_mutex); + + return rc; + } + case IOC_LIBCFS_GET_NET: { size_t total = sizeof(*config) + sizeof(struct lnet_ioctl_net_config); diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c index 2ff329bf91ba..5694d85c713c 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-move.c +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c @@ -45,6 +45,104 @@ static int local_nid_dist_zero = 1; module_param(local_nid_dist_zero, int, 0444); MODULE_PARM_DESC(local_nid_dist_zero, "Reserved"); +static inline struct lnet_comm_count * +get_stats_counts(struct lnet_element_stats *stats, + enum lnet_stats_type stats_type) +{ + switch (stats_type) { + case LNET_STATS_TYPE_SEND: + return &stats->el_send_stats; + case LNET_STATS_TYPE_RECV: + return &stats->el_recv_stats; + case LNET_STATS_TYPE_DROP: + return &stats->el_drop_stats; + default: + CERROR("Unknown stats type\n"); + } + + return NULL; +} + +void lnet_incr_stats(struct lnet_element_stats *stats, + enum lnet_msg_type msg_type, + enum lnet_stats_type stats_type) +{ + struct lnet_comm_count *counts = get_stats_counts(stats, stats_type); + + if (!counts) + return; + + switch (msg_type) { + case LNET_MSG_ACK: + atomic_inc(&counts->co_ack_count); + break; + case LNET_MSG_PUT: + atomic_inc(&counts->co_put_count); + break; + case LNET_MSG_GET: + atomic_inc(&counts->co_get_count); + break; + case LNET_MSG_REPLY: + atomic_inc(&counts->co_reply_count); + break; + case LNET_MSG_HELLO: + atomic_inc(&counts->co_hello_count); + break; + default: + CERROR("There is a BUG in the code. Unknown message type\n"); + break; + } +} + +__u32 lnet_sum_stats(struct lnet_element_stats *stats, + enum lnet_stats_type stats_type) +{ + struct lnet_comm_count *counts = get_stats_counts(stats, stats_type); + + if (!counts) + return 0; + + return (atomic_read(&counts->co_ack_count) + + atomic_read(&counts->co_put_count) + + atomic_read(&counts->co_get_count) + + atomic_read(&counts->co_reply_count) + + atomic_read(&counts->co_hello_count)); +} + +static inline void assign_stats(struct lnet_ioctl_comm_count *msg_stats, + struct lnet_comm_count *counts) +{ + msg_stats->ico_get_count = atomic_read(&counts->co_get_count); + msg_stats->ico_put_count = atomic_read(&counts->co_put_count); + msg_stats->ico_reply_count = atomic_read(&counts->co_reply_count); + msg_stats->ico_ack_count = atomic_read(&counts->co_ack_count); + msg_stats->ico_hello_count = atomic_read(&counts->co_hello_count); +} + +void lnet_usr_translate_stats(struct lnet_ioctl_element_msg_stats *msg_stats, + struct lnet_element_stats *stats) +{ + struct lnet_comm_count *counts; + + LASSERT(msg_stats); + LASSERT(stats); + + counts = get_stats_counts(stats, LNET_STATS_TYPE_SEND); + if (!counts) + return; + assign_stats(&msg_stats->im_send_stats, counts); + + counts = get_stats_counts(stats, LNET_STATS_TYPE_RECV); + if (!counts) + return; + assign_stats(&msg_stats->im_recv_stats, counts); + + counts = get_stats_counts(stats, LNET_STATS_TYPE_DROP); + if (!counts) + return; + assign_stats(&msg_stats->im_drop_stats, counts); +} + int lnet_fail_nid(lnet_nid_t nid, unsigned int threshold) { @@ -632,9 +730,13 @@ lnet_post_send_locked(struct lnet_msg *msg, int do_send) the_lnet.ln_counters[cpt]->drop_length += msg->msg_len; lnet_net_unlock(cpt); if (msg->msg_txpeer) - atomic_inc(&msg->msg_txpeer->lpni_stats.drop_count); + lnet_incr_stats(&msg->msg_txpeer->lpni_stats, + msg->msg_type, + LNET_STATS_TYPE_DROP); if (msg->msg_txni) - atomic_inc(&msg->msg_txni->ni_stats.drop_count); + lnet_incr_stats(&msg->msg_txni->ni_stats, + msg->msg_type, + LNET_STATS_TYPE_DROP); CNETERR("Dropping message for %s: peer not alive\n", libcfs_id2str(msg->msg_target)); @@ -1859,9 +1961,11 @@ lnet_send(lnet_nid_t src_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid) } void -lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, unsigned int nob) +lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, unsigned int nob, + __u32 msg_type) { lnet_net_lock(cpt); + lnet_incr_stats(&ni->ni_stats, msg_type, LNET_STATS_TYPE_DROP); the_lnet.ln_counters[cpt]->drop_count++; the_lnet.ln_counters[cpt]->drop_length += nob; lnet_net_unlock(cpt); @@ -2510,7 +2614,7 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid, lnet_finalize(msg, rc); drop: - lnet_drop_message(ni, cpt, private, payload_length); + lnet_drop_message(ni, cpt, private, payload_length, type); return 0; } EXPORT_SYMBOL(lnet_parse); @@ -2546,7 +2650,8 @@ lnet_drop_delayed_msg_list(struct list_head *head, char *reason) * until that's done */ lnet_drop_message(msg->msg_rxni, msg->msg_rx_cpt, - msg->msg_private, msg->msg_len); + msg->msg_private, msg->msg_len, + msg->msg_type); /* * NB: message will not generate event because w/o attached MD, * but we still should give error code so lnet_msg_decommit() @@ -2786,6 +2891,7 @@ lnet_create_reply_msg(struct lnet_ni *ni, struct lnet_msg *getmsg) cpt = lnet_cpt_of_nid(peer_id.nid, ni); lnet_net_lock(cpt); + lnet_incr_stats(&ni->ni_stats, LNET_MSG_GET, LNET_STATS_TYPE_DROP); the_lnet.ln_counters[cpt]->drop_count++; the_lnet.ln_counters[cpt]->drop_length += getmd->md_length; lnet_net_unlock(cpt); diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c index db13d01d366f..7f58cfe25bc2 100644 --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c @@ -219,9 +219,13 @@ lnet_msg_decommit_tx(struct lnet_msg *msg, int status) incr_stats: if (msg->msg_txpeer) - atomic_inc(&msg->msg_txpeer->lpni_stats.send_count); + lnet_incr_stats(&msg->msg_txpeer->lpni_stats, + msg->msg_type, + LNET_STATS_TYPE_SEND); if (msg->msg_txni) - atomic_inc(&msg->msg_txni->ni_stats.send_count); + lnet_incr_stats(&msg->msg_txni->ni_stats, + msg->msg_type, + LNET_STATS_TYPE_SEND); out: lnet_return_tx_credits_locked(msg); msg->msg_tx_committed = 0; @@ -280,9 +284,13 @@ lnet_msg_decommit_rx(struct lnet_msg *msg, int status) incr_stats: if (msg->msg_rxpeer) - atomic_inc(&msg->msg_rxpeer->lpni_stats.recv_count); + lnet_incr_stats(&msg->msg_rxpeer->lpni_stats, + msg->msg_type, + LNET_STATS_TYPE_RECV); if (msg->msg_rxni) - atomic_inc(&msg->msg_rxni->ni_stats.recv_count); + lnet_incr_stats(&msg->msg_rxni->ni_stats, + msg->msg_type, + LNET_STATS_TYPE_RECV); if (ev->type == LNET_EVENT_PUT || ev->type == LNET_EVENT_REPLY) counters->recv_length += msg->msg_wanted; diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c index 3841bac1aa0a..e2c746855da9 100644 --- a/drivers/staging/lustre/lnet/lnet/net_fault.c +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c @@ -632,7 +632,8 @@ delayed_msg_process(struct list_head *msg_list, bool drop) } } - lnet_drop_message(ni, cpt, msg->msg_private, msg->msg_len); + lnet_drop_message(ni, cpt, msg->msg_private, msg->msg_len, + msg->msg_type); lnet_finalize(msg, rc); } } diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 95f72ae39a89..03c1c34517e4 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -3301,6 +3301,7 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, void __user *bulk) { struct lnet_ioctl_element_stats *lpni_stats; + struct lnet_ioctl_element_msg_stats *lpni_msg_stats; struct lnet_peer_ni_credit_info *lpni_info; struct lnet_peer_ni *lpni; struct lnet_peer *lp; @@ -3315,7 +3316,8 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, goto out; } - size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats); + size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats) + + sizeof(*lpni_msg_stats); size *= lp->lp_nnis; if (size > *sizep) { *sizep = size; @@ -3337,13 +3339,17 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, lpni_stats = kzalloc(sizeof(*lpni_stats), GFP_KERNEL); if (!lpni_stats) goto out_free_info; + lpni_msg_stats = kzalloc(sizeof(*lpni_msg_stats), GFP_KERNEL); + if (!lpni_msg_stats) + goto out_free_stats; + lpni = NULL; rc = -EFAULT; while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { nid = lpni->lpni_nid; if (copy_to_user(bulk, &nid, sizeof(nid))) - goto out_free_stats; + goto out_free_msg_stats; bulk += sizeof(nid); memset(lpni_info, 0, sizeof(*lpni_info)); @@ -3362,22 +3368,28 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, lpni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits; lpni_info->cr_peer_tx_qnob = lpni->lpni_txqnob; if (copy_to_user(bulk, lpni_info, sizeof(*lpni_info))) - goto out_free_stats; + goto out_free_msg_stats; bulk += sizeof(*lpni_info); memset(lpni_stats, 0, sizeof(*lpni_stats)); lpni_stats->iel_send_count = - atomic_read(&lpni->lpni_stats.send_count); + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_SEND); lpni_stats->iel_recv_count = - atomic_read(&lpni->lpni_stats.recv_count); + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_RECV); lpni_stats->iel_drop_count = - atomic_read(&lpni->lpni_stats.drop_count); + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_DROP); if (copy_to_user(bulk, lpni_stats, sizeof(*lpni_stats))) - goto out_free_stats; + goto out_free_msg_stats; bulk += sizeof(*lpni_stats); + lnet_usr_translate_stats(lpni_msg_stats, &lpni->lpni_stats); + if (copy_to_user(bulk, lpni_msg_stats, sizeof(*lpni_msg_stats))) + goto out_free_msg_stats; + bulk += sizeof(*lpni_msg_stats); } rc = 0; +out_free_msg_stats: + kfree(lpni_msg_stats); out_free_stats: kfree(lpni_stats); out_free_info: From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 23/24] lustre: lnet: show peer state In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437844.16383.527689917065770648.stgit@noble> From: Amir Shehata It is important to show the peer state when debugging. This patch exports the peer state from the kernel to user space, and is shown when the detail level requested in the peer show command is >= 3 WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 Signed-off-by: Amir Shehata Signed-off-by: Olaf Weber Reviewed-on: https://review.whamcloud.com/26130 Reviewed-by: Olaf Weber Reviewed-by: Dmitry Eremin Signed-off-by: NeilBrown --- .../staging/lustre/include/linux/lnet/lib-lnet.h | 4 +--- drivers/staging/lustre/lnet/lnet/api-ni.c | 6 +----- drivers/staging/lustre/lnet/lnet/peer.c | 21 ++++++++++---------- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h index 91980f60a50d..fcfd844e0162 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h @@ -733,9 +733,7 @@ bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); -int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nid, - __u32 *nnis, bool *mr, __u32 *sizep, - void __user *bulk); +int lnet_get_peer_info(struct lnet_ioctl_peer_cfg *cfg, void __user *bulk); int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, char alivness[LNET_MAX_STR_LEN], __u32 *cpt_iter, __u32 *refcount, diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c index 0852118bf803..e2c86b8279e5 100644 --- a/drivers/staging/lustre/lnet/lnet/api-ni.c +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c @@ -3166,11 +3166,7 @@ LNetCtl(unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&the_lnet.ln_api_mutex); - rc = lnet_get_peer_info(&cfg->prcfg_prim_nid, - &cfg->prcfg_cfg_nid, - &cfg->prcfg_count, - &cfg->prcfg_mr, - &cfg->prcfg_size, + rc = lnet_get_peer_info(cfg, (void __user *)cfg->prcfg_bulk); mutex_unlock(&the_lnet.ln_api_mutex); return rc; diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 03c1c34517e4..5f61fca09f44 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -3296,9 +3296,7 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, } /* ln_api_mutex is held, which keeps the peer list stable */ -int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, - __u32 *nnis, bool *mr, __u32 *sizep, - void __user *bulk) +int lnet_get_peer_info(struct lnet_ioctl_peer_cfg *cfg, void __user *bulk) { struct lnet_ioctl_element_stats *lpni_stats; struct lnet_ioctl_element_msg_stats *lpni_msg_stats; @@ -3309,7 +3307,7 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, __u32 size; int rc; - lp = lnet_find_peer(*primary_nid); + lp = lnet_find_peer(cfg->prcfg_prim_nid); if (!lp) { rc = -ENOENT; @@ -3319,17 +3317,18 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats) + sizeof(*lpni_msg_stats); size *= lp->lp_nnis; - if (size > *sizep) { - *sizep = size; + if (size > cfg->prcfg_size) { + cfg->prcfg_size = size; rc = -E2BIG; goto out_lp_decref; } - *primary_nid = lp->lp_primary_nid; - *mr = lnet_peer_is_multi_rail(lp); - *nidp = lp->lp_primary_nid; - *nnis = lp->lp_nnis; - *sizep = size; + cfg->prcfg_prim_nid = lp->lp_primary_nid; + cfg->prcfg_mr = lnet_peer_is_multi_rail(lp); + cfg->prcfg_cfg_nid = lp->lp_primary_nid; + cfg->prcfg_count = lp->lp_nnis; + cfg->prcfg_size = size; + cfg->prcfg_state = lp->lp_state; /* Allocate helper buffers. */ rc = -ENOMEM; From neilb at suse.com Sun Oct 7 23:19:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 08 Oct 2018 10:19:38 +1100 Subject: [lustre-devel] [PATCH 24/24] lustre: lnet: balance references in lnet_discover_peer_locked() In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <153895437848.16383.5882317080014923551.stgit@noble> From: John L. Hammond In lnet_discover_peer_locked() avoid a leaked reference to the peer in the non-blocking discovery case. WC-bug-id: https://jira.whamcloud.com/browse/LU-9913 Signed-off-by: John L. Hammond Reviewed-on: https://review.whamcloud.com/28695 Reviewed-by: Olaf Weber Reviewed-by: Quentin Bouget Reviewed-by: Oleg Drokin Signed-off-by: NeilBrown --- drivers/staging/lustre/lnet/lnet/peer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c index 5f61fca09f44..db36b5cf31e1 100644 --- a/drivers/staging/lustre/lnet/lnet/peer.c +++ b/drivers/staging/lustre/lnet/lnet/peer.c @@ -2010,7 +2010,6 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) if (lnet_peer_is_uptodate(lp)) break; lnet_peer_queue_for_discovery(lp); - lnet_peer_addref_locked(lp); /* * if caller requested a non-blocking operation then * return immediately. Once discovery is complete then the @@ -2019,6 +2018,8 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) */ if (!block) break; + + lnet_peer_addref_locked(lp); lnet_net_unlock(LNET_LOCK_EX); schedule(); finish_wait(&lp->lp_dc_waitq, &wait); From green at whamcloud.com Thu Oct 11 18:45:34 2018 From: green at whamcloud.com (Oleg Drokin) Date: Thu, 11 Oct 2018 18:45:34 +0000 Subject: [lustre-devel] New tag 2.11.56 Message-ID: Hello! I just tagged 2.11.56 in lustre master development branch. Here’s the changelog: Alex Zhuravlev (4): LU-11128 ptlrpc: new request vs disconnect race LU-11164 ldlm: pass env to lvbo methods LU-11420 mdt: export mdt_dom_read_open_fops LU-11375 mdc: use old statfs format Alexander Boyko (3): LU-11392 llog: fix race llog_process_thread vs llog_add LU-10806 target: skip discard for a missing obt_lut LU-10595 mgc: don't proccess cld during stopping Alexey Lyashkov (2): LU-11020 osd: use right sync LU-11169 obdclass: fix old return code usage Andreas Dilger (12): LU-11016 obdclass: change JobID error into warning LU-11303 out: clean up osp_update_rpc_pack() macro LU-10899 obdclass: remove unused ll_import_cachep LU-11128 ptlrpc: add debugging for idle connections LU-11329 utils: add get_maintainer.pl script LU-6864 mdc: move RPC semaphore code to lustre/osp LU-11237 build: delete obsolete slapd-lustre.conf LU-8616 utils: document specific MDT index selection LU-8174 misc: name open file handles as such LU-11111 lfsck: print correct parent FID LU-10899 osc: move obdo_cache to OSC code LU-11397 idl: remove obsolete RPC flags Arshad Hussain (2): LU-6142 obdclass: Fix style issues for obd_sysfs.c LU-6142 osd-ldiskfs: Fix style issues for osd_iam_lvar.c Bobi Jam (1): LU-11400 flr: add 'nosync' flag for FLR mirrors Gu Zheng (1): LU-11436 build: always dist debian stuff Hongchao Zhang (1): LU-11281 ptlrpc: race in AT early reply James Nunez (4): LU-9268 tests: check obj distribution for PFL striping LU-11010 tests: remove calls to return after skip() LU-11349 tests: remove insanity test 15 LU-11381 tests: sanity-flr 201 skip information James Simmons (13): LU-8066 llite: move /proc/fs/lustre/llite/stats_track* to sysfs LU-8066 llite: move /proc/fs/lustre/llite/statahead_{max, agl} to sysfs LU-8066 ofd: migrate from proc to sysfs LU-11071 build: create lustre resource package for Ubuntu LU-8066 llite: move /proc/fs/lustre/llite/lazystatfs to sysfs LU-8066 llite: move /proc/fs/lustre/llite/*_easize to sysfs LU-8066 llite: move /proc/fs/lustre/llite/xattr_cache to sysfs LU-10030 clio: don't use spare bits in iattr.ia_valid LU-10906 llite: create checksums to replace checksum_pages LU-11424 lnet: copy the correct amount of cpts to lnet_cpts LU-8066 llite: move remaining single item proc files to sysfs LU-11058 test: reenable sanity 77k test LU-7004 tests: move from lctl conf_param to lctl set_param -P Jian Yu (2): LU-10660 mdt: revoke lease lock for truncate LU-11412 kernel: kernel update [SLES12 SP3 4.4.155-94.50] John L. Hammond (3): LU-11268 mdc: use smaller buffers for getxattr LU-11380 llite: zero lum for stripeless files LU-11364 osd: remove unused 'ignore quota' parameters Lai Siyao (4): LU-4684 migrate: migrate striped directory LU-4684 migrate: shrink dir layout after migration LU-11301 target: add lock in sub_trans_stop_cb() LU-4684 lmv: support accessing migrating directory Li Dongyang (4): LU-11071 ldiskfs: fix ldiskfs patch for ubuntu18 LU-11360 osd-ldiskfs: hold s_umount before calling sync_fs LU-11187 ldiskfs: don't mark mmp buffer head dirty LU-11368 build: link the shared libraries properly Mikhail Pershin (4): LU-10177 lfs: support DOM-to-OST migration LU-11414 ptlrpc: don't change buffer when signature is ready LU-11287 ldlm: update l_blocking_lock under lock LU-11388 test: disable replay-single test_131b Nathaniel Clark (1): LU-11455 build: Remove conflicting lustre and Lustre NeilBrown (5): LU-8066 llite: use more private data in dump_pgcache LU-8130 ptlrpc: convert conn_hash to rhashtable LU-8066 llite: remove redundant lookup in dump_pgcache LU-8066 llite: change how "dump_page_cache" walks a hash table LU-6202 libcfs: replace libcfs_register_ioctl with a blocking notifier_chain Nikitas Angelinas (1): LU-930 doc: update data_version command in lfs man page Oleg Drokin (2): Revert "LU-11058 test: reenable sanity 77k test" New tag 2.11.56 Ryan Haasken (1): LU-5026 obdclass: Add lbug_on_eviction option Sebastien Piechurski (1): LU-11133 dkms: Add missing ldiskfs module in dkms config Sonia Sharma (5): LU-10124 lnet: Correctly add peer MR value while importing LU-11372 o2iblnd: add clarifying comment to ko2iblnd.conf LU-10772 utils: incorrect check in build_layout_from_yaml_node LU-11370 lnet: cleanup ni_cptlist LU-11422 lnet: Fix selftest backward compatibility post health Vladimir Saveliev (1): LU-11441 obdclass: make mod rpc slot wait queue FIFO Wang Shilong (4): LU-11165 llite: set iflags and catch error from md_setattr() properly LU-11373 libcfs: fix wrong check in libcfs_debug_vmsg2() LU-11198 utils: propagate errors for read_param LU-11451 utils: fix to dump usage messages to stdout Yang Sheng (1): LU-9966 tests: sanity-411 check LBUG direct frank zago (1): LU-6081 user: adding llapi_create_volatile_param() From jsimmons at infradead.org Sun Oct 14 18:55:22 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:22 -0400 Subject: [lustre-devel] [PATCH 00/10] lustre: lnet: fixes for non-x86 systems Message-ID: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> These are the required patches to make LNet work with non-x86 platforms like ARM or Power8. The tunables map_on_demand and concurrent_sends assumed pages were 4K in size which is not correct. Massively reworked to basically defunct those tunables. Also the size of the LNet packet was always 256 pages but when the page size is 64K like some ARM or Power8 systems the maximum LNet message sent was 16MB not 1MB which is what is expected. Fixing up the RDMA handling in the ko2iblnd driver also resolved some performance issues. Alexey Lyashkov (1): lustre: lnd: use less CQ entries for each connection Amir Shehata (6): lustre: lnd: set device capabilities lustre: o2iblnd: use IB_MR_TYPE_SG_GAPS lustre: lnd: rework map_on_demand behavior lustre: lnd: calculate qp max_send_wrs properly lustre: lnd: remove concurrent_sends tunable lustre: lnd: correct WR fast reg accounting Dmitry Eremin (1): lustre: o2iblnd: limit cap.max_send_wr for MLX5 James Simmons (1): lustre: lnet: make LNET_MAX_IOV dependent on page size John L. Hammond (1): lustre: o2ib: use splice in kiblnd_peer_connect_failed() .../staging/lustre/include/linux/lnet/lib-types.h | 10 +- .../lustre/include/uapi/linux/lnet/lnet-types.h | 3 - drivers/staging/lustre/lnet/Kconfig | 10 -- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 138 +++++++++++++++------ .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 68 +++------- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 133 ++++++++++++++------ .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 85 ++++++------- drivers/staging/lustre/lustre/include/lustre_net.h | 1 + 8 files changed, 256 insertions(+), 192 deletions(-) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:26 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:26 -0400 Subject: [lustre-devel] [PATCH 04/10] lustre: lnd: use less CQ entries for each connection In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-5-git-send-email-jsimmons@infradead.org> From: Alexey Lyashkov Currently we have a 2 work requests chains per transfer. It mean OFED stack will generate only 2 events if transfer will faild. Reduce number CQ entries to avoid extra resource consumption. Signed-off-by: Alexey Lyashkov WC-bug-id: https://jira.whamcloud.com/browse/LU-9810 Seagate-bug-id: MRP-4508 Reviewed-on: https://review.whamcloud.com/28279 Reviewed-by: Dmitry Eremin Reviewed-by: Doug Oucharek Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index a6008ea..cd64cfb 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -142,7 +142,9 @@ struct kib_tunables { #define IBLND_SEND_WRS(c) \ ((c->ibc_max_frags + 1) * kiblnd_concurrent_sends(c->ibc_version, \ c->ibc_peer->ibp_ni)) -#define IBLND_CQ_ENTRIES(c) (IBLND_RECV_WRS(c) + IBLND_SEND_WRS(c)) +#define IBLND_CQ_ENTRIES(c) \ + (IBLND_RECV_WRS(c) + 2 * kiblnd_concurrent_sends(c->ibc_version, \ + c->ibc_peer->ibp_ni)) struct kib_hca_dev; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:27 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:27 -0400 Subject: [lustre-devel] [PATCH 05/10] lustre: o2iblnd: limit cap.max_send_wr for MLX5 In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-6-git-send-email-jsimmons@infradead.org> From: Dmitry Eremin Decrease cap.max_send_wr until it is accepted by rdma_create_qp() Signed-off-by: Dmitry Eremin WC-bug-id: https://jira.whamcloud.com/browse/LU-7124 Reviewed-on: http://review.whamcloud.com/18347 Reviewed-by: Olaf Weber Reviewed-by: Doug Oucharek Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 8f984a0..99a4650 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -812,7 +812,14 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, conn->ibc_sched = sched; - rc = rdma_create_qp(cmid, conn->ibc_hdev->ibh_pd, init_qp_attr); + do { + rc = rdma_create_qp(cmid, conn->ibc_hdev->ibh_pd, init_qp_attr); + if (!rc || init_qp_attr->cap.max_send_wr < 16) + break; + + init_qp_attr->cap.max_send_wr -= init_qp_attr->cap.max_send_wr / 4; + } while (rc); + if (rc) { CERROR("Can't create QP: %d, send_wr: %d, recv_wr: %d, send_sge: %d, recv_sge: %d\n", rc, init_qp_attr->cap.max_send_wr, @@ -822,6 +829,10 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, goto failed_2; } + if (init_qp_attr->cap.max_send_wr != IBLND_SEND_WRS(conn)) + CDEBUG(D_NET, "original send wr %d, created with %d\n", + IBLND_SEND_WRS(conn), init_qp_attr->cap.max_send_wr); + kfree(init_qp_attr); /* 1 ref for caller and each rxmsg */ -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:23 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:23 -0400 Subject: [lustre-devel] [PATCH 01/10] lustre: lnd: set device capabilities In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-2-git-send-email-jsimmons@infradead.org> From: Amir Shehata MLX-4, MLX-5 and OPA support different capabilities. Query the device and cache the capabilities of the device for future use. At the time of the patches creation MLX5 could support fast registration and gaps while MLX4 and OPA only support FMR Signed-off-by: Amir Shehata WC-bug-id: https://jira.whamcloud.com/browse/LU-10129 Reviewed-on: https://review.whamcloud.com/30309 Reviewed-by: Alexey Lyashkov Reviewed-by: Dmitry Eremin Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 41 ++++++++++++---------- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 5 +++ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index bf969b3..b10658b 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1399,6 +1399,7 @@ static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_poo else CERROR("FMRs are not supported\n"); } + fpo->fpo_is_fmr = true; return rc; } @@ -1408,6 +1409,8 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po struct kib_fast_reg_descriptor *frd; int i, rc; + fpo->fpo_is_fmr = false; + INIT_LIST_HEAD(&fpo->fast_reg.fpo_pool_list); fpo->fast_reg.fpo_pool_size = 0; for (i = 0; i < fps->fps_pool_size; i++) { @@ -1469,23 +1472,7 @@ static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, fpo->fpo_hdev = kiblnd_current_hdev(dev); dev_attr = &fpo->fpo_hdev->ibh_ibdev->attrs; - /* Check for FMR or FastReg support */ - fpo->fpo_is_fmr = 0; - if (fpo->fpo_hdev->ibh_ibdev->alloc_fmr && - fpo->fpo_hdev->ibh_ibdev->dealloc_fmr && - fpo->fpo_hdev->ibh_ibdev->map_phys_fmr && - fpo->fpo_hdev->ibh_ibdev->unmap_fmr) { - LCONSOLE_INFO("Using FMR for registration\n"); - fpo->fpo_is_fmr = 1; - } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { - LCONSOLE_INFO("Using FastReg for registration\n"); - } else { - rc = -ENOSYS; - LCONSOLE_ERROR_MSG(rc, "IB device does not support FMRs nor FastRegs, can't register memory\n"); - goto out_fpo; - } - - if (fpo->fpo_is_fmr) + if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) rc = kiblnd_alloc_fmr_pool(fps, fpo); else rc = kiblnd_alloc_freg_pool(fps, fpo); @@ -2261,6 +2248,9 @@ static int kiblnd_net_init_pools(struct kib_net *net, struct lnet_ni *ni, static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) { + struct ib_device_attr *dev_attr = &hdev->ibh_ibdev->attrs; + int rc = 0; + /* * It's safe to assume a HCA can handle a page size * matching that of the native system @@ -2269,7 +2259,22 @@ static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) hdev->ibh_page_size = 1 << PAGE_SHIFT; hdev->ibh_page_mask = ~((__u64)hdev->ibh_page_size - 1); - hdev->ibh_mr_size = hdev->ibh_ibdev->attrs.max_mr_size; + if (hdev->ibh_ibdev->alloc_fmr && + hdev->ibh_ibdev->dealloc_fmr && + hdev->ibh_ibdev->map_phys_fmr && + hdev->ibh_ibdev->unmap_fmr) { + LCONSOLE_INFO("Using FMR for registration\n"); + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FMR_ENABLED; + } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { + LCONSOLE_INFO("Using FastReg for registration\n"); + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_ENABLED; + } else { + CERROR("IB device does not support FMRs nor FastRegs, can't register memory: %d\n", + rc); + return -ENXIO; + } + + hdev->ibh_mr_size = dev_attr->max_mr_size; if (hdev->ibh_mr_size == ~0ULL) { hdev->ibh_mr_shift = 64; return 0; diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index a4438d2..9f0a47d 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -73,6 +73,10 @@ #define IBLND_N_SCHED 2 #define IBLND_N_SCHED_HIGH 4 +#define IBLND_DEV_CAPS_FASTREG_ENABLED 0x1 +#define IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT 0x2 +#define IBLND_DEV_CAPS_FMR_ENABLED 0x4 + struct kib_tunables { int *kib_dev_failover; /* HCA failover */ unsigned int *kib_service; /* IB service number */ @@ -162,6 +166,7 @@ struct kib_dev { unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ struct list_head ibd_nets; struct kib_hca_dev *ibd_hdev; + u32 ibd_dev_caps; }; struct kib_hca_dev { -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:25 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:25 -0400 Subject: [lustre-devel] [PATCH 03/10] lustre: lnd: rework map_on_demand behavior In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-4-git-send-email-jsimmons@infradead.org> From: Amir Shehata map_on_demand use is ambiguous. In kernels which supported global memory regions, map-on-demand was used to limit the number of RDMA fragments transferred between peers. That tuanble didn't impact the memory allocation since the maximum allowed was always allocated. It was used however as a variable in determining max_send_wr. With the introduction of FMR if the number of fragments exceed the negotiated number of fragments, which is determined by the map-on-demand value, then FMR is used because we can transfer all the fragments in one FMR fragment. The latest kernels have removed support for global memory regions so the use of map-on-demand has become ineffectual. However, we need to keep it for backwards compatibility. The behavior has changed as follows: map_on_demand is a flag used to determine if we can use FMR or FastReg. This is applicable for kernels which support global memory regions. For later kernels this flag is always enabled, since we will always either use FMR or FastReg For kernels which support global memory regions map_on_demand defaults to 0 which means we will be using global memory regions exclusively. If it is set to a value other than 0, then we will behave as follows: 1. Always default the number of fragments to IBLND_MAX_RDMA_FRAGS 2. Create FMR/FastReg pools 3. Negotiate the supported number of fragments per connection 4. Attempt to transmit using global memory regions only if map-on-demand is off, otherwise use FMR or FastReg. 5. In case of transmitting tx with GAPS over FMR we will need to transmit it with multiple fragments. Look at the comments in kiblnd_fmr_map_tx() for an explanation of the behavior. For later kernels we default map_on_demand to 1 and not allow it to be set to 0, since there is no longer support for global memory regions. Behavior: 1. Default the number of fragments to IBLND_MAX_RDMA_FRAGS 2. Create FMR/FastReg pools 3. Negotiate the supported number of fragments per connection 4. Look at the comments in kiblnd_fmr_map_tx() for an explanation of the behavior when transmit with GAPS verses contiguous. Signed-off-by: Amir Shehata Signed-off-by: Alex Zhuravlev WC-bug-id: https://jira.whamcloud.com/browse/LU-10129 Reviewed-on: https://review.whamcloud.com/29995 WC-bug-id: https://jira.whamcloud.com/browse/LU-8573 Reviewed-on: http://review.whamcloud.com/23439 Reviewed-by: Doug Oucharek Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 31 ++--- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 37 ++---- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 125 +++++++++++++++------ .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 55 ++++++--- 4 files changed, 154 insertions(+), 94 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index ca3e9ce..8f984a0 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -130,7 +130,6 @@ static int kiblnd_msgtype2size(int type) static int kiblnd_unpack_rd(struct kib_msg *msg, int flip) { struct kib_rdma_desc *rd; - int msg_size; int nob; int n; int i; @@ -149,6 +148,12 @@ static int kiblnd_unpack_rd(struct kib_msg *msg, int flip) n = rd->rd_nfrags; + if (n <= 0 || n > IBLND_MAX_RDMA_FRAGS) { + CERROR("Bad nfrags: %d, should be 0 < n <= %d\n", + n, IBLND_MAX_RDMA_FRAGS); + return 1; + } + nob = offsetof(struct kib_msg, ibm_u) + kiblnd_rd_msg_size(rd, msg->ibm_type, n); @@ -158,13 +163,6 @@ static int kiblnd_unpack_rd(struct kib_msg *msg, int flip) return 1; } - msg_size = kiblnd_rd_size(rd); - if (msg_size <= 0 || msg_size > LNET_MAX_PAYLOAD) { - CERROR("Bad msg_size: %d, should be 0 < n <= %d\n", - msg_size, LNET_MAX_PAYLOAD); - return 1; - } - if (!flip) return 0; @@ -336,7 +334,7 @@ int kiblnd_create_peer(struct lnet_ni *ni, struct kib_peer_ni **peerp, peer_ni->ibp_nid = nid; peer_ni->ibp_error = 0; peer_ni->ibp_last_alive = 0; - peer_ni->ibp_max_frags = kiblnd_cfg_rdma_frags(peer_ni->ibp_ni); + peer_ni->ibp_max_frags = IBLND_MAX_RDMA_FRAGS; peer_ni->ibp_queue_depth = ni->ni_net->net_tunables.lct_peer_tx_credits; atomic_set(&peer_ni->ibp_refcount, 1); /* 1 ref for caller */ @@ -782,6 +780,12 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, kiblnd_cq_completion, kiblnd_cq_event, conn, &cq_attr); if (IS_ERR(cq)) { + /* + * on MLX-5 (possibly MLX-4 as well) this error could be + * hit if the concurrent_sends and/or peer_tx_credits is set + * too high. Or due to an MLX-5 bug which tries to + * allocate 256kb via kmalloc for WR cookie array + */ CERROR("Failed to create CQ with %d CQEs: %ld\n", IBLND_CQ_ENTRIES(conn), PTR_ERR(cq)); goto failed_2; @@ -1320,9 +1324,8 @@ static void kiblnd_destroy_fmr_pool(struct kib_fmr_pool *fpo) { LASSERT(!fpo->fpo_map_count); - if (fpo->fpo_is_fmr) { - if (fpo->fmr.fpo_fmr_pool) - ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); + if (fpo->fpo_is_fmr && fpo->fmr.fpo_fmr_pool) { + ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); } else { struct kib_fast_reg_descriptor *frd; int i = 0; @@ -1654,7 +1657,7 @@ void kiblnd_fmr_pool_unmap(struct kib_fmr *fmr, int status) int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, struct kib_rdma_desc *rd, __u32 nob, __u64 iov, - struct kib_fmr *fmr, bool *is_fastreg) + struct kib_fmr *fmr) { __u64 *pages = tx->tx_pages; bool is_rx = (rd != tx->tx_rd); @@ -1674,7 +1677,6 @@ int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, if (fpo->fpo_is_fmr) { struct ib_pool_fmr *pfmr; - *is_fastreg = 0; spin_unlock(&fps->fps_lock); if (!tx_pages_mapped) { @@ -1694,7 +1696,6 @@ int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, } rc = PTR_ERR(pfmr); } else { - *is_fastreg = 1; if (!list_empty(&fpo->fast_reg.fpo_pool_list)) { struct kib_fast_reg_descriptor *frd; struct ib_reg_wr *wr; diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index aaf0118..a6008ea 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -121,9 +121,8 @@ struct kib_tunables { #define IBLND_OOB_CAPABLE(v) ((v) != IBLND_MSG_VERSION_1) #define IBLND_OOB_MSGS(v) (IBLND_OOB_CAPABLE(v) ? 2 : 0) -#define IBLND_FRAG_SHIFT (PAGE_SHIFT - 12) /* frag size on wire is in 4K units */ -#define IBLND_MSG_SIZE (4 << 10) /* max size of queued messages (inc hdr) */ -#define IBLND_MAX_RDMA_FRAGS (LNET_MAX_PAYLOAD >> 12)/* max # of fragments supported in 4K size */ +#define IBLND_MSG_SIZE (4 << 10) /* max size of queued messages (inc hdr) */ +#define IBLND_MAX_RDMA_FRAGS LNET_MAX_IOV /* max # of fragments supported */ /************************/ /* derived constants... */ @@ -141,8 +140,8 @@ struct kib_tunables { /* WRs and CQEs (per connection) */ #define IBLND_RECV_WRS(c) IBLND_RX_MSGS(c) #define IBLND_SEND_WRS(c) \ - (((c->ibc_max_frags + 1) << IBLND_FRAG_SHIFT) * \ - kiblnd_concurrent_sends(c->ibc_version, c->ibc_peer->ibp_ni)) + ((c->ibc_max_frags + 1) * kiblnd_concurrent_sends(c->ibc_version, \ + c->ibc_peer->ibp_ni)) #define IBLND_CQ_ENTRIES(c) (IBLND_RECV_WRS(c) + IBLND_SEND_WRS(c)) struct kib_hca_dev; @@ -288,7 +287,7 @@ struct kib_fmr_pool { time64_t fpo_deadline; /* deadline of this pool */ int fpo_failed; /* fmr pool is failed */ int fpo_map_count; /* # of mapped FMR */ - int fpo_is_fmr; + bool fpo_is_fmr; /* True if FMR pools allocated */ }; struct kib_fmr { @@ -515,7 +514,9 @@ struct kib_tx { /* transmit message */ int tx_nfrags; /* # entries in... */ struct scatterlist *tx_frags; /* dma_map_sg descriptor */ __u64 *tx_pages; /* rdma phys page addrs */ - struct kib_fmr fmr; /* FMR */ + /* gaps in fragments */ + bool tx_gaps; + struct kib_fmr tx_fmr; /* FMR */ int tx_dmadir; /* dma direction */ }; @@ -616,26 +617,6 @@ struct kib_peer_ni { int kiblnd_msg_queue_size(int version, struct lnet_ni *ni); -/* max # of fragments configured by user */ -static inline int -kiblnd_cfg_rdma_frags(struct lnet_ni *ni) -{ - struct lnet_ioctl_config_o2iblnd_tunables *tunables; - int mod; - - tunables = &ni->ni_lnd_tunables.lnd_tun_u.lnd_o2ib; - mod = tunables->lnd_map_on_demand; - return mod ? mod : IBLND_MAX_RDMA_FRAGS >> IBLND_FRAG_SHIFT; -} - -static inline int -kiblnd_rdma_frags(int version, struct lnet_ni *ni) -{ - return version == IBLND_MSG_VERSION_1 ? - (IBLND_MAX_RDMA_FRAGS >> IBLND_FRAG_SHIFT) : - kiblnd_cfg_rdma_frags(ni); -} - static inline int kiblnd_concurrent_sends(int version, struct lnet_ni *ni) { @@ -1011,7 +992,7 @@ static inline unsigned int kiblnd_sg_dma_len(struct ib_device *dev, int kiblnd_fmr_pool_map(struct kib_fmr_poolset *fps, struct kib_tx *tx, struct kib_rdma_desc *rd, __u32 nob, __u64 iov, - struct kib_fmr *fmr, bool *is_fastreg); + struct kib_fmr *fmr); void kiblnd_fmr_pool_unmap(struct kib_fmr *fmr, int status); int kiblnd_tunables_setup(struct lnet_ni *ni); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index b16153f..9d30f31 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -133,6 +133,8 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, LASSERT(!tx->tx_lntmsg[1]); LASSERT(!tx->tx_nfrags); + tx->tx_gaps = false; + return tx; } @@ -538,7 +540,7 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, { struct kib_hca_dev *hdev; struct kib_fmr_poolset *fps; - bool is_fastreg = 0; + struct kib_dev *dev; int cpt; int rc; int i; @@ -546,11 +548,42 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, LASSERT(tx->tx_pool); LASSERT(tx->tx_pool->tpo_pool.po_owner); + dev = net->ibn_dev; hdev = tx->tx_pool->tpo_hdev; cpt = tx->tx_pool->tpo_pool.po_owner->ps_cpt; + /* + * If we're dealing with FastReg, but the device doesn't + * support GAPS and the tx has GAPS, then there is no real point + * in trying to map the memory, because it'll just fail. So + * preemptively fail with an appropriate message + */ + if ((dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED) && + !(dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT) && + tx->tx_gaps) { + CERROR("Using FastReg with no GAPS support, but tx has gaps\n"); + return -EPROTONOSUPPORT; + } + + /* + * FMR does not support gaps but the tx has gaps then + * we should make sure that the number of fragments we'll be sending + * over fits within the number of fragments negotiated on the + * connection, otherwise, we won't be able to RDMA the data. + * We need to maintain the number of fragments negotiation on the + * connection for backwards compatibility. + */ + if (tx->tx_gaps && (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED)) { + if (tx->tx_conn && + tx->tx_conn->ibc_max_frags <= rd->rd_nfrags) { + CERROR("TX number of frags (%d) is <= than connection number of frags (%d). Consider setting peer's map_on_demand to 256\n", + tx->tx_nfrags, tx->tx_conn->ibc_max_frags); + return -EFBIG; + } + } + fps = net->ibn_fmr_ps[cpt]; - rc = kiblnd_fmr_pool_map(fps, tx, rd, nob, 0, &tx->fmr, &is_fastreg); + rc = kiblnd_fmr_pool_map(fps, tx, rd, nob, 0, &tx->tx_fmr); if (rc) { CERROR("Can't map %u bytes: %d\n", nob, rc); return rc; @@ -560,15 +593,28 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, * If rd is not tx_rd, it's going to get sent to a peer_ni, * who will need the rkey */ - rd->rd_key = tx->fmr.fmr_key; - if (!is_fastreg) { + rd->rd_key = tx->tx_fmr.fmr_key; + /* + * for FastReg or FMR with no gaps we can accumulate all + * the fragments in one FastReg or FMR fragment. + */ + if (((dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) && !tx->tx_gaps) || + (dev->ibd_dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED)) { + /* FMR requires zero based address */ + if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) + rd->rd_frags[0].rf_addr &= ~hdev->ibh_page_mask; + rd->rd_frags[0].rf_nob = nob; + rd->rd_nfrags = 1; + } else { + /* + * We're transmitting with gaps using FMR. + * We'll need to use multiple fragments and identify the + * zero based address of each fragment. + */ for (i = 0; i < rd->rd_nfrags; i++) { rd->rd_frags[i].rf_addr &= ~hdev->ibh_page_mask; rd->rd_frags[i].rf_addr += i << hdev->ibh_page_shift; } - } else { - rd->rd_frags[0].rf_nob = nob; - rd->rd_nfrags = 1; } return 0; @@ -576,8 +622,8 @@ static int kiblnd_init_rdma(struct kib_conn *conn, struct kib_tx *tx, int type, static void kiblnd_unmap_tx(struct kib_tx *tx) { - if (tx->fmr.fmr_pfmr || tx->fmr.fmr_frd) - kiblnd_fmr_pool_unmap(&tx->fmr, tx->tx_status); + if (tx->tx_fmr.fmr_pfmr || tx->tx_fmr.fmr_frd) + kiblnd_fmr_pool_unmap(&tx->tx_fmr, tx->tx_status); if (tx->tx_nfrags) { kiblnd_dma_unmap_sg(tx->tx_pool->tpo_hdev->ibh_ibdev, @@ -656,6 +702,13 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, fragnob = min((int)(iov->iov_len - offset), nob); fragnob = min(fragnob, (int)PAGE_SIZE - page_offset); + if ((fragnob < (int)PAGE_SIZE - page_offset) && (niov > 1)) { + CDEBUG(D_NET, + "fragnob %d < available page %d: with remaining %d iovs\n", + fragnob, (int)PAGE_SIZE - page_offset, niov); + tx->tx_gaps = true; + } + sg_set_page(sg, page, fragnob, page_offset); sg = sg_next(sg); if (!sg) { @@ -704,6 +757,13 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, fragnob = min((int)(kiov->bv_len - offset), nob); + if ((fragnob < (int)(kiov->bv_len - offset)) && nkiov > 1) { + CDEBUG(D_NET, + "fragnob %d < available page %d: with remaining %d kiovs\n", + fragnob, (int)(kiov->bv_len - offset), nkiov); + tx->tx_gaps = true; + } + sg_set_page(sg, kiov->bv_page, fragnob, kiov->bv_offset + offset); sg = sg_next(sg); @@ -735,6 +795,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, LASSERT(tx->tx_queued); /* We rely on this for QP sizing */ LASSERT(tx->tx_nwrq > 0 && tx->tx_nsge >= 0); + LASSERT(tx->tx_nwrq <= 1 + conn->ibc_max_frags); LASSERT(!credit || credit == 1); LASSERT(conn->ibc_outstanding_credits >= 0); @@ -814,7 +875,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, /* close_conn will launch failover */ rc = -ENETDOWN; } else { - struct kib_fast_reg_descriptor *frd = tx->fmr.fmr_frd; + struct kib_fast_reg_descriptor *frd = tx->tx_fmr.fmr_frd; const struct ib_send_wr *bad = &tx->tx_wrq[tx->tx_nwrq - 1].wr; struct ib_send_wr *wrq = &tx->tx_wrq[0].wr; @@ -1042,15 +1103,6 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, LASSERT(!tx->tx_nwrq && !tx->tx_nsge); LASSERT(type == IBLND_MSG_GET_DONE || type == IBLND_MSG_PUT_DONE); - if (kiblnd_rd_size(srcrd) > conn->ibc_max_frags << PAGE_SHIFT) { - CERROR("RDMA is too large for peer_ni %s (%d), src size: %d dst size: %d\n", - libcfs_nid2str(conn->ibc_peer->ibp_nid), - conn->ibc_max_frags << PAGE_SHIFT, - kiblnd_rd_size(srcrd), kiblnd_rd_size(dstrd)); - rc = -EMSGSIZE; - goto too_big; - } - for (srcidx = dstidx = wrq_sge = sge_nob = 0; resid > 0; resid -= sge_nob) { int prev = dstidx; @@ -1067,10 +1119,10 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, break; } - if (tx->tx_nwrq >= IBLND_MAX_RDMA_FRAGS) { + if (tx->tx_nwrq >= conn->ibc_max_frags) { CERROR("RDMA has too many fragments for peer_ni %s (%d), src idx/frags: %d/%d dst idx/frags: %d/%d\n", libcfs_nid2str(conn->ibc_peer->ibp_nid), - IBLND_MAX_RDMA_FRAGS, + conn->ibc_max_frags, srcidx, srcrd->rd_nfrags, dstidx, dstrd->rd_nfrags); rc = -EMSGSIZE; @@ -1110,7 +1162,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, } tx->tx_nsge++; } -too_big: + if (rc < 0) { /* no RDMA if completing with failure */ tx->tx_nsge = 0; tx->tx_nwrq = 0; @@ -2335,21 +2387,20 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, goto failed; } - max_frags = reqmsg->ibm_u.connparams.ibcp_max_frags >> IBLND_FRAG_SHIFT; - if (max_frags > kiblnd_rdma_frags(version, ni)) { + max_frags = reqmsg->ibm_u.connparams.ibcp_max_frags; + if (max_frags > IBLND_MAX_RDMA_FRAGS) { CWARN("Can't accept conn from %s (version %x): max message size %d is too large (%d wanted)\n", libcfs_nid2str(nid), version, max_frags, - kiblnd_rdma_frags(version, ni)); + IBLND_MAX_RDMA_FRAGS); if (version >= IBLND_MSG_VERSION) rej.ibr_why = IBLND_REJECT_RDMA_FRAGS; goto failed; - } else if (max_frags < kiblnd_rdma_frags(version, ni) && - !net->ibn_fmr_ps) { + } else if (max_frags < IBLND_MAX_RDMA_FRAGS && !net->ibn_fmr_ps) { CWARN("Can't accept conn from %s (version %x): max message size %d incompatible without FMR pool (%d wanted)\n", libcfs_nid2str(nid), version, max_frags, - kiblnd_rdma_frags(version, ni)); + IBLND_MAX_RDMA_FRAGS); if (version == IBLND_MSG_VERSION) rej.ibr_why = IBLND_REJECT_RDMA_FRAGS; @@ -2495,7 +2546,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, kiblnd_init_msg(ackmsg, IBLND_MSG_CONNACK, sizeof(ackmsg->ibm_u.connparams)); ackmsg->ibm_u.connparams.ibcp_queue_depth = conn->ibc_queue_depth; - ackmsg->ibm_u.connparams.ibcp_max_frags = conn->ibc_max_frags << IBLND_FRAG_SHIFT; + ackmsg->ibm_u.connparams.ibcp_max_frags = conn->ibc_max_frags; ackmsg->ibm_u.connparams.ibcp_max_msg_size = IBLND_MSG_SIZE; kiblnd_pack_msg(ni, ackmsg, version, 0, nid, reqmsg->ibm_srcstamp); @@ -2528,7 +2579,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, failed: if (ni) { rej.ibr_cp.ibcp_queue_depth = kiblnd_msg_queue_size(version, ni); - rej.ibr_cp.ibcp_max_frags = kiblnd_rdma_frags(version, ni); + rej.ibr_cp.ibcp_max_frags = IBLND_MAX_RDMA_FRAGS; lnet_ni_decref(ni); } @@ -2556,7 +2607,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, if (cp) { msg_size = cp->ibcp_max_msg_size; - frag_num = cp->ibcp_max_frags << IBLND_FRAG_SHIFT; + frag_num = cp->ibcp_max_frags; queue_dep = cp->ibcp_queue_depth; } @@ -2590,6 +2641,10 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, goto out; } tunables = &peer_ni->ibp_ni->ni_lnd_tunables.lnd_tun_u.lnd_o2ib; + /* + * This check only makes sense if the kernel supports global + * memory registration. Otherwise, map_on_demand will never == 0 + */ if (!tunables->lnd_map_on_demand) { reason = "map_on_demand must be enabled"; goto out; @@ -2829,11 +2884,11 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, goto failed; } - if ((msg->ibm_u.connparams.ibcp_max_frags >> IBLND_FRAG_SHIFT) > + if ((msg->ibm_u.connparams.ibcp_max_frags) > conn->ibc_max_frags) { CERROR("%s has incompatible max_frags %d (<=%d wanted)\n", libcfs_nid2str(peer_ni->ibp_nid), - msg->ibm_u.connparams.ibcp_max_frags >> IBLND_FRAG_SHIFT, + msg->ibm_u.connparams.ibcp_max_frags, conn->ibc_max_frags); rc = -EPROTO; goto failed; @@ -2867,7 +2922,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, conn->ibc_credits = msg->ibm_u.connparams.ibcp_queue_depth; conn->ibc_reserved_credits = msg->ibm_u.connparams.ibcp_queue_depth; conn->ibc_queue_depth = msg->ibm_u.connparams.ibcp_queue_depth; - conn->ibc_max_frags = msg->ibm_u.connparams.ibcp_max_frags >> IBLND_FRAG_SHIFT; + conn->ibc_max_frags = msg->ibm_u.connparams.ibcp_max_frags; LASSERT(conn->ibc_credits + conn->ibc_reserved_credits + IBLND_OOB_MSGS(ver) <= IBLND_RX_MSGS(conn)); @@ -2924,7 +2979,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, memset(msg, 0, sizeof(*msg)); kiblnd_init_msg(msg, IBLND_MSG_CONNREQ, sizeof(msg->ibm_u.connparams)); msg->ibm_u.connparams.ibcp_queue_depth = conn->ibc_queue_depth; - msg->ibm_u.connparams.ibcp_max_frags = conn->ibc_max_frags << IBLND_FRAG_SHIFT; + msg->ibm_u.connparams.ibcp_max_frags = conn->ibc_max_frags; msg->ibm_u.connparams.ibcp_max_msg_size = IBLND_MSG_SIZE; kiblnd_pack_msg(peer_ni->ibp_ni, msg, version, diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index 985ccdf..7fc6a8a 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -115,10 +115,37 @@ module_param(use_fastreg_gaps, bool, 0444); MODULE_PARM_DESC(use_fastreg_gaps, "Enable discontiguous fastreg fragment support. Expect performance drop"); -#define IBLND_DEFAULT_MAP_ON_DEMAND IBLND_MAX_RDMA_FRAGS +/* + * map_on_demand is a flag used to determine if we can use FMR or FastReg. + * This is applicable for kernels which support global memory regions. For + * later kernels this flag is always enabled, since we will always either + * use FMR or FastReg + * For kernels which support global memory regions map_on_demand defaults + * to 0 which means we will be using global memory regions exclusively. + * If it is set to a value other than 0, then we will behave as follows: + * 1. Always default the number of fragments to IBLND_MAX_RDMA_FRAGS + * 2. Create FMR/FastReg pools + * 3. Negotiate the supported number of fragments per connection + * 4. Attempt to transmit using global memory regions only if + * map-on-demand is not turned on, otherwise use FMR or FastReg + * 5. In case of transmitting tx with GAPS over FMR we will need to + * transmit it with multiple fragments. Look at the comments in + * kiblnd_fmr_map_tx() for an explanation of the behavior. + * + * For later kernels we default map_on_demand to 1 and not allow + * it to be set to 0, since there is no longer support for global memory + * regions. Behavior: + * 1. Default the number of fragments to IBLND_MAX_RDMA_FRAGS + * 2. Create FMR/FastReg pools + * 3. Negotiate the supported number of fragments per connection + * 4. Look at the comments in kiblnd_fmr_map_tx() for an explanation of + * the behavior when transmit with GAPS verses contiguous. + */ + +#define IBLND_DEFAULT_MAP_ON_DEMAND 1 static int map_on_demand = IBLND_DEFAULT_MAP_ON_DEMAND; module_param(map_on_demand, int, 0444); -MODULE_PARM_DESC(map_on_demand, "map on demand"); +MODULE_PARM_DESC(map_on_demand, "map on demand (obsolete)"); /* NB: this value is shared by all CPTs, it can grow at runtime */ static int fmr_pool_size = 512; @@ -234,6 +261,13 @@ int kiblnd_tunables_setup(struct lnet_ni *ni) net_tunables->lct_peer_tx_credits = net_tunables->lct_max_tx_credits; + /* + * For kernels which do not support global memory regions, always + * enable map_on_demand + */ + if (tunables->lnd_map_on_demand == 0) + tunables->lnd_map_on_demand = 1; + if (!tunables->lnd_peercredits_hiw) tunables->lnd_peercredits_hiw = peer_credits_hiw; @@ -243,19 +277,8 @@ int kiblnd_tunables_setup(struct lnet_ni *ni) if (tunables->lnd_peercredits_hiw >= net_tunables->lct_peer_tx_credits) tunables->lnd_peercredits_hiw = net_tunables->lct_peer_tx_credits - 1; - if (tunables->lnd_map_on_demand <= 0 || - tunables->lnd_map_on_demand > IBLND_MAX_RDMA_FRAGS) { - /* Use the default */ - CWARN("Invalid map_on_demand (%d), expects 1 - %d. Using default of %d\n", - tunables->lnd_map_on_demand, - IBLND_MAX_RDMA_FRAGS, IBLND_DEFAULT_MAP_ON_DEMAND); - tunables->lnd_map_on_demand = IBLND_DEFAULT_MAP_ON_DEMAND; - } - - if (tunables->lnd_map_on_demand == 1) { - /* don't make sense to create map if only one fragment */ - tunables->lnd_map_on_demand = 2; - } + if (tunables->lnd_concurrent_sends == 0) + tunables->lnd_concurrent_sends = net_tunables->lct_peer_tx_credits; if (!tunables->lnd_concurrent_sends) { if (tunables->lnd_map_on_demand > 0 && @@ -299,7 +322,7 @@ int kiblnd_tunables_setup(struct lnet_ni *ni) void kiblnd_tunables_init(void) { default_tunables.lnd_version = 0; - default_tunables.lnd_peercredits_hiw = peer_credits_hiw, + default_tunables.lnd_peercredits_hiw = peer_credits_hiw; default_tunables.lnd_map_on_demand = map_on_demand; default_tunables.lnd_concurrent_sends = concurrent_sends; default_tunables.lnd_fmr_pool_size = fmr_pool_size; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:28 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:28 -0400 Subject: [lustre-devel] [PATCH 06/10] lustre: lnd: calculate qp max_send_wrs properly In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-7-git-send-email-jsimmons@infradead.org> From: Amir Shehata The maximum in-flight transfers can not exceed the negotiated queue depth. Instead of calculating the max_send_wrs to be the negotiated number of frags * concurrent sends, it should be the negotiated number of frags * queue depth. If that value is too large for successful qp creation then we reduce the queue depth in a loop until we successfully create the qp or the queue depth dips below 2. Due to the queue depth negotiation protocol it is guaranteed that the queue depth on both the active and the passive will match. This change resolves the discrepancy created by the previous code which reduces max_send_wr by a quarter. That could lead to: mlx5_ib_post_send:4184:(pid 26272): Failed to prepare WQE When the o2iblnd transfers a message which requires more WRs than the max that has been allocated. Signed-off-by: Amir Shehata Signed-off-by: Alexey Lyashkov WC-bug-id: https://jira.whamcloud.com/browse/LU-10213 Reviewed-on: https://review.whamcloud.com/30310 Reviewed-by: Alexey Lyashkov Reviewed-by: Dmitry Eremin Reviewed-by: Doug Oucharek Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 30 +++++++++++++++++----- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 4 +-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 99a4650..43266d8 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -650,6 +650,19 @@ static struct kib_sched_info *kiblnd_get_scheduler(int cpt) return NULL; } +static unsigned int kiblnd_send_wrs(struct kib_conn *conn) +{ + /* + * One WR for the LNet message + * And ibc_max_frags for the transfer WRs + */ + unsigned int ret = 1 + conn->ibc_max_frags; + + /* account for a maximum of ibc_queue_depth in-flight transfers */ + ret *= conn->ibc_queue_depth; + return ret; +} + struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, struct rdma_cm_id *cmid, int state, int version) @@ -801,8 +814,6 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, init_qp_attr->event_handler = kiblnd_qp_event; init_qp_attr->qp_context = conn; - init_qp_attr->cap.max_send_wr = IBLND_SEND_WRS(conn); - init_qp_attr->cap.max_recv_wr = IBLND_RECV_WRS(conn); init_qp_attr->cap.max_send_sge = *kiblnd_tunables.kib_wrq_sge; init_qp_attr->cap.max_recv_sge = 1; init_qp_attr->sq_sig_type = IB_SIGNAL_REQ_WR; @@ -813,11 +824,14 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, conn->ibc_sched = sched; do { + init_qp_attr->cap.max_send_wr = kiblnd_send_wrs(conn); + init_qp_attr->cap.max_recv_wr = IBLND_RECV_WRS(conn); + rc = rdma_create_qp(cmid, conn->ibc_hdev->ibh_pd, init_qp_attr); - if (!rc || init_qp_attr->cap.max_send_wr < 16) + if (!rc || conn->ibc_queue_depth < 2) break; - init_qp_attr->cap.max_send_wr -= init_qp_attr->cap.max_send_wr / 4; + conn->ibc_queue_depth--; } while (rc); if (rc) { @@ -829,9 +843,11 @@ struct kib_conn *kiblnd_create_conn(struct kib_peer_ni *peer_ni, goto failed_2; } - if (init_qp_attr->cap.max_send_wr != IBLND_SEND_WRS(conn)) - CDEBUG(D_NET, "original send wr %d, created with %d\n", - IBLND_SEND_WRS(conn), init_qp_attr->cap.max_send_wr); + if (conn->ibc_queue_depth != peer_ni->ibp_queue_depth) + CWARN("peer %s - queue depth reduced from %u to %u to allow for qp creation\n", + libcfs_nid2str(peer_ni->ibp_nid), + peer_ni->ibp_queue_depth, + conn->ibc_queue_depth); kfree(init_qp_attr); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index cd64cfb..c6c8106 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -139,9 +139,7 @@ struct kib_tunables { /* WRs and CQEs (per connection) */ #define IBLND_RECV_WRS(c) IBLND_RX_MSGS(c) -#define IBLND_SEND_WRS(c) \ - ((c->ibc_max_frags + 1) * kiblnd_concurrent_sends(c->ibc_version, \ - c->ibc_peer->ibp_ni)) + #define IBLND_CQ_ENTRIES(c) \ (IBLND_RECV_WRS(c) + 2 * kiblnd_concurrent_sends(c->ibc_version, \ c->ibc_peer->ibp_ni)) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:31 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:31 -0400 Subject: [lustre-devel] [PATCH 09/10] lustre: o2ib: use splice in kiblnd_peer_connect_failed() In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-10-git-send-email-jsimmons@infradead.org> From: "John L. Hammond" In kiblnd_peer_connect_failed() replace a backwards list_add() and list_del() with list_splice_init(). Signed-off-by: John L. Hammond WC-bug-id: https://jira.whamcloud.com/browse/LU-10819 Reviewed-on: https://review.whamcloud.com/31643 Reviewed-by: Andreas Dilger Reviewed-by: Dmitry Eremin Reviewed-by: Doug Oucharek Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 1f31798..23ce59e 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -2118,8 +2118,7 @@ static int kiblnd_resolve_addr(struct rdma_cm_id *cmid, peer_ni->ibp_reconnected = 0; if (list_empty(&peer_ni->ibp_conns)) { /* Take peer_ni's blocked transmits to complete with error */ - list_add(&zombies, &peer_ni->ibp_tx_queue); - list_del_init(&peer_ni->ibp_tx_queue); + list_splice_init(&peer_ni->ibp_tx_queue, &zombies); if (kiblnd_peer_active(peer_ni)) kiblnd_unlink_peer_locked(peer_ni); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:24 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:24 -0400 Subject: [lustre-devel] [PATCH 02/10] lustre: o2iblnd: use IB_MR_TYPE_SG_GAPS In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-3-git-send-email-jsimmons@infradead.org> From: Amir Shehata When allocating fastreg buffers allow the use of IB_MR_TYPE_SG_GAPS instead of IB_MR_TYPE_MEM_REG, since the fragments we provide the fast registration API can have gaps. MEM_REG doesn't handle that case. There is a performance drop when using IB_MR_TYPE_SG_GAPS and it is recommended not to use it. To mitigate this, we added a module parameter, use_fastreg_gaps, which defaults to 0. When allocating the memory region if this parameter is set to 1 and the hw has gaps support then use it and output a warning that performance may drop. Otherwise always use IB_MR_TYPE_MEM_REG. We still want to give user the choice to use this option. Signed-off-by: Amir Shehata WC-bug-id: https://jira.whamcloud.com/browse/LU-10089 Reviewed-on: https://review.whamcloud.com/29551 WC-bug-id: https://jira.whamcloud.com/browse/LU-10394 Reviewed-on: https://review.whamcloud.com/30749 Reviewed-by: Dmitry Eremin Reviewed-by: James Simmons Reviewed-by: Doug Oucharek Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 24 +++++++++++++++++++--- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 3 +++ .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 5 +++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index b10658b..ca3e9ce 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1404,7 +1404,8 @@ static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_poo return rc; } -static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_pool *fpo) +static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, + struct kib_fmr_pool *fpo, u32 dev_caps) { struct kib_fast_reg_descriptor *frd; int i, rc; @@ -1414,6 +1415,8 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po INIT_LIST_HEAD(&fpo->fast_reg.fpo_pool_list); fpo->fast_reg.fpo_pool_size = 0; for (i = 0; i < fps->fps_pool_size; i++) { + bool fastreg_gaps = false; + frd = kzalloc_cpt(sizeof(*frd), GFP_NOFS, fps->fps_cpt); if (!frd) { CERROR("Failed to allocate a new fast_reg descriptor\n"); @@ -1421,8 +1424,21 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po goto out; } + /* + * it is expected to get here if this is an MLX-5 card. + * MLX-4 cards will always use FMR and MLX-5 cards will + * always use fast_reg. It turns out that some MLX-5 cards + * (possibly due to older FW versions) do not natively support + * gaps. So we will need to track them here. + */ + if ((*kiblnd_tunables.kib_use_fastreg_gaps == 1) && + (dev_caps & IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT)) { + CWARN("using IB_MR_TYPE_SG_GAPS, expect a performance drop\n"); + fastreg_gaps = true; + } frd->frd_mr = ib_alloc_mr(fpo->fpo_hdev->ibh_pd, - IB_MR_TYPE_MEM_REG, + fastreg_gaps ? IB_MR_TYPE_SG_GAPS : + IB_MR_TYPE_MEM_REG, LNET_MAX_PAYLOAD / PAGE_SIZE); if (IS_ERR(frd->frd_mr)) { rc = PTR_ERR(frd->frd_mr); @@ -1475,7 +1491,7 @@ static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) rc = kiblnd_alloc_fmr_pool(fps, fpo); else - rc = kiblnd_alloc_freg_pool(fps, fpo); + rc = kiblnd_alloc_freg_pool(fps, fpo, dev->ibd_dev_caps); if (rc) goto out_fpo; @@ -2268,6 +2284,8 @@ static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { LCONSOLE_INFO("Using FastReg for registration\n"); hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_ENABLED; + if (dev_attr->device_cap_flags & IB_DEVICE_SG_GAPS_REG) + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT; } else { CERROR("IB device does not support FMRs nor FastRegs, can't register memory: %d\n", rc); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index 9f0a47d..aaf0118 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -94,6 +94,9 @@ struct kib_tunables { int *kib_use_priv_port; /* use privileged port for active connect */ int *kib_nscheds; /* # threads on each CPT */ int *kib_wrq_sge; /* # sg elements per wrq */ + bool *kib_use_fastreg_gaps; /* enable discontiguous fastreg + * fragment support + */ }; extern struct kib_tunables kiblnd_tunables; diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index 13b19f3..985ccdf 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -111,6 +111,10 @@ module_param(concurrent_sends, int, 0444); MODULE_PARM_DESC(concurrent_sends, "send work-queue sizing"); +static bool use_fastreg_gaps; +module_param(use_fastreg_gaps, bool, 0444); +MODULE_PARM_DESC(use_fastreg_gaps, "Enable discontiguous fastreg fragment support. Expect performance drop"); + #define IBLND_DEFAULT_MAP_ON_DEMAND IBLND_MAX_RDMA_FRAGS static int map_on_demand = IBLND_DEFAULT_MAP_ON_DEMAND; module_param(map_on_demand, int, 0444); @@ -165,6 +169,7 @@ struct kib_tunables kiblnd_tunables = { .kib_use_priv_port = &use_privileged_port, .kib_nscheds = &nscheds, .kib_wrq_sge = &wrq_sge, + .kib_use_fastreg_gaps = &use_fastreg_gaps, }; static struct lnet_ioctl_config_o2iblnd_tunables default_tunables; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:30 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:30 -0400 Subject: [lustre-devel] [PATCH 08/10] lustre: lnd: correct WR fast reg accounting In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-9-git-send-email-jsimmons@infradead.org> From: Amir Shehata Ensure that enough WRs are allocated for the fast reg case which needs two additional WRs per transfer: the first for memory window registration and the second for memory window invalidation. Failure to allocate these causes the following problem: mlx5_warn:mlx5_0:begin_wqe:4085(pid 9590): work queue overflow Signed-off-by: Amir Shehata Signed-off-by: Alexey Lyashkov WC-bug-id: https://jira.whamcloud.com/browse/LU-9943 Reviewed-on: https://review.whamcloud.com/30311 Reviewed-by: Alexey Lyashkov Reviewed-by: Dmitry Eremin Reviewed-by: Doug Oucharek Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 43266d8..66aa45f 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -656,8 +656,13 @@ static unsigned int kiblnd_send_wrs(struct kib_conn *conn) * One WR for the LNet message * And ibc_max_frags for the transfer WRs */ + u32 dev_caps = conn->ibc_hdev->ibh_dev->ibd_dev_caps; unsigned int ret = 1 + conn->ibc_max_frags; + /* FastReg needs two extra WRs for map and invalidate */ + if (dev_caps & IBLND_DEV_CAPS_FASTREG_ENABLED) + ret += 2; + /* account for a maximum of ibc_queue_depth in-flight transfers */ ret *= conn->ibc_queue_depth; return ret; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:32 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:32 -0400 Subject: [lustre-devel] [PATCH 10/10] lustre: lnet: make LNET_MAX_IOV dependent on page size In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-11-git-send-email-jsimmons@infradead.org> The default behavior of LNet is to always use 256 pages which is LNET_MAX_IOV and that LNET_MAX_PAYLOAD is always one megabyte. This assumes pages are always 4K in size which is not the case. This cause bulk I/O errors when using platforms like PowerPC or ARM which tend to use 64K pages. This is resolved by first making LNET_MAX_PAYLOAD always one megabyte since this is what the configuring sets it too by default and no one ever changes it. In theory it could set it to as high as 16MB but that will cause the I/O errors since the ptlrpc layer expects the packets to be always 1 megabyte in size. Also it would be better to make the maximum payload a per network setup configurations instead of for everything. Second we make LNET_MAX_IOV equal to LNET_MAX_PAYLOAD divided by the PAGE_SIZE. This way packets will always be the LNET_MAX_PAYLOAD in size but the number of pages used, LNET_MAX_IOV will vary depending on the platform it is creating packets on. Signed-off-by: James Simmons WC-bug-id: https://jira.whamcloud.com/browse/LU-10157 Reviewed-on: https://review.whamcloud.com/31559 Reviewed-by: Wang Shilong Reviewed-by: Ruth Klundt Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/include/linux/lnet/lib-types.h | 10 ++++------ drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h | 3 --- drivers/staging/lustre/lnet/Kconfig | 10 ---------- drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 4 ++-- drivers/staging/lustre/lustre/include/lustre_net.h | 1 + 5 files changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h index 19f7b11..8951a53 100644 --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h @@ -37,6 +37,7 @@ #define __LNET_LIB_TYPES_H__ #include +#include #include #include #include @@ -46,12 +47,9 @@ #include /* Max payload size */ -#define LNET_MAX_PAYLOAD CONFIG_LNET_MAX_PAYLOAD -#if (LNET_MAX_PAYLOAD < LNET_MTU) -# error "LNET_MAX_PAYLOAD too small - error in configure --with-max-payload-mb" -#elif (LNET_MAX_PAYLOAD > (PAGE_SIZE * LNET_MAX_IOV)) -# error "LNET_MAX_PAYLOAD too large - error in configure --with-max-payload-mb" -#endif +#define LNET_MAX_PAYLOAD LNET_MTU + +#define LNET_MAX_IOV (LNET_MAX_PAYLOAD >> PAGE_SHIFT) /* forward refs */ struct lnet_libmd; diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h index 1ecf18e..e440100 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h @@ -522,9 +522,6 @@ struct lnet_md { #define LNET_MTU_BITS 20 #define LNET_MTU (1 << LNET_MTU_BITS) -/** limit on the number of fragments in discontiguous MDs */ -#define LNET_MAX_IOV 256 - /** * Options for the MD structure. See lnet_md::options. */ diff --git a/drivers/staging/lustre/lnet/Kconfig b/drivers/staging/lustre/lnet/Kconfig index ad049e6..6062a82 100644 --- a/drivers/staging/lustre/lnet/Kconfig +++ b/drivers/staging/lustre/lnet/Kconfig @@ -8,16 +8,6 @@ config LNET case of Lustre routers only the LNet layer is required. Lately other projects are also looking into using LNet as their networking API as well. -config LNET_MAX_PAYLOAD - int "Lustre lnet max transfer payload (default 1MB)" - depends on LNET - default "1048576" - help - This option defines the maximum size of payload in bytes that lnet - can put into its transport. - - If unsure, use default. - config LNET_SELFTEST tristate "Lustre networking self testing" depends on LNET diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 66aa45f..68a8963 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1414,7 +1414,7 @@ static void kiblnd_destroy_fmr_pool_list(struct list_head *head) static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_pool *fpo) { struct ib_fmr_pool_param param = { - .max_pages_per_fmr = LNET_MAX_PAYLOAD / PAGE_SIZE, + .max_pages_per_fmr = LNET_MAX_IOV, .page_shift = PAGE_SHIFT, .access = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE), @@ -1474,7 +1474,7 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, frd->frd_mr = ib_alloc_mr(fpo->fpo_hdev->ibh_pd, fastreg_gaps ? IB_MR_TYPE_SG_GAPS : IB_MR_TYPE_MEM_REG, - LNET_MAX_PAYLOAD / PAGE_SIZE); + LNET_MAX_IOV); if (IS_ERR(frd->frd_mr)) { rc = PTR_ERR(frd->frd_mr); CERROR("Failed to allocate ib_alloc_mr: %d\n", rc); diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index 2df72c7..ce7e98c 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:55:29 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:55:29 -0400 Subject: [lustre-devel] [PATCH 07/10] lustre: lnd: remove concurrent_sends tunable In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543332-28679-8-git-send-email-jsimmons@infradead.org> From: Amir Shehata Concurrent sends tunable was intended to limit the number of in-flight transfers per connection. However queue depth does the exact same job. So for example if the queue depth is negotiated to 16 and concurrent_sends is set to 32, the maximum number of in-flight transfers doesn't exceed 16. There is no need to keep concurrent_sends around since it doesn't add any unique functionality Signed-off-by: Amir Shehata WC-bug-id: https://jira.whamcloud.com/browse/LU-10291 Reviewed-on: https://review.whamcloud.com/30312 WC-bug-id: https://jira.whamcloud.com/browse/LU-10459 Reviewed-on: https://review.whamcloud.com/30751 Reviewed-by: Alexey Lyashkov Reviewed-by: Dmitry Eremin Reviewed-by: Doug Oucharek Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 23 +---------------- .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 5 ++-- .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 29 +--------------------- 3 files changed, 4 insertions(+), 53 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index c6c8106..c882345 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -141,8 +141,7 @@ struct kib_tunables { #define IBLND_RECV_WRS(c) IBLND_RX_MSGS(c) #define IBLND_CQ_ENTRIES(c) \ - (IBLND_RECV_WRS(c) + 2 * kiblnd_concurrent_sends(c->ibc_version, \ - c->ibc_peer->ibp_ni)) + (IBLND_RECV_WRS(c) + 2 * c->ibc_queue_depth) struct kib_hca_dev; @@ -617,26 +616,6 @@ struct kib_peer_ni { int kiblnd_msg_queue_size(int version, struct lnet_ni *ni); -static inline int -kiblnd_concurrent_sends(int version, struct lnet_ni *ni) -{ - struct lnet_ioctl_config_o2iblnd_tunables *tunables; - int concurrent_sends; - - tunables = &ni->ni_lnd_tunables.lnd_tun_u.lnd_o2ib; - concurrent_sends = tunables->lnd_concurrent_sends; - - if (version == IBLND_MSG_VERSION_1) { - if (concurrent_sends > IBLND_MSG_QUEUE_SIZE_V1 * 2) - return IBLND_MSG_QUEUE_SIZE_V1 * 2; - - if (concurrent_sends < IBLND_MSG_QUEUE_SIZE_V1 / 2) - return IBLND_MSG_QUEUE_SIZE_V1 / 2; - } - - return concurrent_sends; -} - static inline void kiblnd_hdev_addref_locked(struct kib_hca_dev *hdev) { diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 9d30f31..1f31798 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -787,7 +787,6 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, { struct kib_msg *msg = tx->tx_msg; struct kib_peer_ni *peer_ni = conn->ibc_peer; - struct lnet_ni *ni = peer_ni->ibp_ni; int ver = conn->ibc_version; int rc; int done; @@ -803,7 +802,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, LASSERT(conn->ibc_credits >= 0); LASSERT(conn->ibc_credits <= conn->ibc_queue_depth); - if (conn->ibc_nsends_posted == kiblnd_concurrent_sends(ver, ni)) { + if (conn->ibc_nsends_posted == conn->ibc_queue_depth) { /* tx completions outstanding... */ CDEBUG(D_NET, "%s: posted enough\n", libcfs_nid2str(peer_ni->ibp_nid)); @@ -953,7 +952,7 @@ static int kiblnd_map_tx(struct lnet_ni *ni, struct kib_tx *tx, return; } - LASSERT(conn->ibc_nsends_posted <= kiblnd_concurrent_sends(ver, ni)); + LASSERT(conn->ibc_nsends_posted <= conn->ibc_queue_depth); LASSERT(!IBLND_OOB_CAPABLE(ver) || conn->ibc_noops_posted <= IBLND_OOB_MSGS(ver)); LASSERT(conn->ibc_reserved_credits >= 0); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index 7fc6a8a..47e8a60 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -109,7 +109,7 @@ static int concurrent_sends; module_param(concurrent_sends, int, 0444); -MODULE_PARM_DESC(concurrent_sends, "send work-queue sizing"); +MODULE_PARM_DESC(concurrent_sends, "send work-queue sizing (obsolete)"); static bool use_fastreg_gaps; module_param(use_fastreg_gaps, bool, 0444); @@ -277,32 +277,6 @@ int kiblnd_tunables_setup(struct lnet_ni *ni) if (tunables->lnd_peercredits_hiw >= net_tunables->lct_peer_tx_credits) tunables->lnd_peercredits_hiw = net_tunables->lct_peer_tx_credits - 1; - if (tunables->lnd_concurrent_sends == 0) - tunables->lnd_concurrent_sends = net_tunables->lct_peer_tx_credits; - - if (!tunables->lnd_concurrent_sends) { - if (tunables->lnd_map_on_demand > 0 && - tunables->lnd_map_on_demand <= IBLND_MAX_RDMA_FRAGS / 8) { - tunables->lnd_concurrent_sends = - net_tunables->lct_peer_tx_credits * 2; - } else { - tunables->lnd_concurrent_sends = - net_tunables->lct_peer_tx_credits; - } - } - - if (tunables->lnd_concurrent_sends > net_tunables->lct_peer_tx_credits * 2) - tunables->lnd_concurrent_sends = net_tunables->lct_peer_tx_credits * 2; - - if (tunables->lnd_concurrent_sends < net_tunables->lct_peer_tx_credits / 2) - tunables->lnd_concurrent_sends = net_tunables->lct_peer_tx_credits / 2; - - if (tunables->lnd_concurrent_sends < net_tunables->lct_peer_tx_credits) { - CWARN("Concurrent sends %d is lower than message queue size: %d, performance may drop slightly.\n", - tunables->lnd_concurrent_sends, - net_tunables->lct_peer_tx_credits); - } - if (!tunables->lnd_fmr_pool_size) tunables->lnd_fmr_pool_size = fmr_pool_size; if (!tunables->lnd_fmr_flush_trigger) @@ -324,7 +298,6 @@ void kiblnd_tunables_init(void) default_tunables.lnd_version = 0; default_tunables.lnd_peercredits_hiw = peer_credits_hiw; default_tunables.lnd_map_on_demand = map_on_demand; - default_tunables.lnd_concurrent_sends = concurrent_sends; default_tunables.lnd_fmr_pool_size = fmr_pool_size; default_tunables.lnd_fmr_flush_trigger = fmr_flush_trigger; default_tunables.lnd_fmr_cache = fmr_cache; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:50 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:50 -0400 Subject: [lustre-devel] [PATCH 00/28] lustre: more assorted fixes for lustre 2.10 Message-ID: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Another bacth of assorted fixes missing in the linux client from lustre 2.10. All of these should be order independent and don't collide with the PFL work that will land at a later date. Alex Zhuravlev (2): lustre: llite: use security context if it's enabled in the kernel lustre: ptlrpc: do not wakeup every second Andreas Dilger (2): lustre: mdc: improve mdc_enqueue() error message lustre: obdclass: deprecate OBD_GET_VERSION ioctl Andrew Perepechko (1): lustre: osc: osc_extent_tree_dump0() implementation is suboptimal Andriy Skulysh (1): lustre: ldlm: ELC shouldn't wait on lock flush Bob Glossman (1): lustre: ptlrpc: handle case of epp_free_pages <= PTLRPC_MAX_BRW_PAGES Doug Oucharek (1): lustre: ptlrpc: Do not assert when bd_nob_transferred != 0 Fan Yong (1): lustre: llite: control concurrent statahead instances Frank Zago (1): lustre: llite: fix for stat under kthread and X86_X32 Henri Doreau (2): lustre: hsm: add kkuc before sending registration RPCs lustre: mdc: expose changelog through char devices Hongchao Zhang (1): lustre: llite: IO accounting of page read James Simmons (5): lustre: uapi: add back LUSTRE_MAXFSNAME to lustre_user.h lustre: uapi: add missing headers in lustre UAPI headers lustre: llite: enhance vvp_dev data structure naming lustre: clio: update spare bit handling lustre: llite: restore lld_nfs_dentry handling Jinshan Xiong (2): lustre: llite: pipeline readahead better with large I/O lustre: ldlm: check lock cancellation in ldlm_cli_cancel() John L. Hammond (2): lustre: llog: fix EOF handling in llog_client_next_block() lustre: mdc: set correct body eadatasize for getxattr() Lai Siyao (3): lustre: ptlrpc: missing barrier before wake_up lustre: statahead: missing barrier before wake_up lustre: llite: disable statahead if starting statahead fail Patrick Farrell (3): lustre: llite: Read ahead should return pages read lustre: llite: Update i_nlink on unlink lustre: ldlm: Make lru clear always discard read lock pages .../lustre/include/uapi/linux/lnet/libcfs_debug.h | 2 + .../lustre/include/uapi/linux/lnet/lnetctl.h | 1 + .../lustre/include/uapi/linux/lnet/nidstr.h | 1 + .../lustre/include/uapi/linux/lustre/lustre_cfg.h | 1 + .../lustre/include/uapi/linux/lustre/lustre_fid.h | 1 + .../include/uapi/linux/lustre/lustre_fiemap.h | 1 + .../include/uapi/linux/lustre/lustre_ioctl.h | 2 +- .../include/uapi/linux/lustre/lustre_kernelcomm.h | 3 - .../include/uapi/linux/lustre/lustre_ostid.h | 1 + .../lustre/include/uapi/linux/lustre/lustre_user.h | 9 +- drivers/staging/lustre/lustre/include/cl_object.h | 2 +- .../lustre/lustre/include/lustre_dlm_flags.h | 2 +- drivers/staging/lustre/lustre/include/lustre_net.h | 2 + drivers/staging/lustre/lustre/include/obd.h | 18 +- drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 20 +- drivers/staging/lustre/lustre/ldlm/ldlm_lib.c | 2 + drivers/staging/lustre/lustre/ldlm/ldlm_lock.c | 13 - drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 66 +- drivers/staging/lustre/lustre/ldlm/ldlm_resource.c | 6 +- drivers/staging/lustre/lustre/llite/dir.c | 14 +- drivers/staging/lustre/lustre/llite/file.c | 25 +- drivers/staging/lustre/lustre/llite/lcommon_cl.c | 4 +- .../staging/lustre/lustre/llite/llite_internal.h | 39 +- drivers/staging/lustre/lustre/llite/llite_lib.c | 22 +- drivers/staging/lustre/lustre/llite/lproc_llite.c | 37 ++ drivers/staging/lustre/lustre/llite/namei.c | 12 +- drivers/staging/lustre/lustre/llite/rw.c | 57 +- drivers/staging/lustre/lustre/llite/statahead.c | 39 +- drivers/staging/lustre/lustre/llite/vvp_dev.c | 54 +- drivers/staging/lustre/lustre/lmv/lmv_obd.c | 57 +- drivers/staging/lustre/lustre/mdc/Makefile | 2 +- drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 722 +++++++++++++++++++++ drivers/staging/lustre/lustre/mdc/mdc_internal.h | 4 + drivers/staging/lustre/lustre/mdc/mdc_lib.c | 10 +- drivers/staging/lustre/lustre/mdc/mdc_locks.c | 11 +- drivers/staging/lustre/lustre/mdc/mdc_request.c | 198 +----- drivers/staging/lustre/lustre/obdclass/class_obd.c | 18 +- drivers/staging/lustre/lustre/obdclass/obd_mount.c | 2 +- drivers/staging/lustre/lustre/osc/osc_cache.c | 7 +- .../staging/lustre/lustre/osc/osc_cl_internal.h | 2 +- drivers/staging/lustre/lustre/osc/osc_io.c | 6 +- drivers/staging/lustre/lustre/osc/osc_lock.c | 10 +- drivers/staging/lustre/lustre/osc/osc_object.c | 2 +- drivers/staging/lustre/lustre/ptlrpc/llog_client.c | 24 +- drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 8 +- drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 +- drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c | 11 +- 47 files changed, 1150 insertions(+), 404 deletions(-) create mode 100644 drivers/staging/lustre/lustre/mdc/mdc_changelog.c -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:51 -0400 Subject: [lustre-devel] [PATCH 01/28] lustre: osc: osc_extent_tree_dump0() implementation is suboptimal In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-2-git-send-email-jsimmons@infradead.org> From: Andrew Perepechko Avoid looping in osc_extent_tree_dump() if debugging is disabled. This helps us save some cpu ticks. Signed-off-by: Andrew Perepechko WC-bug-id: https://jira.whamcloud.com/browse/LU-9716 Seagate-bug-id: MRP-4469 Reviewed-on: https://review.whamcloud.com/27866 Reviewed-by: Alexandr Boyko Reviewed-by: Alexander Zarochentsev Reviewed-by: Andreas Dilger Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/osc/osc_cache.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 326f663..92d292d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -1283,6 +1283,9 @@ static void osc_extent_tree_dump0(int level, struct osc_object *obj, struct osc_extent *ext; int cnt; + if (!cfs_cdebug_show(level, DEBUG_SUBSYSTEM)) + return; + CDEBUG(level, "Dump object %p extents at %s:%d, mppr: %u.\n", obj, func, line, osc_cli(obj)->cl_max_pages_per_rpc); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:52 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:52 -0400 Subject: [lustre-devel] [PATCH 02/28] lustre: llite: Read ahead should return pages read In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-3-git-send-email-jsimmons@infradead.org> From: Patrick Farrell ll_read_ahead_pages was modified by commit 198a49a964a0 ("staging: lustre: clio: revise readahead to support 16MB IO") and returning the count of pages read was removed. This only affects debug, but it's very nice to have it printed out, and several messages still try to print out pages read ahead, but print 0. Restore this functionality. Signed-off-by: Patrick Farrell WC-bug-id: https://jira.whamcloud.com/browse/LU-9778 Reviewed-on: https://review.whamcloud.com/28052 Reviewed-by: Andreas Dilger Reviewed-by: Ben Evans Reviewed-by: Gu Zheng Reviewed-by: Jinshan Xiong Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/rw.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 49ac723..82d874a 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -342,12 +342,12 @@ static int ras_inside_ra_window(unsigned long idx, struct ra_io_arg *ria) static unsigned long ll_read_ahead_pages(const struct lu_env *env, struct cl_io *io, struct cl_page_list *queue, struct ll_readahead_state *ras, - struct ra_io_arg *ria) + struct ra_io_arg *ria, pgoff_t *ra_end) { struct cl_read_ahead ra = { 0 }; - unsigned long ra_end = 0; bool stride_ria; pgoff_t page_idx; + int count = 0; int rc; LASSERT(ria); @@ -393,9 +393,14 @@ static int ras_inside_ra_window(unsigned long idx, struct ra_io_arg *ria) if (rc < 0) break; - ra_end = page_idx; - if (!rc) + *ra_end = page_idx; + /* Only subtract from reserve & count the page if we + * really did readahead on that page. + */ + if (!rc) { ria->ria_reserved--; + count++; + } } else if (stride_ria) { /* If it is not in the read-ahead window, and it is * read-ahead mode, then check whether it should skip @@ -423,7 +428,7 @@ static int ras_inside_ra_window(unsigned long idx, struct ra_io_arg *ria) } cl_read_ahead_release(env, &ra); - return ra_end; + return count; } static int ll_readahead(const struct lu_env *env, struct cl_io *io, @@ -434,7 +439,7 @@ static int ll_readahead(const struct lu_env *env, struct cl_io *io, struct ll_thread_info *lti = ll_env_info(env); struct cl_attr *attr = vvp_env_thread_attr(env); unsigned long len, mlen = 0; - pgoff_t ra_end, start = 0, end = 0; + pgoff_t ra_end = 0, start = 0, end = 0; struct inode *inode; struct ra_io_arg *ria = <i->lti_ria; struct cl_object *clob; @@ -542,7 +547,7 @@ static int ll_readahead(const struct lu_env *env, struct cl_io *io, atomic_read(&ll_i2sbi(inode)->ll_ra_info.ra_cur_pages), ll_i2sbi(inode)->ll_ra_info.ra_max_pages); - ra_end = ll_read_ahead_pages(env, io, queue, ras, ria); + ret = ll_read_ahead_pages(env, io, queue, ras, ria, &ra_end); if (ria->ria_reserved) ll_ra_count_put(ll_i2sbi(inode), ria->ria_reserved); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:54 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:54 -0400 Subject: [lustre-devel] [PATCH 04/28] lustre: ptlrpc: Do not assert when bd_nob_transferred != 0 In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-5-git-send-email-jsimmons@infradead.org> From: Doug Oucharek There is a case in the routine ptlrpc_register_bulk() where we were asserting if bd_nob_transferred != 0 when not resending. There is evidence that network errors can create a situation where this does happen. So we should not be asserting! This patch changes that assert to an error return code of -EIO. Signed-off-by: Doug Oucharek WC-bug-id: https://jira.whamcloud.com/browse/LU-9828 Reviewed-on: https://review.whamcloud.com/28491 Reviewed-by: Dmitry Eremin Reviewed-by: Sonia Sharma Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 27eb1c0..7e7db24 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -139,8 +139,12 @@ static int ptlrpc_register_bulk(struct ptlrpc_request *req) /* cleanup the state of the bulk for it will be reused */ if (req->rq_resend || req->rq_send_state == LUSTRE_IMP_REPLAY) desc->bd_nob_transferred = 0; - else - LASSERT(desc->bd_nob_transferred == 0); + else if (desc->bd_nob_transferred != 0) + /* If the network failed after an RPC was sent, this condition + * could happen. Rather than assert (was here before), return + * an EIO error. + */ + return -EIO; desc->bd_failure = 0; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:58 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:58 -0400 Subject: [lustre-devel] [PATCH 08/28] lustre: hsm: add kkuc before sending registration RPCs In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-9-git-send-email-jsimmons@infradead.org> From: Henri Doreau This avoids a situation where the registration completes and the CDT sends HSM actions just before the kkuc registration happens. In this case the client drops the actions because there are no CT pipes in the kkuc list. Signed-off-by: Henri Doreau WC-bug-id: https://jira.whamcloud.com/browse/LU-9416 Reviewed-on: https://review.whamcloud.com/28751 Reviewed-by: John L. Hammond Reviewed-by: Faccini Bruno Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/lmv/lmv_obd.c | 44 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 71bd843..952c68e 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -784,9 +784,23 @@ static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len, { struct file *filp; __u32 i, j; - int err, rc = 0; + int err; bool any_set = false; - struct kkuc_ct_data kcd = { 0 }; + struct kkuc_ct_data kcd = { + .kcd_magic = KKUC_CT_DATA_MAGIC, + .kcd_uuid = lmv->cluuid, + .kcd_archive = lk->lk_data + }; + int rc = 0; + + filp = fget(lk->lk_wfd); + if (!filp) + return -EBADF; + + rc = libcfs_kkuc_group_add(filp, lk->lk_uid, lk->lk_group, + &kcd, sizeof(kcd)); + if (rc) + goto err_fput; /* All or nothing: try to register to all MDS. * In case of failure, unregister from previous MDS, @@ -815,7 +829,7 @@ static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len, obd_iocontrol(cmd, tgt->ltd_exp, len, lk, uarg); } - return rc; + goto err_kkuc_rem; } /* else: transient error. * kuc will register to the missing MDT when it is back @@ -825,24 +839,18 @@ static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len, } } - if (!any_set) + if (!any_set) { /* no registration done: return error */ - return -ENOTCONN; - - /* at least one registration done, with no failure */ - filp = fget(lk->lk_wfd); - if (!filp) - return -EBADF; - - kcd.kcd_magic = KKUC_CT_DATA_MAGIC; - kcd.kcd_uuid = lmv->cluuid; - kcd.kcd_archive = lk->lk_data; + rc = -ENOTCONN; + goto err_kkuc_rem; + } - rc = libcfs_kkuc_group_add(filp, lk->lk_uid, lk->lk_group, - &kcd, sizeof(kcd)); - if (rc) - fput(filp); + return 0; +err_kkuc_rem: + libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group); +err_fput: + fput(filp); return rc; } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:59 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:59 -0400 Subject: [lustre-devel] [PATCH 09/28] lustre: mdc: improve mdc_enqueue() error message In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-10-git-send-email-jsimmons@infradead.org> From: Andreas Dilger Include the parent/child FIDs and name in the mdc_enqueue() debug message. Signed-off-by: Andreas Dilger WC-bug-id: https://jira.whamcloud.com/browse/LU-4705 Reviewed-on: https://review.whamcloud.com/28978 Reviewed-by: Steve Guminski Reviewed-by: Yang Sheng Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/mdc/mdc_locks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index cfe917c..5ec5d78 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -824,8 +824,10 @@ int mdc_enqueue_base(struct obd_export *exp, struct ldlm_enqueue_info *einfo, mdc_put_mod_rpc_slot(req, it); if (rc < 0) { - CDEBUG(D_INFO, "%s: ldlm_cli_enqueue failed: rc = %d\n", - obddev->obd_name, rc); + CDEBUG(D_INFO, + "%s: ldlm_cli_enqueue " DFID ":" DFID "=%s failed: rc = %d\n", + obddev->obd_name, PFID(&op_data->op_fid1), + PFID(&op_data->op_fid2), op_data->op_name ?: "", rc); mdc_clear_replay_flag(req, rc); ptlrpc_req_finished(req); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:01 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:01 -0400 Subject: [lustre-devel] [PATCH 11/28] lustre: llite: use security context if it's enabled in the kernel In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-12-git-send-email-jsimmons@infradead.org> From: Alex Zhuravlev if it's disabled, then Lustre stop to work properly (can not create files, etc) Signed-off-by: Alex Zhuravlev WC-bug-id: https://jira.whamcloud.com/browse/LU-9578 Reviewed-on: https://review.whamcloud.com/27364 Reviewed-by: Andreas Dilger Reviewed-by: Chris Horn Reviewed-by: James Simmons Reviewed-by: Sebastien Buisson Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/llite_lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 22b545e..153aa12 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -243,8 +243,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) if (sbi->ll_flags & LL_SBI_ALWAYS_PING) data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; +#ifdef CONFIG_SECURITY data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; - +#endif data->ocd_brw_size = MD_MAX_BRW_SIZE; err = obd_connect(NULL, &sbi->ll_md_exp, sbi->ll_md_obd, -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:57 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:57 -0400 Subject: [lustre-devel] [PATCH 07/28] lustre: llite: pipeline readahead better with large I/O In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-8-git-send-email-jsimmons@infradead.org> From: Jinshan Xiong Fixed a bug where next readahead is not set correctly when appplication issues large I/O; Extend the readahead window length to at least cover the size of current I/O. Signed-off-by: Jinshan Xiong WC-bug-id: https://jira.whamcloud.com/browse/LU-9574 Reviewed-on: https://review.whamcloud.com/27388 Reviewed-by: Bobi Jam Reviewed-by: Patrick Farrell Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/rw.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 82d874a..9cc0d4fe 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -494,10 +494,8 @@ static int ll_readahead(const struct lu_env *env, struct cl_io *io, end = end_index; ria->ria_eof = true; } - - ras->ras_next_readahead = max(end, end + 1); - RAS_CDEBUG(ras); } + ria->ria_start = start; ria->ria_end = end; /* If stride I/O mode is detected, get stride window*/ @@ -518,6 +516,7 @@ static int ll_readahead(const struct lu_env *env, struct cl_io *io, return 0; } + RAS_CDEBUG(ras); CDEBUG(D_READA, DFID ": ria: %lu/%lu, bead: %lu/%lu, hit: %d\n", PFID(lu_object_fid(&clob->co_lu)), ria->ria_start, ria->ria_end, @@ -555,25 +554,20 @@ static int ll_readahead(const struct lu_env *env, struct cl_io *io, if (ra_end == end && ra_end == (kms >> PAGE_SHIFT)) ll_ra_stats_inc(inode, RA_STAT_EOF); - /* if we didn't get to the end of the region we reserved from - * the ras we need to go back and update the ras so that the - * next read-ahead tries from where we left off. we only do so - * if the region we failed to issue read-ahead on is still ahead - * of the app and behind the next index to start read-ahead from - */ CDEBUG(D_READA, "ra_end = %lu end = %lu stride end = %lu pages = %d\n", ra_end, end, ria->ria_end, ret); - if (ra_end > 0 && ra_end != end) { + if (ra_end != end) ll_ra_stats_inc(inode, RA_STAT_FAILED_REACH_END); + + if (ra_end > 0) { + /* update the ras so that the next read-ahead tries from + * where we left off. + */ spin_lock(&ras->ras_lock); - if (ra_end <= ras->ras_next_readahead && - index_in_window(ra_end, ras->ras_window_start, 0, - ras->ras_window_len)) { - ras->ras_next_readahead = ra_end + 1; - RAS_CDEBUG(ras); - } + ras->ras_next_readahead = ra_end + 1; spin_unlock(&ras->ras_lock); + RAS_CDEBUG(ras); } return ret; @@ -857,7 +851,8 @@ static void ras_update(struct ll_sb_info *sbi, struct inode *inode, * of read-ahead, so we use original offset here, * instead of ras_window_start, which is RPC aligned */ - ras->ras_next_readahead = max(index, ras->ras_next_readahead); + ras->ras_next_readahead = max(index + 1, + ras->ras_next_readahead); ras->ras_window_start = max(ras->ras_stride_offset, ras->ras_window_start); } else { -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:10 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:10 -0400 Subject: [lustre-devel] [PATCH 20/28] lustre: obdclass: deprecate OBD_GET_VERSION ioctl In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-21-git-send-email-jsimmons@infradead.org> From: Andreas Dilger Mark OBD_GET_VERSION ioctl deprecated, disable before 3.1 release. Signed-off-by: Andreas Dilger WC-bug-id: https://jira.whamcloud.com/browse/LU-5969 Reviewed-on: https://review.whamcloud.com/26440 Reviewed-by: James Simmons Reviewed-by: Dmitry Eremin Reviewed-by: John L. Hammond Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/obdclass/class_obd.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c index 2103d2a..c4d820a 100644 --- a/drivers/staging/lustre/lustre/obdclass/class_obd.c +++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c @@ -364,7 +364,15 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) goto out; } - case OBD_GET_VERSION: + case OBD_GET_VERSION: { + static bool warned; + + /* This was the method to pass to user land the lustre version. + * Today that information is in the sysfs tree so we can in the + * future remove this. + */ + BUILD_BUG_ON(OBD_OCD_VERSION(3, 0, 53, 0) <= LUSTRE_VERSION_CODE); + if (!data->ioc_inlbuf1) { CERROR("No buffer passed in ioctl\n"); err = -EINVAL; @@ -377,13 +385,19 @@ int class_handle_ioctl(unsigned int cmd, unsigned long arg) goto out; } + if (!warned) { + warned = true; + CWARN("%s: ioctl(OBD_GET_VERSION) is deprecated, use llapi_get_version_string() and/or relink\n", + current->comm); + } + memcpy(data->ioc_bulk, LUSTRE_VERSION_STRING, strlen(LUSTRE_VERSION_STRING) + 1); if (copy_to_user((void __user *)arg, data, len)) err = -EFAULT; goto out; - + } case OBD_IOC_NAME2DEV: { /* Resolve a device name. This does not change the * currently selected device. -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:07 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:07 -0400 Subject: [lustre-devel] [PATCH 17/28] lustre: ldlm: Make lru clear always discard read lock pages In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-18-git-send-email-jsimmons@infradead.org> From: Patrick Farrell A significant amount of time is sometimes spent during lru clearing (IE, echo 'clear' > lru_size) checking pages to see if they are covered by another read lock. Since all unused read locks will be destroyed by this operation, the pages will be freed momentarily anyway, and this is a waste of time. This patch sets the LDLM_FL_DISCARD_DATA flag on all the PR locks which are slated for cancellation by ldlm_prepare_lru_list when it is called from ldlm_ns_drop_cache. The case where another lock covers those pages (and is in use and so does not get cancelled by lru clear) is safe for a few reasons: 1. When discarding pages, we wait (discard_cb->cl_page_own) until they are in the cached state before invalidating. So if they are actively in use, we'll wait until that use is done. 2. Removal of pages under a read lock is something that can happen due to memory pressure, since these are VFS cache pages. If a client reads something which is then removed from the cache and goes to read it again, this will simply generate a new read request. This has a performance cost for that reader, but if anyone is clearing the ldlm lru while actively doing I/O in that namespace, then they cannot expect good performance. In the case of many read locks on a single resource, this improves cleanup time dramatically. In internal testing at Cray with ~80,000 read locks on a single file, this improves cleanup time from ~60 seconds to ~0.5 seconds. This also slightly improves cleanup speed in the case of 1 or a few read locks on a file. Signed-off-by: Patrick Farrell WC-bug-id: https://jira.whamcloud.com/browse/LU-8276 Reviewed-on: https://review.whamcloud.com/20785 Reviewed-by: Andreas Dilger Reviewed-by: Jinshan Xiong Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/include/lustre_dlm_flags.h | 2 +- drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 6 ++++++ drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 9 +++++++++ drivers/staging/lustre/lustre/ldlm/ldlm_resource.c | 6 ++++-- drivers/staging/lustre/lustre/osc/osc_cache.c | 4 ++-- drivers/staging/lustre/lustre/osc/osc_cl_internal.h | 2 +- drivers/staging/lustre/lustre/osc/osc_lock.c | 10 +++++----- drivers/staging/lustre/lustre/osc/osc_object.c | 2 +- 8 files changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h index 53db031..487ea17 100644 --- a/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h +++ b/drivers/staging/lustre/lustre/include/lustre_dlm_flags.h @@ -95,7 +95,7 @@ #define ldlm_set_flock_deadlock(_l) LDLM_SET_FLAG((_l), 1ULL << 15) #define ldlm_clear_flock_deadlock(_l) LDLM_CLEAR_FLAG((_l), 1ULL << 15) -/** discard (no writeback) on cancel */ +/** discard (no writeback) (PW locks) or page retention (PR locks)) on cancel */ #define LDLM_FL_DISCARD_DATA 0x0000000000010000ULL /* bit 16 */ #define ldlm_is_discard_data(_l) LDLM_TEST_FLAG((_l), 1ULL << 16) #define ldlm_set_discard_data(_l) LDLM_SET_FLAG((_l), 1ULL << 16) diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index 46b2b64..b64e2be0 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -96,6 +96,12 @@ enum { LDLM_LRU_FLAG_NO_WAIT = BIT(4), /* Cancel locks w/o blocking (neither * sending nor waiting for any rpcs) */ + LDLM_LRU_FLAG_CLEANUP = BIT(5), /* Used when clearing lru, tells + * prepare_lru_list to set discard + * flag on PR extent locks so we + * don't waste time saving pages + * that will be discarded momentarily + */ }; int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr, diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index a208c99..ab089e8 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -1360,6 +1360,10 @@ typedef enum ldlm_policy_res (*ldlm_cancel_lru_policy_t)( * (typically before replaying locks) w/o * sending any RPCs or waiting for any * outstanding RPC to complete. + * + * flags & LDLM_CANCEL_CLEANUP - when cancelling read locks, do not check for + * other read locks covering the same pages, just + * discard those pages. */ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns, struct list_head *cancels, int count, int max, @@ -1487,6 +1491,11 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns, */ lock->l_flags |= LDLM_FL_CBPENDING | LDLM_FL_CANCELING; + if ((flags & LDLM_LRU_FLAG_CLEANUP) && + lock->l_resource->lr_type == LDLM_EXTENT && + lock->l_granted_mode == LCK_PR) + ldlm_set_discard_data(lock); + /* We can't re-add to l_lru as it confuses the * refcounting in ldlm_lock_remove_from_lru() if an AST * arrives after we drop lr_lock below. We use l_bl_ast diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c index bd5622d..5028db7 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c @@ -197,7 +197,8 @@ static ssize_t lru_size_store(struct kobject *kobj, struct attribute *attr, /* Try to cancel all @ns_nr_unused locks. */ canceled = ldlm_cancel_lru(ns, unused, 0, - LDLM_LRU_FLAG_PASSED); + LDLM_LRU_FLAG_PASSED | + LDLM_LRU_FLAG_CLEANUP); if (canceled < unused) { CDEBUG(D_DLMTRACE, "not all requested locks are canceled, requested: %d, canceled: %d\n", @@ -208,7 +209,8 @@ static ssize_t lru_size_store(struct kobject *kobj, struct attribute *attr, } else { tmp = ns->ns_max_unused; ns->ns_max_unused = 0; - ldlm_cancel_lru(ns, 0, 0, LDLM_LRU_FLAG_PASSED); + ldlm_cancel_lru(ns, 0, 0, LDLM_LRU_FLAG_PASSED | + LDLM_LRU_FLAG_CLEANUP); ns->ns_max_unused = tmp; } return count; diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 92d292d..5d09a4f 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -3339,7 +3339,7 @@ static int discard_cb(const struct lu_env *env, struct cl_io *io, * behind this being that lock cancellation cannot be delayed indefinitely). */ int osc_lock_discard_pages(const struct lu_env *env, struct osc_object *osc, - pgoff_t start, pgoff_t end, enum cl_lock_mode mode) + pgoff_t start, pgoff_t end, bool discard) { struct osc_thread_info *info = osc_env_info(env); struct cl_io *io = &info->oti_io; @@ -3353,7 +3353,7 @@ int osc_lock_discard_pages(const struct lu_env *env, struct osc_object *osc, if (result != 0) goto out; - cb = mode == CLM_READ ? check_and_discard_cb : discard_cb; + cb = discard ? discard_cb : check_and_discard_cb; info->oti_fn_index = start; info->oti_next_index = start; do { diff --git a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h index da04c2c..4b01809 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cl_internal.h +++ b/drivers/staging/lustre/lustre/osc/osc_cl_internal.h @@ -670,7 +670,7 @@ int osc_extent_finish(const struct lu_env *env, struct osc_extent *ext, void osc_extent_release(const struct lu_env *env, struct osc_extent *ext); int osc_lock_discard_pages(const struct lu_env *env, struct osc_object *osc, - pgoff_t start, pgoff_t end, enum cl_lock_mode mode); + pgoff_t start, pgoff_t end, bool discard_pages); typedef int (*osc_page_gang_cbt)(const struct lu_env *, struct cl_io *, struct osc_page *, void *); diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c index 6059dba..4cc813d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_lock.c +++ b/drivers/staging/lustre/lustre/osc/osc_lock.c @@ -380,7 +380,7 @@ static int osc_lock_upcall_agl(void *cookie, struct lustre_handle *lockh, } static int osc_lock_flush(struct osc_object *obj, pgoff_t start, pgoff_t end, - enum cl_lock_mode mode, int discard) + enum cl_lock_mode mode, bool discard) { struct lu_env *env; u16 refcheck; @@ -401,7 +401,7 @@ static int osc_lock_flush(struct osc_object *obj, pgoff_t start, pgoff_t end, rc = 0; } - rc2 = osc_lock_discard_pages(env, obj, start, end, mode); + rc2 = osc_lock_discard_pages(env, obj, start, end, discard); if (rc == 0 && rc2 < 0) rc = rc2; @@ -417,10 +417,10 @@ static int osc_dlm_blocking_ast0(const struct lu_env *env, struct ldlm_lock *dlmlock, void *data, int flag) { + enum cl_lock_mode mode = CLM_READ; struct cl_object *obj = NULL; int result = 0; - int discard; - enum cl_lock_mode mode = CLM_READ; + bool discard; LASSERT(flag == LDLM_CB_CANCELING); @@ -1098,7 +1098,7 @@ static void osc_lock_lockless_cancel(const struct lu_env *env, LASSERT(!ols->ols_dlmlock); result = osc_lock_flush(osc, descr->cld_start, descr->cld_end, - descr->cld_mode, 0); + descr->cld_mode, false); if (result) CERROR("Pages for lockless lock %p were not purged(%d)\n", ols, result); diff --git a/drivers/staging/lustre/lustre/osc/osc_object.c b/drivers/staging/lustre/lustre/osc/osc_object.c index a86d4c2..e9ecb77 100644 --- a/drivers/staging/lustre/lustre/osc/osc_object.c +++ b/drivers/staging/lustre/lustre/osc/osc_object.c @@ -462,7 +462,7 @@ int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc) osc_cache_truncate_start(env, osc, 0, NULL); /* Discard all caching pages */ - osc_lock_discard_pages(env, osc, 0, CL_PAGE_EOF, CLM_WRITE); + osc_lock_discard_pages(env, osc, 0, CL_PAGE_EOF, true); /* Clear ast data of dlm lock. Do this after discarding all pages */ osc_object_prune(env, osc2cl(osc)); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:09 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:09 -0400 Subject: [lustre-devel] [PATCH 19/28] lustre: uapi: add missing headers in lustre UAPI headers In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-20-git-send-email-jsimmons@infradead.org> A test move was done in the linux kernel that moved the UAPI headers to their proper place. Errors were reported mainly due to linux/types.h being missing. Add in linux/types.h to prepare for the move out of staging. Signed-off-by: James Simmons WC-bug-id: https://jira.whamcloud.com/browse/ Reviewed-on: https://review.whamcloud.com/31737 Reviewed-by: Andreas Dilger Reviewed-by: James Nunez Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h | 2 ++ drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h | 1 + drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h | 1 + drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h | 1 + drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h | 1 + drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h | 1 + drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h | 1 + 7 files changed, 8 insertions(+) diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h index c4d9472..2672fe7 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_debug.h @@ -38,6 +38,8 @@ #ifndef __UAPI_LIBCFS_DEBUG_H__ #define __UAPI_LIBCFS_DEBUG_H__ +#include + /** * Format for debug message headers */ diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h index cccb32d..9d53c51 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnetctl.h @@ -15,6 +15,7 @@ #ifndef _LNETCTL_H_ #define _LNETCTL_H_ +#include #include /** \addtogroup lnet_fault_simulation diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h b/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h index 3354e5a..3c5901d 100644 --- a/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h +++ b/drivers/staging/lustre/include/uapi/linux/lnet/nidstr.h @@ -28,6 +28,7 @@ #ifndef _LNET_NIDSTRINGS_H #define _LNET_NIDSTRINGS_H +#include #include /** diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h index 11b51d9..0620e49 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_cfg.h @@ -35,6 +35,7 @@ #include #include +#include #include /** \defgroup cfg cfg diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h index 2e7a8d1..746bf7a 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fid.h @@ -37,6 +37,7 @@ #ifndef _UAPI_LUSTRE_FID_H_ #define _UAPI_LUSTRE_FID_H_ +#include #include /** returns fid object sequence */ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h index d375a47..d24a93e 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_fiemap.h @@ -41,6 +41,7 @@ #include #include +#include /* XXX: We use fiemap_extent::fe_reserved[0] */ #define fe_device fe_reserved[0] diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h index 3343b60..4b5f110 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ostid.h @@ -35,6 +35,7 @@ #define _UAPI_LUSTRE_OSTID_H_ #include +#include #include static inline __u64 lmm_oi_id(const struct ost_id *oi) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:13 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:13 -0400 Subject: [lustre-devel] [PATCH 23/28] lustre: llog: fix EOF handling in llog_client_next_block() In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-24-git-send-email-jsimmons@infradead.org> From: "John L. Hammond" In llog_client_next_block() update *cur_idx and *cur_offset in the special case that the handler has returned -EIO after reaching the end of the log without finding the desired record. This fixes client side EOF detection in llog_process_thread(). Signed-off-by: John L. Hammond WC-bug-id: https://jira.whamcloud.com/browse/LU-10267 Reviewed-on: https://review.whamcloud.com/30313 Reviewed-by: Mike Pershin Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ptlrpc/llog_client.c | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c index 946d538..6ddd93c 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/llog_client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/llog_client.c @@ -171,8 +171,21 @@ static int llog_client_next_block(const struct lu_env *env, req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_SERVER, len); ptlrpc_request_set_replen(req); rc = ptlrpc_queue_wait(req); - if (rc) + /* -EIO has a special meaning here. If llog_osd_next_block() + * reaches the end of the log without finding the desired + * record then it updates *cur_offset and *cur_idx and returns + * -EIO. In llog_process_thread() we use this to detect + * EOF. But we must be careful to distinguish between -EIO + * coming from llog_osd_next_block() and -EIO coming from + * ptlrpc or below. + */ + if (rc == -EIO) { + if (!req->rq_repmsg || + lustre_msg_get_status(req->rq_repmsg) != -EIO) + goto out; + } else if (rc < 0) { goto out; + } body = req_capsule_server_get(&req->rq_pill, &RMF_LLOGD_BODY); if (!body) { @@ -180,6 +193,12 @@ static int llog_client_next_block(const struct lu_env *env, goto out; } + *cur_idx = body->lgd_saved_index; + *cur_offset = body->lgd_cur_offset; + + if (rc < 0) + goto out; + /* The log records are swabbed as they are processed */ ptr = req_capsule_server_get(&req->rq_pill, &RMF_EADATA); if (!ptr) { @@ -187,9 +206,6 @@ static int llog_client_next_block(const struct lu_env *env, goto out; } - *cur_idx = body->lgd_saved_index; - *cur_offset = body->lgd_cur_offset; - memcpy(buf, ptr, len); out: ptlrpc_req_finished(req); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:03 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:03 -0400 Subject: [lustre-devel] [PATCH 13/28] lustre: ldlm: check lock cancellation in ldlm_cli_cancel() In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-14-git-send-email-jsimmons@infradead.org> From: Jinshan Xiong In that case, the assert for 'list_empty(&lock->l_bl_ast)' will fail because the lock is already in a cancel list. This patch checks if the lock is already being canceled in prior. Signed-off-by: Jinshan Xiong WC-bug-id: https://jira.whamcloud.com/browse/LU-9997 Reviewed-on: https://review.whamcloud.com/29080 Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 13 +++++++++++++ drivers/staging/lustre/lustre/ldlm/ldlm_lock.c | 13 ------------- drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 6 +++++- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index 709c527..46b2b64 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -299,6 +299,19 @@ static inline int is_granted_or_cancelled(struct ldlm_lock *lock) return ret; } +static inline bool is_bl_done(struct ldlm_lock *lock) +{ + bool bl_done = true; + + if (!ldlm_is_bl_done(lock)) { + lock_res_and_lock(lock); + bl_done = ldlm_is_bl_done(lock); + unlock_res_and_lock(lock); + } + + return bl_done; +} + typedef void (*ldlm_policy_wire_to_local_t)(const union ldlm_wire_policy_data *, union ldlm_policy_data *); diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c index bc6b122..ebdfc11 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lock.c @@ -1832,19 +1832,6 @@ int ldlm_run_ast_work(struct ldlm_namespace *ns, struct list_head *rpc_list, return rc; } -static bool is_bl_done(struct ldlm_lock *lock) -{ - bool bl_done = true; - - if (!ldlm_is_bl_done(lock)) { - lock_res_and_lock(lock); - bl_done = ldlm_is_bl_done(lock); - unlock_res_and_lock(lock); - } - - return bl_done; -} - /** * Helper function to call blocking AST for LDLM lock \a lock in a * "cancelling" mode. diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 3eb5036..a208c99 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -1026,8 +1026,12 @@ int ldlm_cli_cancel(const struct lustre_handle *lockh, lock_res_and_lock(lock); /* Lock is being canceled and the caller doesn't want to wait */ - if (ldlm_is_canceling(lock) && (cancel_flags & LCF_ASYNC)) { + if (ldlm_is_canceling(lock)) { unlock_res_and_lock(lock); + + if (!(cancel_flags & LCF_ASYNC)) + wait_event_idle(lock->l_waitq, is_bl_done(lock)); + LDLM_LOCK_RELEASE(lock); return 0; } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:04 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:04 -0400 Subject: [lustre-devel] [PATCH 14/28] lustre: ptlrpc: handle case of epp_free_pages <= PTLRPC_MAX_BRW_PAGES In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-15-git-send-email-jsimmons@infradead.org> From: Bob Glossman Current code where page_pools.epp_free_pages is too small isn't handled correctly. This mod fixes those instances. Signed-off-by: Bob Glossman WC-bug-id: https://jira.whamcloud.com/browse/LU-9458 Reviewed-on: https://review.whamcloud.com/27016 Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c index 3d336d9..03bc95f 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c @@ -232,7 +232,8 @@ static unsigned long enc_pools_shrink_count(struct shrinker *s, } LASSERT(page_pools.epp_idle_idx <= IDLE_IDX_MAX); - return max(page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES, 0UL) * + return (page_pools.epp_free_pages <= PTLRPC_MAX_BRW_PAGES) ? 0 : + (page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES) * (IDLE_IDX_MAX - page_pools.epp_idle_idx) / IDLE_IDX_MAX; } @@ -243,8 +244,12 @@ static unsigned long enc_pools_shrink_scan(struct shrinker *s, struct shrink_control *sc) { spin_lock(&page_pools.epp_lock); - sc->nr_to_scan = min_t(unsigned long, sc->nr_to_scan, - page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES); + if (page_pools.epp_free_pages > PTLRPC_MAX_BRW_PAGES) + sc->nr_to_scan = min_t(unsigned long, sc->nr_to_scan, + page_pools.epp_free_pages - + PTLRPC_MAX_BRW_PAGES); + else + sc->nr_to_scan = 0; if (sc->nr_to_scan > 0) { enc_pools_release_free_pages(sc->nr_to_scan); CDEBUG(D_SEC, "released %ld pages, %ld left\n", -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:12 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:12 -0400 Subject: [lustre-devel] [PATCH 22/28] lustre: clio: update spare bit handling In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-23-git-send-email-jsimmons@infradead.org> Turn the OP_ATTR_* values into an enum and rename them to make their purpose clear. Signed-off-by: James Simmons WC-bug-id: https://jira.whamcloud.com/browse/LU-10030 Reviewed-on: https://review.whamcloud.com/32825 Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Reviewed-by: Wang Shilong Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/include/cl_object.h | 2 +- drivers/staging/lustre/lustre/include/obd.h | 16 +++++++++------- drivers/staging/lustre/lustre/llite/file.c | 4 ++-- drivers/staging/lustre/lustre/llite/lcommon_cl.c | 2 +- drivers/staging/lustre/lustre/llite/llite_internal.h | 4 ++-- drivers/staging/lustre/lustre/llite/llite_lib.c | 18 +++++++++--------- drivers/staging/lustre/lustre/mdc/mdc_lib.c | 10 +++++----- drivers/staging/lustre/lustre/osc/osc_io.c | 6 +++--- 8 files changed, 32 insertions(+), 30 deletions(-) diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 382bfe8..9ff1ca5 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -1778,7 +1778,7 @@ struct cl_io { struct ost_lvb sa_attr; unsigned int sa_attr_flags; unsigned int sa_avalid; - unsigned int sa_xvalid; + unsigned int sa_xvalid; /* OP_XVALID */ int sa_stripe_index; const struct lu_fid *sa_parent_fid; } ci_setattr; diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 76ae0b3..cf3dbd6 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -664,6 +664,14 @@ struct obd_device { #define KEY_CACHE_SET "cache_set" #define KEY_CACHE_LRU_SHRINK "cache_lru_shrink" +/* Flags for op_xvalid */ +enum op_xvalid { + OP_XVALID_CTIME_SET = BIT(0), /* 0x0001 */ + OP_XVALID_BLOCKS = BIT(1), /* 0x0002 */ + OP_XVALID_OWNEROVERRIDE = BIT(2), /* 0x0004 */ + OP_XVALID_FLAGS = BIT(3), /* 0x0008 */ +}; + struct lu_context; static inline int it_to_lock_mode(struct lookup_intent *it) @@ -733,7 +741,7 @@ struct md_op_data { /* iattr fields and blocks. */ struct iattr op_attr; - unsigned int op_xvalid; /* eXtra validity flags */ + enum op_xvalid op_xvalid; /* eXtra validity flags */ unsigned int op_attr_flags; __u64 op_valid; loff_t op_attr_blocks; @@ -764,12 +772,6 @@ struct md_op_data { __u32 op_default_stripe_offset; }; -/* Flags for op_xvalid */ -#define OP_ATTR_CTIME_SET (1 << 0) -#define OP_ATTR_BLOCKS (1 << 1) -#define OP_ATTR_OWNEROVERRIDE (1 << 2) -#define OP_ATTR_FLAGS (1 << 3) - struct md_callback { int (*md_blocking_ast)(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 3bfc6d84..d80bda4 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -96,7 +96,7 @@ static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data, op_data->op_attr.ia_valid |= (ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET | ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME); - op_data->op_xvalid |= OP_ATTR_CTIME_SET; + op_data->op_xvalid |= OP_XVALID_CTIME_SET; op_data->op_attr_blocks = inode->i_blocks; op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags); op_data->op_handle = och->och_fh; @@ -163,7 +163,7 @@ static int ll_close_inode_openhandle(struct inode *inode, op_data->op_data_version = *(__u64 *)data; op_data->op_lease_handle = och->och_lease_handle; op_data->op_attr.ia_valid |= ATTR_SIZE; - op_data->op_xvalid |= OP_ATTR_BLOCKS; + op_data->op_xvalid |= OP_XVALID_BLOCKS; break; default: diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c index 20a3c74..ade3b12 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c @@ -80,7 +80,7 @@ static DEFINE_MUTEX(cl_inode_fini_guard); int cl_setattr_ost(struct cl_object *obj, const struct iattr *attr, - unsigned int xvalid, unsigned int attr_flags) + enum op_xvalid xvalid, unsigned int attr_flags) { struct lu_env *env; struct cl_io *io; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 796a8ae..ad380f1 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -843,7 +843,7 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request, void ll_dir_clear_lsm_md(struct inode *inode); void ll_clear_inode(struct inode *inode); int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, - unsigned int xvalid, bool hsm_import); + enum op_xvalid xvalid, bool hsm_import); int ll_setattr(struct dentry *de, struct iattr *attr); int ll_statfs(struct dentry *de, struct kstatfs *sfs); int ll_statfs_internal(struct ll_sb_info *sbi, struct obd_statfs *osfs, @@ -1357,7 +1357,7 @@ int ll_page_sync_io(const struct lu_env *env, struct cl_io *io, /* lcommon_cl.c */ int cl_setattr_ost(struct cl_object *obj, const struct iattr *attr, - unsigned int xvalid, unsigned int attr_flags); + enum op_xvalid xvalid, unsigned int attr_flags); extern struct lu_env *cl_inode_fini_env; extern u16 cl_inode_fini_refcheck; diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 153aa12..a5e65db 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1492,7 +1492,7 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data) * In case of HSMimport, we only set attr on MDS. */ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, - unsigned int xvalid, bool hsm_import) + enum op_xvalid xvalid, bool hsm_import) { struct inode *inode = d_inode(dentry); struct ll_inode_info *lli = ll_i2info(inode); @@ -1531,10 +1531,10 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, } /* We mark all of the fields "set" so MDS/OST does not re-set them */ - if (!(xvalid & OP_ATTR_CTIME_SET) && + if (!(xvalid & OP_XVALID_CTIME_SET) && attr->ia_valid & ATTR_CTIME) { attr->ia_ctime = current_time(inode); - xvalid |= OP_ATTR_CTIME_SET; + xvalid |= OP_XVALID_CTIME_SET; } if (!(attr->ia_valid & ATTR_ATIME_SET) && (attr->ia_valid & ATTR_ATIME)) { @@ -1570,7 +1570,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, * If we are changing file size, file content is * modified, flag it. */ - xvalid |= OP_ATTR_OWNEROVERRIDE; + xvalid |= OP_XVALID_OWNEROVERRIDE; op_data->op_bias |= MDS_DATA_MODIFIED; clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags); } @@ -1589,7 +1589,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, if (attr->ia_valid & (ATTR_SIZE | ATTR_ATIME | ATTR_ATIME_SET | ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME) || - xvalid & OP_ATTR_CTIME_SET) { + xvalid & OP_XVALID_CTIME_SET) { /* For truncate and utimes sending attributes to OSTs, setting * mtime/atime to the past will be performed under PW [0:EOF] * extent lock (new_size:EOF for truncate). It may seem @@ -1655,11 +1655,11 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, int ll_setattr(struct dentry *de, struct iattr *attr) { int mode = d_inode(de)->i_mode; - unsigned int xvalid = 0; + enum op_xvalid xvalid = 0; if ((attr->ia_valid & (ATTR_CTIME | ATTR_SIZE | ATTR_MODE)) == (ATTR_CTIME | ATTR_SIZE | ATTR_MODE)) - xvalid |= OP_ATTR_OWNEROVERRIDE; + xvalid |= OP_XVALID_OWNEROVERRIDE; if (((attr->ia_valid & (ATTR_MODE | ATTR_FORCE | ATTR_SIZE)) == (ATTR_SIZE | ATTR_MODE)) && @@ -2014,7 +2014,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, return PTR_ERR(op_data); op_data->op_attr_flags = flags; - op_data->op_xvalid |= OP_ATTR_FLAGS; + op_data->op_xvalid |= OP_XVALID_FLAGS; rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, &req); ll_finish_md_op_data(op_data); ptlrpc_req_finished(req); @@ -2031,7 +2031,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, if (!attr) return -ENOMEM; - rc = cl_setattr_ost(obj, attr, OP_ATTR_FLAGS, flags); + rc = cl_setattr_ost(obj, attr, OP_XVALID_FLAGS, flags); kfree(attr); return rc; } diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index fc5a51d..1ab1ad2 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -266,7 +266,7 @@ void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data, set_mrc_cr_flags(rec, cr_flags); } -static inline __u64 attr_pack(unsigned int ia_valid, unsigned int ia_xvalid) +static inline u64 attr_pack(unsigned int ia_valid, enum op_xvalid ia_xvalid) { __u64 sa_valid = 0; @@ -290,19 +290,19 @@ static inline __u64 attr_pack(unsigned int ia_valid, unsigned int ia_xvalid) sa_valid |= MDS_ATTR_MTIME_SET; if (ia_valid & ATTR_FORCE) sa_valid |= MDS_ATTR_FORCE; - if (ia_xvalid & OP_ATTR_FLAGS) + if (ia_xvalid & OP_XVALID_FLAGS) sa_valid |= MDS_ATTR_ATTR_FLAG; if (ia_valid & ATTR_KILL_SUID) sa_valid |= MDS_ATTR_KILL_SUID; if (ia_valid & ATTR_KILL_SGID) sa_valid |= MDS_ATTR_KILL_SGID; - if (ia_xvalid & OP_ATTR_CTIME_SET) + if (ia_xvalid & OP_XVALID_CTIME_SET) sa_valid |= MDS_ATTR_CTIME_SET; if (ia_valid & ATTR_OPEN) sa_valid |= MDS_ATTR_FROM_OPEN; - if (ia_xvalid & OP_ATTR_BLOCKS) + if (ia_xvalid & OP_XVALID_BLOCKS) sa_valid |= MDS_ATTR_BLOCKS; - if (ia_xvalid & OP_ATTR_OWNEROVERRIDE) + if (ia_xvalid & OP_XVALID_OWNEROVERRIDE) /* NFSD hack (see bug 5781) */ sa_valid |= MDS_OPEN_OWNEROVERRIDE; return sa_valid; diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index e7151ed..dabdf6d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -500,7 +500,7 @@ static int osc_io_setattr_start(const struct lu_env *env, struct osc_async_cbargs *cbargs = &oio->oi_cbarg; __u64 size = io->u.ci_setattr.sa_attr.lvb_size; unsigned int ia_avalid = io->u.ci_setattr.sa_avalid; - unsigned int ia_xvalid = io->u.ci_setattr.sa_xvalid; + enum op_xvalid ia_xvalid = io->u.ci_setattr.sa_xvalid; int result = 0; /* truncate cache dirty pages first */ @@ -528,7 +528,7 @@ static int osc_io_setattr_start(const struct lu_env *env, attr->cat_atime = lvb->lvb_atime; cl_valid |= CAT_ATIME; } - if (ia_xvalid & OP_ATTR_CTIME_SET) { + if (ia_xvalid & OP_XVALID_CTIME_SET) { attr->cat_ctime = lvb->lvb_ctime; cl_valid |= CAT_CTIME; } @@ -567,7 +567,7 @@ static int osc_io_setattr_start(const struct lu_env *env, } else { LASSERT(oio->oi_lockless == 0); } - if (ia_xvalid & OP_ATTR_FLAGS) { + if (ia_xvalid & OP_XVALID_FLAGS) { oa->o_flags = io->u.ci_setattr.sa_attr_flags; oa->o_valid |= OBD_MD_FLFLAGS; } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:16 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:16 -0400 Subject: [lustre-devel] [PATCH 26/28] lustre: mdc: set correct body eadatasize for getxattr() In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-27-git-send-email-jsimmons@infradead.org> From: "John L. Hammond" In mdc_intent_getxattr_pack() set mbo_eadatasize to the size of the xattr values buffer rather than the size of the xattr names buffer. Only the xattr values buffer should be upsized for older MDTs. Signed-off-by: John L. Hammond WC-bug-id: https://jira.whamcloud.com/browse/LU-10912 Reviewed-on: https://review.whamcloud.com/31990 WC-bug-id: https://jira.whamcloud.com/browse/LU-11268 Reviewed-on: https://review.whamcloud.com/33024 Reviewed-by: Andreas Dilger Reviewed-by: Andrew Perepechko Reviewed-by: Fan Yong Reviewed-by: James Simmons Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/mdc/mdc_locks.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 5ec5d78..2cc2378 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -331,6 +331,7 @@ static void mdc_realloc_openmsg(struct ptlrpc_request *req, struct lookup_intent *it, struct md_op_data *op_data) { + u32 ea_vals_buf_size = GA_DEFAULT_EA_VAL_LEN * GA_DEFAULT_EA_NUM; struct ptlrpc_request *req; struct ldlm_intent *lit; int rc, count = 0; @@ -353,13 +354,13 @@ static void mdc_realloc_openmsg(struct ptlrpc_request *req, /* pack the intended request */ mdc_pack_body(req, &op_data->op_fid1, op_data->op_valid, - GA_DEFAULT_EA_NAME_LEN * GA_DEFAULT_EA_NUM, -1, 0); + ea_vals_buf_size, -1, 0); req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_SERVER, GA_DEFAULT_EA_NAME_LEN * GA_DEFAULT_EA_NUM); req_capsule_set_size(&req->rq_pill, &RMF_EAVALS, RCL_SERVER, - GA_DEFAULT_EA_NAME_LEN * GA_DEFAULT_EA_NUM); + ea_vals_buf_size); req_capsule_set_size(&req->rq_pill, &RMF_EAVALS_LENS, RCL_SERVER, sizeof(u32) * GA_DEFAULT_EA_NUM); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:53 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:53 -0400 Subject: [lustre-devel] [PATCH 03/28] lustre: ptlrpc: missing barrier before wake_up In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-4-git-send-email-jsimmons@infradead.org> From: Lai Siyao ptlrpc_client_wake_req() misses a memory barrier, which may cause strange errors. Signed-off-by: Lai Siyao WC-bug-id: https://jira.whamcloud.com/browse/LU-8935 Reviewed-on: https://review.whamcloud.com/26583 Reviewed-by: Andreas Dilger Reviewed-by: Wang Shilong Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/include/lustre_net.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index ce7e98c..468a03e 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -2211,6 +2211,8 @@ static inline int ptlrpc_status_ntoh(int n) static inline void ptlrpc_client_wake_req(struct ptlrpc_request *req) { + /* ensure ptlrpc_register_bulk see rq_resend as set. */ + smp_mb(); if (!req->rq_set) wake_up(&req->rq_reply_waitq); else -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:56 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:56 -0400 Subject: [lustre-devel] [PATCH 06/28] lustre: ldlm: ELC shouldn't wait on lock flush In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-7-git-send-email-jsimmons@infradead.org> From: Andriy Skulysh The commit 08fd034670b5 ("staging: lustre: ldlm: revert the changes for lock canceling policy") removed the fix for LU-4300 when lru_resize is disabled. Introduce ldlm_cancel_aged_no_wait_policy to be used by ELC. Signed-off-by: Andriy Skulysh WC-bug-id: https://jira.whamcloud.com/browse/LU-8578 Seagate-bug-id: MRP-3662 Reviewed-on: https://review.whamcloud.com/22286 Reviewed-by: Vitaly Fertman Reviewed-by: Patrick Farrell Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 1 - drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 51 +++++++++++++++------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h index 1d7c727..709c527 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h @@ -96,7 +96,6 @@ enum { LDLM_LRU_FLAG_NO_WAIT = BIT(4), /* Cancel locks w/o blocking (neither * sending nor waiting for any rpcs) */ - LDLM_LRU_FLAG_LRUR_NO_WAIT = BIT(5), /* LRUR + NO_WAIT */ }; int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr, diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c index 80260b07..3eb5036 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c @@ -579,8 +579,8 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req, req_capsule_filled_sizes(pill, RCL_CLIENT); avail = ldlm_capsule_handles_avail(pill, RCL_CLIENT, canceloff); - flags = ns_connect_lru_resize(ns) ? - LDLM_LRU_FLAG_LRUR_NO_WAIT : LDLM_LRU_FLAG_AGED; + flags = LDLM_LRU_FLAG_NO_WAIT | ns_connect_lru_resize(ns) ? + LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED; to_free = !ns_connect_lru_resize(ns) && opc == LDLM_ENQUEUE ? 1 : 0; @@ -1254,6 +1254,20 @@ static enum ldlm_policy_res ldlm_cancel_aged_policy(struct ldlm_namespace *ns, return ldlm_cancel_no_wait_policy(ns, lock, unused, added, count); } +static enum ldlm_policy_res +ldlm_cancel_aged_no_wait_policy(struct ldlm_namespace *ns, + struct ldlm_lock *lock, + int unused, int added, int count) +{ + enum ldlm_policy_res result; + + result = ldlm_cancel_aged_policy(ns, lock, unused, added, count); + if (result == LDLM_POLICY_KEEP_LOCK) + return result; + + return ldlm_cancel_no_wait_policy(ns, lock, unused, added, count); +} + /** * Callback function for default policy. Makes decision whether to keep \a lock * in LRU for current LRU size \a unused, added in current scan \a added and @@ -1280,26 +1294,32 @@ typedef enum ldlm_policy_res (*ldlm_cancel_lru_policy_t)( int, int); static ldlm_cancel_lru_policy_t -ldlm_cancel_lru_policy(struct ldlm_namespace *ns, int flags) +ldlm_cancel_lru_policy(struct ldlm_namespace *ns, int lru_flags) { - if (flags & LDLM_LRU_FLAG_NO_WAIT) - return ldlm_cancel_no_wait_policy; - if (ns_connect_lru_resize(ns)) { - if (flags & LDLM_LRU_FLAG_SHRINK) + if (lru_flags & LDLM_LRU_FLAG_SHRINK) { /* We kill passed number of old locks. */ return ldlm_cancel_passed_policy; - else if (flags & LDLM_LRU_FLAG_LRUR) - return ldlm_cancel_lrur_policy; - else if (flags & LDLM_LRU_FLAG_PASSED) + } else if (lru_flags & LDLM_LRU_FLAG_LRUR) { + if (lru_flags & LDLM_LRU_FLAG_NO_WAIT) + return ldlm_cancel_lrur_no_wait_policy; + else + return ldlm_cancel_lrur_policy; + } else if (lru_flags & LDLM_LRU_FLAG_PASSED) { return ldlm_cancel_passed_policy; - else if (flags & LDLM_LRU_FLAG_LRUR_NO_WAIT) - return ldlm_cancel_lrur_no_wait_policy; + } } else { - if (flags & LDLM_LRU_FLAG_AGED) - return ldlm_cancel_aged_policy; + if (lru_flags & LDLM_LRU_FLAG_AGED) { + if (lru_flags & LDLM_LRU_FLAG_NO_WAIT) + return ldlm_cancel_aged_no_wait_policy; + else + return ldlm_cancel_aged_policy; + } } + if (lru_flags & LDLM_LRU_FLAG_NO_WAIT) + return ldlm_cancel_no_wait_policy; + return ldlm_cancel_default_policy; } @@ -1344,8 +1364,7 @@ static int ldlm_prepare_lru_list(struct ldlm_namespace *ns, ldlm_cancel_lru_policy_t pf; struct ldlm_lock *lock, *next; int added = 0, unused, remained; - int no_wait = flags & - (LDLM_LRU_FLAG_NO_WAIT | LDLM_LRU_FLAG_LRUR_NO_WAIT); + int no_wait = flags & LDLM_LRU_FLAG_NO_WAIT; spin_lock(&ns->ns_lock); unused = ns->ns_nr_unused; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:02 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:02 -0400 Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-13-git-send-email-jsimmons@infradead.org> From: Alex Zhuravlev Even if there are no RPC requests on the set, there is no need to wake up every second. The thread is woken up when a request is added to the set or when the STOP bit is set, so it is sufficient to only wake up when there are requests on the set to worry about. Signed-off-by: Alex Zhuravlev WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 Reviewed-on: https://review.whamcloud.com/28776 Reviewed-by: Andreas Dilger Reviewed-by: Patrick Farrell Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c index c201a88..5b4977b 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) } } - return rc; + return rc || test_bit(LIOD_STOP, &pc->pc_flags); } /** @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) lu_context_enter(env.le_ses); if (wait_event_idle_timeout(set->set_waitq, ptlrpcd_check(&env, pc), - (timeout ? timeout : 1) * HZ) == 0) + timeout * HZ) == 0) ptlrpc_expired_set(set); lu_context_exit(&env.le_ctx); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:05 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:05 -0400 Subject: [lustre-devel] [PATCH 15/28] lustre: llite: fix for stat under kthread and X86_X32 In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-16-git-send-email-jsimmons@infradead.org> From: Frank Zago Under the following conditions, ll_getattr will flatten the inode number when it shouldn't: - the X86_X32 architecture is defined CONFIG_X86_X32, and not even used, - ll_getattr is called from a kernel thread (though vfs_getattr for instance.) This has the result that inode numbers are different whether the same file is stat'ed from a kernel thread, or from a syscall. For instance, 4198401 vs. 144115205272502273. ll_getattr calls ll_need_32bit_api to determine whether the task is 32 bits. When the combination is kthread+X86_X32, that function returns that the task is 32 bits, which is incorrect, as the kernel is 64 bits. The solution is to check whether the call is from a kernel thread (which is 64 bits) and act consequently. Signed-off-by: Frank Zago WC-bug-id: https://jira.whamcloud.com/browse/LU-9468 Reviewed-on: https://review.whamcloud.com/26992 Reviewed-by: Andreas Dilger Reviewed-by: Dmitry Eremin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/dir.c | 6 +++--- drivers/staging/lustre/lustre/llite/lcommon_cl.c | 2 +- .../staging/lustre/lustre/llite/llite_internal.h | 22 +++++++++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 231b351..19c5e9c 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -202,7 +202,7 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data, { struct ll_sb_info *sbi = ll_i2sbi(inode); __u64 pos = *ppos; - int is_api32 = ll_need_32bit_api(sbi); + bool is_api32 = ll_need_32bit_api(sbi); int is_hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; struct page *page; bool done = false; @@ -296,7 +296,7 @@ static int ll_readdir(struct file *filp, struct dir_context *ctx) struct ll_sb_info *sbi = ll_i2sbi(inode); __u64 pos = lfd ? lfd->lfd_pos : 0; int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; - int api32 = ll_need_32bit_api(sbi); + bool api32 = ll_need_32bit_api(sbi); struct md_op_data *op_data; int rc; @@ -1674,7 +1674,7 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin) struct inode *inode = file->f_mapping->host; struct ll_file_data *fd = LUSTRE_FPRIVATE(file); struct ll_sb_info *sbi = ll_i2sbi(inode); - int api32 = ll_need_32bit_api(sbi); + bool api32 = ll_need_32bit_api(sbi); loff_t ret = -EINVAL; switch (origin) { diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c index 30f17ea..20a3c74 100644 --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c @@ -267,7 +267,7 @@ void cl_inode_fini(struct inode *inode) /** * build inode number from passed @fid */ -__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32) +u64 cl_fid_build_ino(const struct lu_fid *fid, bool api32) { if (BITS_PER_LONG == 32 || api32) return fid_flatten32(fid); diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index dcb2fed..796a8ae 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -651,13 +651,25 @@ static inline struct inode *ll_info2i(struct ll_inode_info *lli) __u32 ll_i2suppgid(struct inode *i); void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2); -static inline int ll_need_32bit_api(struct ll_sb_info *sbi) +static inline bool ll_need_32bit_api(struct ll_sb_info *sbi) { #if BITS_PER_LONG == 32 - return 1; + return true; #elif defined(CONFIG_COMPAT) - return unlikely(in_compat_syscall() || - (sbi->ll_flags & LL_SBI_32BIT_API)); + if (unlikely(sbi->ll_flags & LL_SBI_32BIT_API)) + return true; + +#ifdef CONFIG_X86_X32 + /* in_compat_syscall() returns true when called from a kthread + * and CONFIG_X86_X32 is enabled, which is wrong. So check + * whether the caller comes from a syscall (ie. not a kthread) + * before calling in_compat_syscall(). + */ + if (current->flags & PF_KTHREAD) + return false; +#endif + + return unlikely(in_compat_syscall()); #else return unlikely(sbi->ll_flags & LL_SBI_32BIT_API); #endif @@ -1353,7 +1365,7 @@ int cl_setattr_ost(struct cl_object *obj, const struct iattr *attr, int cl_file_inode_init(struct inode *inode, struct lustre_md *md); void cl_inode_fini(struct inode *inode); -__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32); +u64 cl_fid_build_ino(const struct lu_fid *fid, bool api32); __u32 cl_fid_build_gen(const struct lu_fid *fid); #endif /* LLITE_INTERNAL_H */ -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:11 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:11 -0400 Subject: [lustre-devel] [PATCH 21/28] lustre: llite: enhance vvp_dev data structure naming In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-22-git-send-email-jsimmons@infradead.org> The new code that added struct seq_private to the vvp_dev.c code has very generic naming which doesn't fit the lustre / kernel style. See http://wiki.lustre.org/Lustre_Coding_Style_Guidelines for the naming conventions. Rename the struct seq_private and it fields. Signed-off-by: James Simmons WC-bug-id: https://jira.whamcloud.com/browse/LU-8066 Reviewed-on: https://review.whamcloud.com/33009 Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/vvp_dev.c | 54 ++++++++++++++------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c index 31dc3c0..8cc981b 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c @@ -391,11 +391,11 @@ struct vvp_pgcache_id { struct lu_object_header *vpi_obj; }; -struct seq_private { - struct ll_sb_info *sbi; - struct lu_env *env; - u16 refcheck; - struct cl_object *clob; +struct vvp_seq_private { + struct ll_sb_info *vsp_sbi; + struct lu_env *vsp_env; + u16 vsp_refcheck; + struct cl_object *vsp_clob; }; static void vvp_pgcache_id_unpack(loff_t pos, struct vvp_pgcache_id *id) @@ -542,52 +542,54 @@ static void vvp_pgcache_page_show(const struct lu_env *env, static int vvp_pgcache_show(struct seq_file *f, void *v) { - struct seq_private *priv = f->private; + struct vvp_seq_private *priv = f->private; struct page *vmpage = v; struct cl_page *page; seq_printf(f, "%8lx@" DFID ": ", vmpage->index, - PFID(lu_object_fid(&priv->clob->co_lu))); + PFID(lu_object_fid(&priv->vsp_clob->co_lu))); lock_page(vmpage); - page = cl_vmpage_page(vmpage, priv->clob); + page = cl_vmpage_page(vmpage, priv->vsp_clob); unlock_page(vmpage); put_page(vmpage); if (page) { - vvp_pgcache_page_show(priv->env, f, page); - cl_page_put(priv->env, page); + vvp_pgcache_page_show(priv->vsp_env, f, page); + cl_page_put(priv->vsp_env, page); } else { seq_puts(f, "missing\n"); } - lu_object_ref_del(&priv->clob->co_lu, "dump", current); - cl_object_put(priv->env, priv->clob); + lu_object_ref_del(&priv->vsp_clob->co_lu, "dump", current); + cl_object_put(priv->vsp_env, priv->vsp_clob); return 0; } static void *vvp_pgcache_start(struct seq_file *f, loff_t *pos) { - struct seq_private *priv = f->private; + struct vvp_seq_private *priv = f->private; struct page *ret; - if (priv->sbi->ll_site->ls_obj_hash->hs_cur_bits > + if (priv->vsp_sbi->ll_site->ls_obj_hash->hs_cur_bits > 64 - PGC_OBJ_SHIFT) ret = ERR_PTR(-EFBIG); else - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, - &priv->clob, pos); + ret = vvp_pgcache_find(priv->vsp_env, + &priv->vsp_sbi->ll_cl->cd_lu_dev, + &priv->vsp_clob, pos); return ret; } static void *vvp_pgcache_next(struct seq_file *f, void *v, loff_t *pos) { - struct seq_private *priv = f->private; + struct vvp_seq_private *priv = f->private; struct page *ret; *pos += 1; - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, - &priv->clob, pos); + ret = vvp_pgcache_find(priv->vsp_env, + &priv->vsp_sbi->ll_cl->cd_lu_dev, + &priv->vsp_clob, pos); return ret; } @@ -605,16 +607,16 @@ static void vvp_pgcache_stop(struct seq_file *f, void *v) static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) { - struct seq_private *priv; + struct vvp_seq_private *priv; priv = __seq_open_private(filp, &vvp_pgcache_ops, sizeof(*priv)); if (!priv) return -ENOMEM; - priv->sbi = inode->i_private; - priv->env = cl_env_get(&priv->refcheck); - if (IS_ERR(priv->env)) { - int err = PTR_ERR(priv->env); + priv->vsp_sbi = inode->i_private; + priv->vsp_env = cl_env_get(&priv->vsp_refcheck); + if (IS_ERR(priv->vsp_env)) { + int err = PTR_ERR(priv->vsp_env); seq_release_private(inode, filp); return err; @@ -625,9 +627,9 @@ static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) static int vvp_dump_pgcache_seq_release(struct inode *inode, struct file *file) { struct seq_file *seq = file->private_data; - struct seq_private *priv = seq->private; + struct vvp_seq_private *priv = seq->private; - cl_env_put(priv->env, &priv->refcheck); + cl_env_put(priv->vsp_env, &priv->vsp_refcheck); return seq_release_private(inode, file); } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:15 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:15 -0400 Subject: [lustre-devel] [PATCH 25/28] lustre: llite: disable statahead if starting statahead fail In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-26-git-send-email-jsimmons@infradead.org> From: Lai Siyao Once starting statahead thread fails, it should disable statahead. Current code only does this when "sai != NULL", instead it should check whether current process is opening this dir, so for cases like current file is not the first dirent, or sai allocation fail, it won't retry statahead. Signed-off-by: Lai Siyao WC-bug-id: https://jira.whamcloud.com/browse/LU-10165 Reviewed-on: https://review.whamcloud.com/29817 Reviewed-by: Fan Yong Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/statahead.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 0174a4c..8f3ff7f 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -1512,6 +1512,9 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) task = kthread_create(ll_statahead_thread, parent, "ll_sa_%u", lli->lli_opendir_pid); if (IS_ERR(task)) { + spin_lock(&lli->lli_sa_lock); + lli->lli_sai = NULL; + spin_unlock(&lli->lli_sa_lock); rc = PTR_ERR(task); CERROR("can't start ll_sa thread, rc : %d\n", rc); goto out; @@ -1537,8 +1540,8 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) * that subsequent stat won't waste time to try it. */ spin_lock(&lli->lli_sa_lock); - lli->lli_sa_enabled = 0; - lli->lli_sai = NULL; + if (lli->lli_opendir_pid == current->pid) + lli->lli_sa_enabled = 0; spin_unlock(&lli->lli_sa_lock); if (sai) ll_sai_free(sai); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:00 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:00 -0400 Subject: [lustre-devel] [PATCH 10/28] lustre: llite: Update i_nlink on unlink In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-11-git-send-email-jsimmons@infradead.org> From: Patrick Farrell Currently, the client inode link count is not updated on last unlink. This is fine because the dentries are all gone and the inode is eligible for reclaim, but it's still incorrect. This causes two problems: 1. Inode is not immediately reclaimed 2. i_nlink count is > 0 for a fully unlinked file, which confuses wrapfs On last unlink, the MDT sends back attributes. Use the nlink count from these to update the client inode. Remove null check inherited from ll_get_child_fid, because the inode should never be null on an unlink. Signed-off-by: Patrick Farrell WC-bug-id: https://jira.whamcloud.com/browse/LU-10131 Reviewed-on: https://review.whamcloud.com/29651 Reviewed-by: Ben Evans Reviewed-by: Alexey Lyashkov Reviewed-by: Andrew Perepechko Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/namei.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 09cdf02..f2bd57e 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -1073,6 +1073,7 @@ static int ll_unlink(struct inode *dir, struct dentry *dchild) { struct ptlrpc_request *request = NULL; struct md_op_data *op_data; + struct mdt_body *body; int rc; CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p)\n", @@ -1085,8 +1086,7 @@ static int ll_unlink(struct inode *dir, struct dentry *dchild) if (IS_ERR(op_data)) return PTR_ERR(op_data); - if (dchild->d_inode) - op_data->op_fid3 = *ll_inode2fid(dchild->d_inode); + op_data->op_fid3 = *ll_inode2fid(dchild->d_inode); op_data->op_fid2 = op_data->op_fid3; rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request); @@ -1094,6 +1094,14 @@ static int ll_unlink(struct inode *dir, struct dentry *dchild) if (rc) goto out; + /* + * The server puts attributes in on the last unlink, use them to update + * the link count so the inode can be freed immediately. + */ + body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY); + if (body->mbo_valid & OBD_MD_FLNLINK) + set_nlink(dchild->d_inode, body->mbo_nlink); + ll_update_times(request, dir); ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_UNLINK, 1); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:06 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:06 -0400 Subject: [lustre-devel] [PATCH 16/28] lustre: statahead: missing barrier before wake_up In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-17-git-send-email-jsimmons@infradead.org> From: Lai Siyao A barrier is missing before wake_up() in ll_statahead_interpret(), which may cause 'ls' hang. Under the right conditions a basic 'ls' can fail. The debug logs show: statahead.c:683:ll_statahead_interpret()) sa_entry software rc -13 statahead.c:1666:ll_statahead()) revalidate statahead software: -11. Obviously statahead failure didn't notify 'ls' process in time. The mi_cbdata can be stale so add a barrier before calling wake_up(). Signed-off-by: Lai Siyao Signed-off-by: Bob Glossman WC-bug-id: https://jira.whamcloud.com/browse/LU-9210 Reviewed-on: https://review.whamcloud.com/27330 Reviewed-by: Nathaniel Clark Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/statahead.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 1ad308c..0174a4c 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -680,8 +680,14 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, spin_lock(&lli->lli_sa_lock); if (rc) { - if (__sa_make_ready(sai, entry, rc)) + if (__sa_make_ready(sai, entry, rc)) { + /* LU-9210 : Under the right conditions even 'ls' + * can cause the statahead to fail. Using a memory + * barrier resolves this issue. + */ + smp_mb(); wake_up(&sai->sai_waitq); + } } else { int first = 0; entry->se_minfo = minfo; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:08 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:08 -0400 Subject: [lustre-devel] [PATCH 18/28] lustre: mdc: expose changelog through char devices In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-19-git-send-email-jsimmons@infradead.org> From: Henri Doreau Register one character device per MDT in order to allow non-llapi to read them and to make delivery more efficient. - open() spawns a thread to prefetch records and enqueue them into a local buffer (unless the device is open in write-only mode). - lseek() can be used to jump to a specific record, in which case the offset is a record number (with SEEK_SET) or a number of records to skip (SEEK_CUR). Movement can only be done forward. - read() copies records to userland. No truncation happens, so short reads are likely. - write() is used to transmit control commands to the device. The only available one is changelog_clear, which is done by writing "clear:cl:" into the device. - close() terminates the prefetch thread if any, and releases resources. It is possible to poll() on the device to get notified when new records are available for read. Signed-off-by: Henri Doreau WC-bug-id: https://jira.whamcloud.com/browse/LU-7659 Reviewed-on: https://review.whamcloud.com/18900 Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../include/uapi/linux/lustre/lustre_ioctl.h | 2 +- .../include/uapi/linux/lustre/lustre_kernelcomm.h | 3 - .../lustre/include/uapi/linux/lustre/lustre_user.h | 7 - drivers/staging/lustre/lustre/include/obd.h | 2 + drivers/staging/lustre/lustre/ldlm/ldlm_lib.c | 2 + drivers/staging/lustre/lustre/llite/dir.c | 8 - drivers/staging/lustre/lustre/lmv/lmv_obd.c | 13 - drivers/staging/lustre/lustre/mdc/Makefile | 2 +- drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 722 +++++++++++++++++++++ drivers/staging/lustre/lustre/mdc/mdc_internal.h | 4 + drivers/staging/lustre/lustre/mdc/mdc_request.c | 198 +----- 11 files changed, 745 insertions(+), 218 deletions(-) create mode 100644 drivers/staging/lustre/lustre/mdc/mdc_changelog.c diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h index 6e4e109..098b6451 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h @@ -172,7 +172,7 @@ static inline __u32 obd_ioctl_packlen(struct obd_ioctl_data *data) #define OBD_GET_VERSION _IOWR('f', 144, OBD_IOC_DATA_TYPE) /* OBD_IOC_GSS_SUPPORT _IOWR('f', 145, OBD_IOC_DATA_TYPE) */ /* OBD_IOC_CLOSE_UUID _IOWR('f', 147, OBD_IOC_DATA_TYPE) */ -#define OBD_IOC_CHANGELOG_SEND _IOW('f', 148, OBD_IOC_DATA_TYPE) +/* OBD_IOC_CHANGELOG_SEND _IOW('f', 148, OBD_IOC_DATA_TYPE) */ #define OBD_IOC_GETDEVICE _IOWR('f', 149, OBD_IOC_DATA_TYPE) #define OBD_IOC_FID2PATH _IOWR('f', 150, OBD_IOC_DATA_TYPE) /* lustre/lustre_user.h 151-153 */ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h index 94dadbe..d84a8fc 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h @@ -54,15 +54,12 @@ struct kuc_hdr { __u16 kuc_msglen; } __aligned(sizeof(__u64)); -#define KUC_CHANGELOG_MSG_MAXSIZE (sizeof(struct kuc_hdr) + CR_MAXSIZE) - #define KUC_MAGIC 0x191C /*Lustre9etLinC */ /* kuc_msgtype values are defined in each transport */ enum kuc_transport_type { KUC_TRANSPORT_GENERIC = 1, KUC_TRANSPORT_HSM = 2, - KUC_TRANSPORT_CHANGELOG = 3, }; enum kuc_generic_message_type { diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h index b8525e5..715f1c5 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h @@ -967,13 +967,6 @@ static inline void changelog_remap_rec(struct changelog_rec *rec, rec->cr_flags = (rec->cr_flags & CLF_FLAGMASK) | crf_wanted; } -struct ioc_changelog { - __u64 icc_recno; - __u32 icc_mdtindex; - __u32 icc_id; - __u32 icc_flags; -}; - enum changelog_message_type { CL_RECORD = 10, /* message is a changelog_rec */ CL_EOF = 11, /* at end of current changelog */ diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 11e7ae8..76ae0b3 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -345,6 +345,8 @@ struct client_obd { void *cl_lru_work; /* hash tables for osc_quota_info */ struct rhashtable cl_quota_hash[MAXQUOTAS]; + /* Links to the global list of registered changelog devices */ + struct list_head cl_chg_dev_linkage; }; #define obd2cli_tgt(obd) ((char *)(obd)->u.cli.cl_target_uuid.uuid) diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c index 32eda4f..732ef3a 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c @@ -395,6 +395,8 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) init_waitqueue_head(&cli->cl_mod_rpcs_waitq); cli->cl_mod_tag_bitmap = NULL; + INIT_LIST_HEAD(&cli->cl_chg_dev_linkage); + if (connect_op == MDS_CONNECT) { cli->cl_max_mod_rpcs_in_flight = cli->cl_max_rpcs_in_flight - 1; cli->cl_mod_tag_bitmap = kcalloc(BITS_TO_LONGS(OBD_MAX_RIF_MAX), diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 19c5e9c..36cea8d 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1481,14 +1481,6 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, (void __user *)arg); } - case OBD_IOC_CHANGELOG_SEND: - case OBD_IOC_CHANGELOG_CLEAR: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg, - sizeof(struct ioc_changelog)); - return rc; case OBD_IOC_FID2PATH: return ll_fid2path(inode, (void __user *)arg); case LL_IOC_GETPARENT: diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 952c68e..32bb9fc 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -951,19 +951,6 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp, kfree(oqctl); break; } - case OBD_IOC_CHANGELOG_SEND: - case OBD_IOC_CHANGELOG_CLEAR: { - struct ioc_changelog *icc = karg; - - if (icc->icc_mdtindex >= count) - return -ENODEV; - - tgt = lmv->tgts[icc->icc_mdtindex]; - if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) - return -ENODEV; - rc = obd_iocontrol(cmd, tgt->ltd_exp, sizeof(*icc), icc, NULL); - break; - } case LL_IOC_GET_CONNECT_FLAGS: { tgt = lmv->tgts[0]; diff --git a/drivers/staging/lustre/lustre/mdc/Makefile b/drivers/staging/lustre/lustre/mdc/Makefile index 64cf49e..5f48e91 100644 --- a/drivers/staging/lustre/lustre/mdc/Makefile +++ b/drivers/staging/lustre/lustre/mdc/Makefile @@ -2,4 +2,4 @@ ccflags-y += -I$(srctree)/drivers/staging/lustre/include ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include obj-$(CONFIG_LUSTRE_FS) += mdc.o -mdc-y := mdc_request.o mdc_reint.o mdc_lib.o mdc_locks.o lproc_mdc.o +mdc-y := mdc_changelog.o mdc_request.o mdc_reint.o mdc_lib.o mdc_locks.o lproc_mdc.o diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c new file mode 100644 index 0000000..a5f3c64 --- /dev/null +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c @@ -0,0 +1,722 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2017, Commissariat a l'Energie Atomique et aux Energies + * Alternatives. + * + * Author: Henri Doreau + */ + +#define DEBUG_SUBSYSTEM S_MDC + +#include +#include +#include +#include + +#include + +#include "mdc_internal.h" + +/* + * -- Changelog delivery through character device -- + */ + +/** + * Mutex to protect chlg_registered_devices below + */ +static DEFINE_MUTEX(chlg_registered_dev_lock); + +/** + * Global linked list of all registered devices (one per MDT). + */ +static LIST_HEAD(chlg_registered_devices); + +struct chlg_registered_dev { + /* Device name of the form "changelog-{MDTNAME}" */ + char ced_name[32]; + /* Misc device descriptor */ + struct miscdevice ced_misc; + /* OBDs referencing this device (multiple mount point) */ + struct list_head ced_obds; + /* Reference counter for proper deregistration */ + struct kref ced_refs; + /* Link within the global chlg_registered_devices */ + struct list_head ced_link; +}; + +struct chlg_reader_state { + /* Shortcut to the corresponding OBD device */ + struct obd_device *crs_obd; + /* An error occurred that prevents from reading further */ + bool crs_err; + /* EOF, no more records available */ + bool crs_eof; + /* Userland reader closed connection */ + bool crs_closed; + /* Desired start position */ + u64 crs_start_offset; + /* Wait queue for the catalog processing thread */ + wait_queue_head_t crs_waitq_prod; + /* Wait queue for the record copy threads */ + wait_queue_head_t crs_waitq_cons; + /* Mutex protecting crs_rec_count and crs_rec_queue */ + struct mutex crs_lock; + /* Number of item in the list */ + u64 crs_rec_count; + /* List of prefetched enqueued_record::enq_linkage_items */ + struct list_head crs_rec_queue; +}; + +struct chlg_rec_entry { + /* Link within the chlg_reader_state::crs_rec_queue list */ + struct list_head enq_linkage; + /* Data (enq_record) field length */ + u64 enq_length; + /* Copy of a changelog record (see struct llog_changelog_rec) */ + struct changelog_rec enq_record[]; +}; + +enum { + /* Number of records to prefetch locally. */ + CDEV_CHLG_MAX_PREFETCH = 1024, +}; + +/** + * ChangeLog catalog processing callback invoked on each record. + * If the current record is eligible to userland delivery, push + * it into the crs_rec_queue where the consumer code will fetch it. + * + * @param[in] env (unused) + * @param[in] llh Client-side handle used to identify the llog + * @param[in] hdr Header of the current llog record + * @param[in,out] data chlg_reader_state passed from caller + * + * @return 0 or LLOG_PROC_* control code on success, negated error on failure. + */ +static int chlg_read_cat_process_cb(const struct lu_env *env, + struct llog_handle *llh, + struct llog_rec_hdr *hdr, void *data) +{ + struct llog_changelog_rec *rec; + struct chlg_reader_state *crs = data; + struct chlg_rec_entry *enq; + size_t len; + int rc; + + LASSERT(crs); + LASSERT(hdr); + + rec = container_of(hdr, struct llog_changelog_rec, cr_hdr); + + if (rec->cr_hdr.lrh_type != CHANGELOG_REC) { + rc = -EINVAL; + CERROR("%s: not a changelog rec %x/%d in llog : rc = %d\n", + crs->crs_obd->obd_name, rec->cr_hdr.lrh_type, + rec->cr.cr_type, rc); + return rc; + } + + /* Skip undesired records */ + if (rec->cr.cr_index < crs->crs_start_offset) + return 0; + + CDEBUG(D_HSM, "%llu %02d%-5s %llu 0x%x t=" DFID " p=" DFID " %.*s\n", + rec->cr.cr_index, rec->cr.cr_type, + changelog_type2str(rec->cr.cr_type), rec->cr.cr_time, + rec->cr.cr_flags & CLF_FLAGMASK, + PFID(&rec->cr.cr_tfid), PFID(&rec->cr.cr_pfid), + rec->cr.cr_namelen, changelog_rec_name(&rec->cr)); + + wait_event_idle(crs->crs_waitq_prod, + (crs->crs_rec_count < CDEV_CHLG_MAX_PREFETCH || + crs->crs_closed)); + + if (crs->crs_closed) + return LLOG_PROC_BREAK; + + len = changelog_rec_size(&rec->cr) + rec->cr.cr_namelen; + enq = kzalloc(sizeof(*enq) + len, GFP_KERNEL); + if (!enq) + return -ENOMEM; + + INIT_LIST_HEAD(&enq->enq_linkage); + enq->enq_length = len; + memcpy(enq->enq_record, &rec->cr, len); + + mutex_lock(&crs->crs_lock); + list_add_tail(&enq->enq_linkage, &crs->crs_rec_queue); + crs->crs_rec_count++; + mutex_unlock(&crs->crs_lock); + + wake_up_all(&crs->crs_waitq_cons); + + return 0; +} + +/** + * Remove record from the list it is attached to and free it. + */ +static void enq_record_delete(struct chlg_rec_entry *rec) +{ + list_del(&rec->enq_linkage); + kfree(rec); +} + +/** + * Release resources associated to a changelog_reader_state instance. + * + * @param crs CRS instance to release. + */ +static void crs_free(struct chlg_reader_state *crs) +{ + struct chlg_rec_entry *rec; + struct chlg_rec_entry *tmp; + + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) + enq_record_delete(rec); + + kfree(crs); +} + +/** + * Record prefetch thread entry point. Opens the changelog catalog and starts + * reading records. + * + * @param[in,out] args chlg_reader_state passed from caller. + * @return 0 on success, negated error code on failure. + */ +static int chlg_load(void *args) +{ + struct chlg_reader_state *crs = args; + struct obd_device *obd = crs->crs_obd; + struct llog_ctxt *ctx = NULL; + struct llog_handle *llh = NULL; + int rc; + + ctx = llog_get_context(obd, LLOG_CHANGELOG_REPL_CTXT); + if (!ctx) { + rc = -ENOENT; + goto err_out; + } + + rc = llog_open(NULL, ctx, &llh, NULL, CHANGELOG_CATALOG, + LLOG_OPEN_EXISTS); + if (rc) { + CERROR("%s: fail to open changelog catalog: rc = %d\n", + obd->obd_name, rc); + goto err_out; + } + + rc = llog_init_handle(NULL, llh, LLOG_F_IS_CAT | LLOG_F_EXT_JOBID, + NULL); + if (rc) { + CERROR("%s: fail to init llog handle: rc = %d\n", + obd->obd_name, rc); + goto err_out; + } + + rc = llog_cat_process(NULL, llh, chlg_read_cat_process_cb, crs, 0, 0); + if (rc < 0) { + CERROR("%s: fail to process llog: rc = %d\n", + obd->obd_name, rc); + goto err_out; + } + +err_out: + crs->crs_err = true; + wake_up_all(&crs->crs_waitq_cons); + + if (llh) + llog_cat_close(NULL, llh); + + if (ctx) + llog_ctxt_put(ctx); + + wait_event_idle(crs->crs_waitq_prod, crs->crs_closed); + crs_free(crs); + return rc; +} + +/** + * Read handler, dequeues records from the chlg_reader_state if any. + * No partial records are copied to userland so this function can return less + * data than required (short read). + * + * @param[in] file File pointer to the character device. + * @param[out] buff Userland buffer where to copy the records. + * @param[in] count Userland buffer size. + * @param[out] ppos File position, updated with the index number of the next + * record to read. + * @return number of copied bytes on success, negated error code on failure. + */ +static ssize_t chlg_read(struct file *file, char __user *buff, size_t count, + loff_t *ppos) +{ + struct chlg_reader_state *crs = file->private_data; + struct chlg_rec_entry *rec; + struct chlg_rec_entry *tmp; + ssize_t written_total = 0; + LIST_HEAD(consumed); + + if (file->f_flags & O_NONBLOCK && crs->crs_rec_count == 0) + return -EAGAIN; + + wait_event_idle(crs->crs_waitq_cons, + crs->crs_rec_count > 0 || crs->crs_eof || crs->crs_err); + + mutex_lock(&crs->crs_lock); + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) { + if (written_total + rec->enq_length > count) + break; + + if (copy_to_user(buff, rec->enq_record, rec->enq_length)) { + if (written_total == 0) + written_total = -EFAULT; + break; + } + + buff += rec->enq_length; + written_total += rec->enq_length; + + crs->crs_rec_count--; + list_move_tail(&rec->enq_linkage, &consumed); + + crs->crs_start_offset = rec->enq_record->cr_index + 1; + } + mutex_unlock(&crs->crs_lock); + + if (written_total > 0) + wake_up_all(&crs->crs_waitq_prod); + + list_for_each_entry_safe(rec, tmp, &consumed, enq_linkage) + enq_record_delete(rec); + + *ppos = crs->crs_start_offset; + + return written_total; +} + +/** + * Jump to a given record index. Helper for chlg_llseek(). + * + * @param[in,out] crs Internal reader state. + * @param[in] offset Desired offset (index record). + * @return 0 on success, negated error code on failure. + */ +static int chlg_set_start_offset(struct chlg_reader_state *crs, u64 offset) +{ + struct chlg_rec_entry *rec; + struct chlg_rec_entry *tmp; + + mutex_lock(&crs->crs_lock); + if (offset < crs->crs_start_offset) { + mutex_unlock(&crs->crs_lock); + return -ERANGE; + } + + crs->crs_start_offset = offset; + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) { + struct changelog_rec *cr = rec->enq_record; + + if (cr->cr_index >= crs->crs_start_offset) + break; + + crs->crs_rec_count--; + enq_record_delete(rec); + } + + mutex_unlock(&crs->crs_lock); + wake_up_all(&crs->crs_waitq_prod); + return 0; +} + +/** + * Move read pointer to a certain record index, encoded as an offset. + * + * @param[in,out] file File pointer to the changelog character device + * @param[in] off Offset to skip, actually a record index, not byte count + * @param[in] whence Relative/Absolute interpretation of the offset + * @return the resulting position on success or negated error code on failure. + */ +static loff_t chlg_llseek(struct file *file, loff_t off, int whence) +{ + struct chlg_reader_state *crs = file->private_data; + loff_t pos; + int rc; + + switch (whence) { + case SEEK_SET: + pos = off; + break; + case SEEK_CUR: + pos = file->f_pos + off; + break; + case SEEK_END: + default: + return -EINVAL; + } + + /* We cannot go backward */ + if (pos < file->f_pos) + return -EINVAL; + + rc = chlg_set_start_offset(crs, pos); + if (rc != 0) + return rc; + + file->f_pos = pos; + return pos; +} + +/** + * Clear record range for a given changelog reader. + * + * @param[in] crs Current internal state. + * @param[in] reader Changelog reader ID (cl1, cl2...) + * @param[in] record Record index up which to clear + * @return 0 on success, negated error code on failure. + */ +static int chlg_clear(struct chlg_reader_state *crs, u32 reader, u64 record) +{ + struct obd_device *obd = crs->crs_obd; + struct changelog_setinfo cs = { + .cs_recno = record, + .cs_id = reader + }; + + return obd_set_info_async(NULL, obd->obd_self_export, + strlen(KEY_CHANGELOG_CLEAR), + KEY_CHANGELOG_CLEAR, sizeof(cs), &cs, NULL); +} + +/** Maximum changelog control command size */ +#define CHLG_CONTROL_CMD_MAX 64 + +/** + * Handle writes() into the changelog character device. Write() can be used + * to request special control operations. + * + * @param[in] file File pointer to the changelog character device + * @param[in] buff User supplied data (written data) + * @param[in] count Number of written bytes + * @param[in] off (unused) + * @return number of written bytes on success, negated error code on failure. + */ +static ssize_t chlg_write(struct file *file, const char __user *buff, + size_t count, loff_t *off) +{ + struct chlg_reader_state *crs = file->private_data; + char *kbuf; + u64 record; + u32 reader; + int rc = 0; + + if (count > CHLG_CONTROL_CMD_MAX) + return -EINVAL; + + kbuf = kzalloc(CHLG_CONTROL_CMD_MAX, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (copy_from_user(kbuf, buff, count)) { + rc = -EFAULT; + goto out_kbuf; + } + + kbuf[CHLG_CONTROL_CMD_MAX - 1] = '\0'; + + if (sscanf(kbuf, "clear:cl%u:%llu", &reader, &record) == 2) + rc = chlg_clear(crs, reader, record); + else + rc = -EINVAL; + +out_kbuf: + kfree(kbuf); + return rc < 0 ? rc : count; +} + +/** + * Find the OBD device associated to a changelog character device. + * @param[in] cdev character device instance descriptor + * @return corresponding OBD device or NULL if none was found. + */ +static struct obd_device *chlg_obd_get(dev_t cdev) +{ + int minor = MINOR(cdev); + struct obd_device *obd = NULL; + struct chlg_registered_dev *curr; + + mutex_lock(&chlg_registered_dev_lock); + list_for_each_entry(curr, &chlg_registered_devices, ced_link) { + if (curr->ced_misc.minor == minor) { + /* take the first available OBD device attached */ + obd = list_first_entry(&curr->ced_obds, + struct obd_device, + u.cli.cl_chg_dev_linkage); + break; + } + } + mutex_unlock(&chlg_registered_dev_lock); + return obd; +} + +/** + * Open handler, initialize internal CRS state and spawn prefetch thread if + * needed. + * @param[in] inode Inode struct for the open character device. + * @param[in] file Corresponding file pointer. + * @return 0 on success, negated error code on failure. + */ +static int chlg_open(struct inode *inode, struct file *file) +{ + struct chlg_reader_state *crs; + struct obd_device *obd = chlg_obd_get(inode->i_rdev); + struct task_struct *task; + int rc; + + if (!obd) + return -ENODEV; + + crs = kzalloc(sizeof(*crs), GFP_KERNEL); + if (!crs) + return -ENOMEM; + + crs->crs_obd = obd; + crs->crs_err = false; + crs->crs_eof = false; + crs->crs_closed = false; + + mutex_init(&crs->crs_lock); + INIT_LIST_HEAD(&crs->crs_rec_queue); + init_waitqueue_head(&crs->crs_waitq_prod); + init_waitqueue_head(&crs->crs_waitq_cons); + + if (file->f_mode & FMODE_READ) { + task = kthread_run(chlg_load, crs, "chlg_load_thread"); + if (IS_ERR(task)) { + rc = PTR_ERR(task); + CERROR("%s: cannot start changelog thread: rc = %d\n", + obd->obd_name, rc); + goto err_crs; + } + } + + file->private_data = crs; + return 0; + +err_crs: + kfree(crs); + return rc; +} + +/** + * Close handler, release resources. + * + * @param[in] inode Inode struct for the open character device. + * @param[in] file Corresponding file pointer. + * @return 0 on success, negated error code on failure. + */ +static int chlg_release(struct inode *inode, struct file *file) +{ + struct chlg_reader_state *crs = file->private_data; + + if (file->f_mode & FMODE_READ) { + crs->crs_closed = true; + wake_up_all(&crs->crs_waitq_prod); + } else { + /* No producer thread, release resource ourselves */ + crs_free(crs); + } + return 0; +} + +/** + * Poll handler, indicates whether the device is readable (new records) and + * writable (always). + * + * @param[in] file Device file pointer. + * @param[in] wait (opaque) + * @return combination of the poll status flags. + */ +static unsigned int chlg_poll(struct file *file, poll_table *wait) +{ + struct chlg_reader_state *crs = file->private_data; + unsigned int mask = 0; + + mutex_lock(&crs->crs_lock); + poll_wait(file, &crs->crs_waitq_cons, wait); + if (crs->crs_rec_count > 0) + mask |= POLLIN | POLLRDNORM; + if (crs->crs_err) + mask |= POLLERR; + if (crs->crs_eof) + mask |= POLLHUP; + mutex_unlock(&crs->crs_lock); + return mask; +} + +static const struct file_operations chlg_fops = { + .owner = THIS_MODULE, + .llseek = chlg_llseek, + .read = chlg_read, + .write = chlg_write, + .open = chlg_open, + .release = chlg_release, + .poll = chlg_poll, +}; + +/** + * This uses obd_name of the form: "testfs-MDT0000-mdc-ffff88006501600" + * and returns a name of the form: "changelog-testfs-MDT0000". + */ +static void get_chlg_name(char *name, size_t name_len, struct obd_device *obd) +{ + int i; + + snprintf(name, name_len, "changelog-%s", obd->obd_name); + + /* Find the 2nd '-' from the end and truncate on it */ + for (i = 0; i < 2; i++) { + char *p = strrchr(name, '-'); + + if (!p) + return; + *p = '\0'; + } +} + +/** + * Find a changelog character device by name. + * All devices registered during MDC setup are listed in a global list with + * their names attached. + */ +static struct chlg_registered_dev * +chlg_registered_dev_find_by_name(const char *name) +{ + struct chlg_registered_dev *dit; + + list_for_each_entry(dit, &chlg_registered_devices, ced_link) + if (strcmp(name, dit->ced_name) == 0) + return dit; + return NULL; +} + +/** + * Find chlg_registered_dev structure for a given OBD device. + * This is bad O(n^2) but for each filesystem: + * - N is # of MDTs times # of mount points + * - this only runs at shutdown + */ +static struct chlg_registered_dev * +chlg_registered_dev_find_by_obd(const struct obd_device *obd) +{ + struct chlg_registered_dev *dit; + struct obd_device *oit; + + list_for_each_entry(dit, &chlg_registered_devices, ced_link) + list_for_each_entry(oit, &dit->ced_obds, + u.cli.cl_chg_dev_linkage) + if (oit == obd) + return dit; + return NULL; +} + +/** + * Changelog character device initialization. + * Register a misc character device with a dynamic minor number, under a name + * of the form: 'changelog-fsname-MDTxxxx'. Reference this OBD device with it. + * + * @param[in] obd This MDC obd_device. + * @return 0 on success, negated error code on failure. + */ +int mdc_changelog_cdev_init(struct obd_device *obd) +{ + struct chlg_registered_dev *exist; + struct chlg_registered_dev *entry; + int rc; + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + get_chlg_name(entry->ced_name, sizeof(entry->ced_name), obd); + + entry->ced_misc.minor = MISC_DYNAMIC_MINOR; + entry->ced_misc.name = entry->ced_name; + entry->ced_misc.fops = &chlg_fops; + + kref_init(&entry->ced_refs); + INIT_LIST_HEAD(&entry->ced_obds); + INIT_LIST_HEAD(&entry->ced_link); + + mutex_lock(&chlg_registered_dev_lock); + exist = chlg_registered_dev_find_by_name(entry->ced_name); + if (exist) { + kref_get(&exist->ced_refs); + list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &exist->ced_obds); + rc = 0; + goto out_unlock; + } + + /* Register new character device */ + rc = misc_register(&entry->ced_misc); + if (rc != 0) + goto out_unlock; + + list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &entry->ced_obds); + list_add_tail(&entry->ced_link, &chlg_registered_devices); + + entry = NULL; /* prevent it from being freed below */ + +out_unlock: + mutex_unlock(&chlg_registered_dev_lock); + kfree(entry); + return rc; +} + +/** + * Deregister a changelog character device whose refcount has reached zero. + */ +static void chlg_dev_clear(struct kref *kref) +{ + struct chlg_registered_dev *entry = container_of(kref, + struct chlg_registered_dev, + ced_refs); + list_del(&entry->ced_link); + misc_deregister(&entry->ced_misc); + kfree(entry); +} + +/** + * Release OBD, decrease reference count of the corresponding changelog device. + */ +void mdc_changelog_cdev_finish(struct obd_device *obd) +{ + struct chlg_registered_dev *dev = chlg_registered_dev_find_by_obd(obd); + + mutex_lock(&chlg_registered_dev_lock); + list_del_init(&obd->u.cli.cl_chg_dev_linkage); + kref_put(&dev->ced_refs, chlg_dev_clear); + mutex_unlock(&chlg_registered_dev_lock); +} diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h index 941a896..6da9046 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h @@ -129,6 +129,10 @@ enum ldlm_mode mdc_lock_match(struct obd_export *exp, __u64 flags, enum ldlm_mode mode, struct lustre_handle *lockh); +int mdc_changelog_cdev_init(struct obd_device *obd); + +void mdc_changelog_cdev_finish(struct obd_device *obd); + static inline int mdc_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req, int opc, struct list_head *cancels, int count) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 8f8e3d2..3692b1c 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -35,7 +35,6 @@ # include # include -# include # include # include # include @@ -1810,174 +1809,6 @@ static int mdc_ioc_hsm_request(struct obd_export *exp, return rc; } -static struct kuc_hdr *changelog_kuc_hdr(char *buf, size_t len, u32 flags) -{ - struct kuc_hdr *lh = (struct kuc_hdr *)buf; - - LASSERT(len <= KUC_CHANGELOG_MSG_MAXSIZE); - - lh->kuc_magic = KUC_MAGIC; - lh->kuc_transport = KUC_TRANSPORT_CHANGELOG; - lh->kuc_flags = flags; - lh->kuc_msgtype = CL_RECORD; - lh->kuc_msglen = len; - return lh; -} - -struct changelog_show { - __u64 cs_startrec; - enum changelog_send_flag cs_flags; - struct file *cs_fp; - char *cs_buf; - struct obd_device *cs_obd; -}; - -static inline char *cs_obd_name(struct changelog_show *cs) -{ - return cs->cs_obd->obd_name; -} - -static int changelog_kkuc_cb(const struct lu_env *env, struct llog_handle *llh, - struct llog_rec_hdr *hdr, void *data) -{ - struct changelog_show *cs = data; - struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr; - struct kuc_hdr *lh; - size_t len; - int rc; - - if (rec->cr_hdr.lrh_type != CHANGELOG_REC) { - rc = -EINVAL; - CERROR("%s: not a changelog rec %x/%d: rc = %d\n", - cs_obd_name(cs), rec->cr_hdr.lrh_type, - rec->cr.cr_type, rc); - return rc; - } - - if (rec->cr.cr_index < cs->cs_startrec) { - /* Skip entries earlier than what we are interested in */ - CDEBUG(D_HSM, "rec=%llu start=%llu\n", - rec->cr.cr_index, cs->cs_startrec); - return 0; - } - - CDEBUG(D_HSM, "%llu %02d%-5s %llu 0x%x t=" DFID " p=" DFID - " %.*s\n", rec->cr.cr_index, rec->cr.cr_type, - changelog_type2str(rec->cr.cr_type), rec->cr.cr_time, - rec->cr.cr_flags & CLF_FLAGMASK, - PFID(&rec->cr.cr_tfid), PFID(&rec->cr.cr_pfid), - rec->cr.cr_namelen, changelog_rec_name(&rec->cr)); - - len = sizeof(*lh) + changelog_rec_size(&rec->cr) + rec->cr.cr_namelen; - - /* Set up the message */ - lh = changelog_kuc_hdr(cs->cs_buf, len, cs->cs_flags); - memcpy(lh + 1, &rec->cr, len - sizeof(*lh)); - - rc = libcfs_kkuc_msg_put(cs->cs_fp, lh); - CDEBUG(D_HSM, "kucmsg fp %p len %zu rc %d\n", cs->cs_fp, len, rc); - - return rc; -} - -static int mdc_changelog_send_thread(void *csdata) -{ - enum llog_flag flags = LLOG_F_IS_CAT; - struct changelog_show *cs = csdata; - struct llog_ctxt *ctxt = NULL; - struct llog_handle *llh = NULL; - struct kuc_hdr *kuch; - int rc; - - CDEBUG(D_HSM, "changelog to fp=%p start %llu\n", - cs->cs_fp, cs->cs_startrec); - - cs->cs_buf = kzalloc(KUC_CHANGELOG_MSG_MAXSIZE, GFP_NOFS); - if (!cs->cs_buf) { - rc = -ENOMEM; - goto out; - } - - /* Set up the remote catalog handle */ - ctxt = llog_get_context(cs->cs_obd, LLOG_CHANGELOG_REPL_CTXT); - if (!ctxt) { - rc = -ENOENT; - goto out; - } - rc = llog_open(NULL, ctxt, &llh, NULL, CHANGELOG_CATALOG, - LLOG_OPEN_EXISTS); - if (rc) { - CERROR("%s: fail to open changelog catalog: rc = %d\n", - cs_obd_name(cs), rc); - goto out; - } - - if (cs->cs_flags & CHANGELOG_FLAG_JOBID) - flags |= LLOG_F_EXT_JOBID; - - rc = llog_init_handle(NULL, llh, flags, NULL); - if (rc) { - CERROR("llog_init_handle failed %d\n", rc); - goto out; - } - - rc = llog_cat_process(NULL, llh, changelog_kkuc_cb, cs, 0, 0); - - /* Send EOF no matter what our result */ - kuch = changelog_kuc_hdr(cs->cs_buf, sizeof(*kuch), cs->cs_flags); - kuch->kuc_msgtype = CL_EOF; - libcfs_kkuc_msg_put(cs->cs_fp, kuch); - -out: - fput(cs->cs_fp); - if (llh) - llog_cat_close(NULL, llh); - if (ctxt) - llog_ctxt_put(ctxt); - kfree(cs->cs_buf); - kfree(cs); - return rc; -} - -static int mdc_ioc_changelog_send(struct obd_device *obd, - struct ioc_changelog *icc) -{ - struct changelog_show *cs; - struct task_struct *task; - int rc; - - /* Freed in mdc_changelog_send_thread */ - cs = kzalloc(sizeof(*cs), GFP_NOFS); - if (!cs) - return -ENOMEM; - - cs->cs_obd = obd; - cs->cs_startrec = icc->icc_recno; - /* matching fput in mdc_changelog_send_thread */ - cs->cs_fp = fget(icc->icc_id); - cs->cs_flags = icc->icc_flags; - - /* - * New thread because we should return to user app before - * writing into our pipe - */ - task = kthread_run(mdc_changelog_send_thread, cs, - "mdc_clg_send_thread"); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - CERROR("%s: can't start changelog thread: rc = %d\n", - cs_obd_name(cs), rc); - kfree(cs); - } else { - rc = 0; - CDEBUG(D_HSM, "%s: started changelog thread\n", - cs_obd_name(cs)); - } - - CERROR("Failed to start changelog thread: %d\n", rc); - return rc; -} - static int mdc_ioc_hsm_ct_start(struct obd_export *exp, struct lustre_kernelcomm *lk); @@ -2087,21 +1918,6 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, return -EINVAL; } switch (cmd) { - case OBD_IOC_CHANGELOG_SEND: - rc = mdc_ioc_changelog_send(obd, karg); - goto out; - case OBD_IOC_CHANGELOG_CLEAR: { - struct ioc_changelog *icc = karg; - struct changelog_setinfo cs = { - .cs_recno = icc->icc_recno, - .cs_id = icc->icc_id - }; - - rc = obd_set_info_async(NULL, exp, strlen(KEY_CHANGELOG_CLEAR), - KEY_CHANGELOG_CLEAR, sizeof(cs), &cs, - NULL); - goto out; - } case OBD_IOC_FID2PATH: rc = mdc_ioc_fid2path(exp, karg); goto out; @@ -2670,12 +2486,22 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg) rc = mdc_llog_init(obd); if (rc) { - CERROR("failed to setup llogging subsystems\n"); + CERROR("%s: failed to setup llogging subsystems: rc = %d\n", + obd->obd_name, rc); goto err_llog_cleanup; } + rc = mdc_changelog_cdev_init(obd); + if (rc) { + CERROR("%s: failed to setup changelog char device: rc = %d\n", + obd->obd_name, rc); + goto err_changelog_cleanup; + } + return 0; +err_changelog_cleanup: + mdc_llog_finish(obd); err_llog_cleanup: ldebugfs_free_md_stats(obd); ptlrpc_lprocfs_unregister_obd(obd); @@ -2714,6 +2540,8 @@ static int mdc_precleanup(struct obd_device *obd) if (obd->obd_type->typ_refcnt <= 1) libcfs_kkuc_group_rem(0, KUC_GRP_HSM); + mdc_changelog_cdev_finish(obd); + obd_cleanup_client_import(obd); ptlrpc_lprocfs_unregister_obd(obd); lprocfs_obd_cleanup(obd); -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:17 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:17 -0400 Subject: [lustre-devel] [PATCH 27/28] lustre: llite: control concurrent statahead instances In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-28-git-send-email-jsimmons@infradead.org> From: Fan Yong It is found that if there are too many concurrent statahead instances, then related statahead RPCs may accumulate on the client import (for MDT) RPC lists (imp_sending_list/imp_delayed_list/imp_unreplied_lis), as to seriously affect the efficiency of spin_lock under the case of MDT overloaded or in recovery. Be as the temporarily solution, restrict the concurrent statahead instances. If want to support more concurrent statahead instances, please consider to decentralize the RPC lists attached on related import. Signed-off-by: Fan Yong WC-bug-id: https://jira.whamcloud.com/browse/LU-11079 Reviewed-on: https://review.whamcloud.com/32690 Reviewed-by: Andreas Dilger Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../staging/lustre/lustre/llite/llite_internal.h | 13 +++++++- drivers/staging/lustre/lustre/llite/llite_lib.c | 1 + drivers/staging/lustre/lustre/llite/lproc_llite.c | 37 ++++++++++++++++++++++ drivers/staging/lustre/lustre/llite/statahead.c | 24 ++++++++++---- 4 files changed, 68 insertions(+), 7 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index ad380f1..359bd53 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -504,6 +504,9 @@ struct ll_sb_info { int ll_rw_stats_on; /* metadata stat-ahead */ + unsigned int ll_sa_running_max; /* max concurrent + * statahead instances + */ unsigned int ll_sa_max; /* max statahead RPCs */ atomic_t ll_sa_total; /* statahead thread started * count @@ -1063,7 +1066,15 @@ enum ras_update_flags { /* statahead.c */ #define LL_SA_RPC_MIN 2 #define LL_SA_RPC_DEF 32 -#define LL_SA_RPC_MAX 8192 +#define LL_SA_RPC_MAX 512 + +/* XXX: If want to support more concurrent statahead instances, + * please consider to decentralize the RPC lists attached + * on related import, such as imp_{sending,delayed}_list. + * LU-11079 + */ +#define LL_SA_RUNNING_MAX 256 +#define LL_SA_RUNNING_DEF 16 #define LL_SA_CACHE_BIT 5 #define LL_SA_CACHE_SIZE (1 << LL_SA_CACHE_BIT) diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index a5e65db..fae7e50 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -116,6 +116,7 @@ static struct ll_sb_info *ll_init_sbi(void) } /* metadata statahead is enabled by default */ + sbi->ll_sa_running_max = LL_SA_RUNNING_DEF; sbi->ll_sa_max = LL_SA_RPC_DEF; atomic_set(&sbi->ll_sa_total, 0); atomic_set(&sbi->ll_sa_wrong, 0); diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c index d8ef090..10dc7a8 100644 --- a/drivers/staging/lustre/lustre/llite/lproc_llite.c +++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c @@ -714,6 +714,42 @@ static ssize_t stats_track_gid_store(struct kobject *kobj, } LUSTRE_RW_ATTR(stats_track_gid); +static ssize_t statahead_running_max_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, + ll_kset.kobj); + + return snprintf(buf, 16, "%u\n", sbi->ll_sa_running_max); +} + +static ssize_t statahead_running_max_store(struct kobject *kobj, + struct attribute *attr, + const char *buffer, + size_t count) +{ + struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info, + ll_kset.kobj); + unsigned long val; + int rc; + + rc = kstrtoul(buffer, 0, &val); + if (rc) + return rc; + + if (val <= LL_SA_RUNNING_MAX) { + sbi->ll_sa_running_max = val; + return count; + } + + CERROR("Bad statahead_running_max value %lu. Valid values are in the range [0, %d]\n", + val, LL_SA_RUNNING_MAX); + + return -ERANGE; +} +LUSTRE_RW_ATTR(statahead_running_max); + static ssize_t statahead_max_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -1171,6 +1207,7 @@ static ssize_t ll_nosquash_nids_seq_write(struct file *file, &lustre_attr_stats_track_pid.attr, &lustre_attr_stats_track_ppid.attr, &lustre_attr_stats_track_gid.attr, + &lustre_attr_statahead_running_max.attr, &lustre_attr_statahead_max.attr, &lustre_attr_statahead_agl.attr, &lustre_attr_lazystatfs.attr, diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 8f3ff7f..336f1cf 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -1472,23 +1472,34 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) struct ll_statahead_info *sai = NULL; struct task_struct *task; struct dentry *parent = dentry->d_parent; - int rc; + struct ll_sb_info *sbi = ll_i2sbi(parent->d_inode); + int first = LS_FIRST_DE; + int rc = 0; /* I am the "lli_opendir_pid" owner, only me can set "lli_sai". */ - rc = is_first_dirent(dir, dentry); - if (rc == LS_NOT_FIRST_DE) { + first = is_first_dirent(dir, dentry); + if (first == LS_NOT_FIRST_DE) { /* It is not "ls -{a}l" operation, no need statahead for it. */ rc = -EFAULT; goto out; } + if (unlikely(atomic_inc_return(&sbi->ll_sa_running) > + sbi->ll_sa_running_max)) { + CDEBUG(D_READA, + "Too many concurrent statahead instances, avoid new statahead instance temporarily.\n"); + rc = -EMFILE; + goto out; + } + + sai = ll_sai_alloc(parent); if (!sai) { rc = -ENOMEM; goto out; } - sai->sai_ls_all = (rc == LS_FIRST_DOT_DE); + sai->sai_ls_all = (first == LS_FIRST_DOT_DE); /* * if current lli_opendir_key was deauthorized, or dir re-opened by * another process, don't start statahead, otherwise the newly spawned @@ -1504,8 +1515,6 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) lli->lli_sai = sai; spin_unlock(&lli->lli_sa_lock); - atomic_inc(&ll_i2sbi(parent->d_inode)->ll_sa_running); - CDEBUG(D_READA, "start statahead thread: [pid %d] [parent %pd]\n", current->pid, parent); @@ -1545,6 +1554,9 @@ static int start_statahead_thread(struct inode *dir, struct dentry *dentry) spin_unlock(&lli->lli_sa_lock); if (sai) ll_sai_free(sai); + if (first != LS_NOT_FIRST_DE) + atomic_dec(&sbi->ll_sa_running); + return rc; } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:18 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:18 -0400 Subject: [lustre-devel] [PATCH 28/28] lustre: llite: restore lld_nfs_dentry handling In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-29-git-send-email-jsimmons@infradead.org> The port of patch for LU-3544 to enable open-by-fid as the default to the linux lustre client was done incorrectly. It ended dropping the handling of lld_nfs_dentry for the NFS export case. Lets restore it. Fixes: c1b66fccf986 ("staging: lustre: fid: do open-by-fid by default") Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/file.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index d80bda4..5df2b87 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -589,6 +589,8 @@ int ll_file_open(struct inode *inode, struct file *file) } else { LASSERT(*och_usecount == 0); if (!it->it_disposition) { + struct ll_dentry_data *ldd = ll_d2d(file->f_path.dentry); + /* We cannot just request lock handle now, new ELC code * means that one of other OPEN locks for this file * could be cancelled, and since blocking ast handler @@ -599,11 +601,24 @@ int ll_file_open(struct inode *inode, struct file *file) /* * Normally called under two situations: * 1. NFS export. - * 2. revalidate with IT_OPEN (revalidate doesn't - * execute this intent any more). + * 2. A race/condition on MDS resulting in no open + * handle to be returned from LOOKUP|OPEN request, + * for example if the target entry was a symlink. * - * Always fetch MDS_OPEN_LOCK if this is not setstripe. + * Only fetch MDS_OPEN_LOCK if this is in NFS path, + * marked by a bit set in ll_iget_for_nfs. Clear the + * bit so that it's not confusing later callers. * + * NB; when ldd is NULL, it must have come via normal + * lookup path only, since ll_iget_for_nfs always calls + * ll_d_init(). + */ + if (ldd && ldd->lld_nfs_dentry) { + ldd->lld_nfs_dentry = 0; + it->it_flags |= MDS_OPEN_LOCK; + } + + /* * Always specify MDS_OPEN_BY_FID because we don't want * to get file with different fid. */ -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:57:55 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:57:55 -0400 Subject: [lustre-devel] [PATCH 05/28] lustre: uapi: add back LUSTRE_MAXFSNAME to lustre_user.h In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-6-git-send-email-jsimmons@infradead.org> The work to turn lustre_param.h into a proper UAPI header removed various user land functions used to validate poolnames and file system names. The checks instead were enforced on the kernel side to ensure any possible user land software directly interfacing to the kernel wouldn't be able to break things badly. For the case of formating the backend file system no kernel interaction doesn't happen until it tries to mount the MDT/OST/MGT which is very late in the process. So for this case lets add back the file system name verification to userland. With bringing this back LUSTRE_MAXFSNAME is needed again since it used by both user land and kernel. For the kernel side use LUSTRE_MAXFSNAME instead of the raw number in the function server_name2fsname() located in obd_mount.c. Signed-off-by: James Simmons WC-bug-id: https://jira.whamcloud.com/browse/LU-9767 Reviewed-on: https://review.whamcloud.com/28070 Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Reviewed-by: Fan Yong Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h | 2 ++ drivers/staging/lustre/lustre/obdclass/obd_mount.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h index 4fa7796..b8525e5 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h @@ -515,6 +515,8 @@ static inline char *obd_uuid2str(const struct obd_uuid *uuid) return (char *)(uuid->uuid); } +#define LUSTRE_MAXFSNAME 8 + /* Extract fsname from uuid (or target name) of a target * e.g. (myfs-OST0007_UUID -> myfs) * see also deuuidify. diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c index 33a67fd..5ed1758 100644 --- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c +++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c @@ -599,7 +599,7 @@ static int server_name2fsname(const char *svname, char *fsname, { const char *dash; - dash = svname + strnlen(svname, 8); /* max fsname length is 8 */ + dash = svname + strnlen(svname, LUSTRE_MAXFSNAME); for (; dash > svname && *dash != '-' && *dash != ':'; dash--) ; if (dash == svname) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 18:58:14 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 14:58:14 -0400 Subject: [lustre-devel] [PATCH 24/28] lustre: llite: IO accounting of page read In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543498-29105-25-git-send-email-jsimmons@infradead.org> From: Hongchao Zhang When CONFIG_TASK_IO_ACCOUNTING is used with Lustre, writes are accounted for but not read. The accounting is normally done in the kernel for page writeback and readahead functionlity, Therefore, as Lustre implements its own readahead, it must also maintain its own accounting on read (but not for write) Signed-off-by: Hongchao Zhang WC-bug-id: https://jira.whamcloud.com/browse/LU-618 Reviewed-on: https://review.whamcloud.com/1636 Reviewed-by: Fan Yong Reviewed-by: Andreas Dilger Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/rw.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/rw.c b/drivers/staging/lustre/lustre/llite/rw.c index 9cc0d4fe..55d8b31 100644 --- a/drivers/staging/lustre/lustre/llite/rw.c +++ b/drivers/staging/lustre/lustre/llite/rw.c @@ -48,6 +48,7 @@ #include /* current_is_kswapd() */ #include +#include #include #define DEBUG_SUBSYSTEM S_LLITE @@ -1137,9 +1138,13 @@ static int ll_io_read_page(const struct lu_env *env, struct cl_io *io, PFID(ll_inode2fid(inode)), rc2, vvp_index(vpg)); } - if (queue->c2_qin.pl_nr > 0) - rc = cl_io_submit_rw(env, io, CRT_READ, queue); + if (queue->c2_qin.pl_nr > 0) { + int count = queue->c2_qin.pl_nr; + rc = cl_io_submit_rw(env, io, CRT_READ, queue); + if (!rc) + task_io_account_read(PAGE_SIZE * count); + } /* * Unlock unsent pages in case of error. */ -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:40 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:40 -0400 Subject: [lustre-devel] [PATCH 1/7] lustre: quota: cleanup codes of quota for new type In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-2-git-send-email-jsimmons@infradead.org> From: Oleg Drokin This patch cleanups codes of quota to prepare for new type other than USRQUOTA/GRPQUOTA. Signed-off-by: Li Xi Signed-off-by: Wang Shilong Signed-off-by: Oleg Drokin WC-bug-id: https://jira.whamcloud.com/browse/LU-4017 Reviewed-on: https://review.whamcloud.com/18894 Reviewed-by: Niu Yawei Signed-off-by: James Simmons --- .../lustre/include/uapi/linux/lustre/lustre_idl.h | 2 ++ .../lustre/include/uapi/linux/lustre/lustre_user.h | 13 ++++++- drivers/staging/lustre/lustre/llite/dir.c | 21 ++++++++--- drivers/staging/lustre/lustre/osc/osc_quota.c | 42 ++++++++++++++-------- drivers/staging/lustre/lustre/osc/osc_request.c | 2 +- 5 files changed, 59 insertions(+), 21 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index 66b15c7..9430f11 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1131,6 +1131,8 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) #define OBD_MD_DEFAULT_MEA (0x0040000000000000ULL) /* default MEA */ +#define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA) + #define OBD_MD_FLGETATTR (OBD_MD_FLID | OBD_MD_FLATIME | OBD_MD_FLMTIME | \ OBD_MD_FLCTIME | OBD_MD_FLSIZE | OBD_MD_FLBLKSZ | \ OBD_MD_FLMODE | OBD_MD_FLTYPE | OBD_MD_FLUID | \ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h index 715f1c5..b1961df 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h @@ -567,7 +567,18 @@ static inline void obd_uuid2fsname(char *buf, char *uuid, int buflen) #define LUSTRE_Q_INVALIDATE 0x80000b /* deprecated as of 2.4 */ #define LUSTRE_Q_FINVALIDATE 0x80000c /* deprecated as of 2.4 */ -#define UGQUOTA 2 /* set both USRQUOTA and GRPQUOTA */ +#define ALLQUOTA 255 /* set all quota */ + +static inline char *qtype_name(int qtype) +{ + switch (qtype) { + case USRQUOTA: + return "usr"; + case GRPQUOTA: + return "grp"; + } + return "unknown"; +} #define IDENTITY_DOWNCALL_MAGIC 0x6d6dd629 diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 36cea8d..7047938 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -902,6 +902,21 @@ static int copy_and_ioctl(int cmd, struct obd_export *exp, return rc; } +static inline int check_owner(int type, int id) +{ + switch (type) { + case USRQUOTA: + if (!uid_eq(current_euid(), make_kuid(&init_user_ns, id))) + return -EPERM; + break; + case GRPQUOTA: + if (!in_egroup_p(make_kgid(&init_user_ns, id))) + return -EPERM; + break; + } + return 0; +} + static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) { int cmd = qctl->qc_cmd; @@ -917,11 +932,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) return -EPERM; break; case Q_GETQUOTA: - if (((type == USRQUOTA && - !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || - (type == GRPQUOTA && - !in_egroup_p(make_kgid(&init_user_ns, id)))) && - !capable(CAP_SYS_ADMIN)) + if (check_owner(type, id) && !capable(CAP_SYS_ADMIN)) return -EPERM; break; case Q_GETINFO: diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c index 25d06de..13ef482 100644 --- a/drivers/staging/lustre/lustre/osc/osc_quota.c +++ b/drivers/staging/lustre/lustre/osc/osc_quota.c @@ -63,7 +63,7 @@ int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[]) * quota space on this OST */ CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n", - type == USRQUOTA ? "user" : "grout", qid[type]); + qtype_name(type), qid[type]); return -EDQUOT; } } @@ -78,11 +78,29 @@ static void osc_quota_free(struct rcu_head *head) kmem_cache_free(osc_quota_kmem, oqi); } +static inline u32 md_quota_flag(int qtype) +{ + switch (qtype) { + case USRQUOTA: + return OBD_MD_FLUSRQUOTA; + case GRPQUOTA: + return OBD_MD_FLGRPQUOTA; + default: + return 0; + } +} -#define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \ - : OBD_MD_FLGRPQUOTA) -#define FL_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_FL_NO_USRQUOTA \ - : OBD_FL_NO_GRPQUOTA) +static inline u32 fl_quota_flag(int qtype) +{ + switch (qtype) { + case USRQUOTA: + return OBD_FL_NO_USRQUOTA; + case GRPQUOTA: + return OBD_FL_NO_GRPQUOTA; + default: + return 0; + } +} int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], u32 valid, u32 flags) @@ -90,20 +108,20 @@ int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], int type; int rc = 0; - if ((valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) == 0) + if ((valid & (OBD_MD_FLALLQUOTA)) == 0) return 0; for (type = 0; type < MAXQUOTAS; type++) { struct osc_quota_info *oqi; - if ((valid & MD_QUOTA_FLAG(type)) == 0) + if ((valid & md_quota_flag(type)) == 0) continue; /* lookup the ID in the per-type hash table */ rcu_read_lock(); oqi = rhashtable_lookup_fast(&cli->cl_quota_hash[type], &qid[type], quota_hash_params); - if ((flags & FL_QUOTA_FLAG(type)) != 0) { + if ((flags & fl_quota_flag(type)) != 0) { /* This ID is getting close to its quota limit, let's * switch to sync I/O */ @@ -130,9 +148,7 @@ int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], } CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n", - cli_name(cli), - type == USRQUOTA ? "user" : "group", - qid[type], rc); + cli_name(cli), qtype_name(type), qid[type], rc); } else { /* This ID is now off the hook, let's remove it from * the hash table @@ -146,9 +162,7 @@ int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], call_rcu(&oqi->rcu, osc_quota_free); rcu_read_unlock(); CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n", - cli_name(cli), - type == USRQUOTA ? "user" : "group", - qid[type], oqi); + cli_name(cli), qtype_name(type), qid[type], oqi); } } diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 5bab8a3..1d21159 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -1476,7 +1476,7 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc) /* set/clear over quota flag for a uid/gid */ if (lustre_msg_get_opc(req->rq_reqmsg) == OST_WRITE && - body->oa.o_valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA)) { + body->oa.o_valid & OBD_MD_FLALLQUOTA) { unsigned int qid[MAXQUOTAS] = { body->oa.o_uid, body->oa.o_gid }; CDEBUG(D_QUOTA, "setdq for [%u %u] with valid %#llx, flags %x\n", -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:42 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:42 -0400 Subject: [lustre-devel] [PATCH 3/7] lustre: quota: add project id support In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-4-git-send-email-jsimmons@infradead.org> From: Oleg Drokin This patch is infrastructure change for Lustre project quota, project ID is considered as file attribute like UID/GID, MDS will return back project id to client upon open/getattr. Signed-off-by: Wang Shilong Signed-off-by: Oleg Drokin WC-bug-id: https://jira.whamcloud.com/browse/LU-4017 Reviewed-on: https://review.whamcloud.com/25812 Reviewed-by: Li Xi Reviewed-by: Niu Yawei Signed-off-by: James Simmons --- .../lustre/include/uapi/linux/lustre/lustre_idl.h | 9 ++++++--- drivers/staging/lustre/lustre/include/obd.h | 1 + drivers/staging/lustre/lustre/llite/llite_internal.h | 2 ++ drivers/staging/lustre/lustre/llite/llite_lib.c | 2 ++ drivers/staging/lustre/lustre/llite/vvp_object.c | 4 +++- drivers/staging/lustre/lustre/obdclass/obdo.c | 7 +++++++ drivers/staging/lustre/lustre/ptlrpc/pack_generic.c | 8 +++++++- drivers/staging/lustre/lustre/ptlrpc/wiretest.c | 19 +++++++++++++------ 8 files changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index 1220acd..a8ffde2 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1133,6 +1133,7 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) */ #define OBD_MD_DEFAULT_MEA (0x0040000000000000ULL) /* default MEA */ +#define OBD_MD_FLPROJID (0x0100000000000000ULL) /* project ID */ #define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \ OBD_MD_FLGRPQUOTA | \ @@ -1142,7 +1143,8 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) OBD_MD_FLCTIME | OBD_MD_FLSIZE | OBD_MD_FLBLKSZ | \ OBD_MD_FLMODE | OBD_MD_FLTYPE | OBD_MD_FLUID | \ OBD_MD_FLGID | OBD_MD_FLFLAGS | OBD_MD_FLNLINK | \ - OBD_MD_FLGENER | OBD_MD_FLRDEV | OBD_MD_FLGROUP) + OBD_MD_FLGENER | OBD_MD_FLRDEV | OBD_MD_FLGROUP | \ + OBD_MD_FLPROJID) #define OBD_MD_FLXATTRALL (OBD_MD_FLXATTR | OBD_MD_FLXATTRLS) @@ -1515,7 +1517,7 @@ struct mdt_body { __u32 mbo_unused3; /* was max_cookiesize until 2.8 */ __u32 mbo_uid_h; /* high 32-bits of uid, for FUID */ __u32 mbo_gid_h; /* high 32-bits of gid, for FUID */ - __u32 mbo_padding_5; /* also fix lustre_swab_mdt_body */ + __u32 mbo_projid; /* also fix lustre_swab_mdt_body */ __u64 mbo_padding_6; __u64 mbo_padding_7; __u64 mbo_padding_8; @@ -2615,7 +2617,8 @@ struct obdo { * brw: grant space consumed on * the client for the write */ - __u64 o_padding_4; + __u32 o_projid; + __u32 o_padding_4; /* also fix lustre_swab_obdo() */ __u64 o_padding_5; __u64 o_padding_6; }; diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index cf3dbd6..81b4750 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -1028,6 +1028,7 @@ static inline struct md_open_data *obd_mod_alloc(void) void obdo_from_inode(struct obdo *dst, struct inode *src, u32 valid); void obdo_set_parent_fid(struct obdo *dst, const struct lu_fid *parent); +void obdo_set_o_projid(struct obdo *dst, u32 projid); /* return 1 if client should be resend request */ static inline int client_should_resend(int resend, struct client_obd *cli) diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 359bd53..ba9ba49 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -237,6 +237,8 @@ struct ll_inode_info { __u32 lli_layout_gen; spinlock_t lli_layout_lock; + u32 lli_projid; /* project id */ + struct rw_semaphore lli_xattrs_list_rwsem; struct mutex lli_xattrs_enq_lock; struct list_head lli_xattrs;/* ll_xattr_entry->xe_list */ diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index fae7e50..7320dc8 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1859,6 +1859,8 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) inode->i_uid = make_kuid(&init_user_ns, body->mbo_uid); if (body->mbo_valid & OBD_MD_FLGID) inode->i_gid = make_kgid(&init_user_ns, body->mbo_gid); + if (body->mbo_valid & OBD_MD_FLPROJID) + lli->lli_projid = body->mbo_projid; if (body->mbo_valid & OBD_MD_FLFLAGS) inode->i_flags = ll_ext_to_inode_flags(body->mbo_flags); if (body->mbo_valid & OBD_MD_FLNLINK) diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index 301a90d..c1f8b50 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -193,9 +193,11 @@ static void vvp_req_attr_set(const struct lu_env *env, struct cl_object *obj, oa = attr->cra_oa; inode = vvp_object_inode(obj); - if (attr->cra_type == CRT_WRITE) + if (attr->cra_type == CRT_WRITE) { valid_flags |= OBD_MD_FLMTIME | OBD_MD_FLCTIME | OBD_MD_FLUID | OBD_MD_FLGID; + obdo_set_o_projid(oa, ll_i2info(inode)->lli_projid); + } obdo_from_inode(oa, inode, valid_flags & attr->cra_flags); obdo_set_parent_fid(oa, &ll_i2info(inode)->lli_fid); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_INVALID_PFID)) diff --git a/drivers/staging/lustre/lustre/obdclass/obdo.c b/drivers/staging/lustre/lustre/obdclass/obdo.c index 8013c1e..7c65d0d 100644 --- a/drivers/staging/lustre/lustre/obdclass/obdo.c +++ b/drivers/staging/lustre/lustre/obdclass/obdo.c @@ -52,6 +52,13 @@ void obdo_set_parent_fid(struct obdo *dst, const struct lu_fid *parent) } EXPORT_SYMBOL(obdo_set_parent_fid); +void obdo_set_o_projid(struct obdo *dst, u32 projid) +{ + dst->o_projid = projid; + dst->o_valid |= OBD_MD_FLPROJID; +} +EXPORT_SYMBOL(obdo_set_o_projid); + /* WARNING: the file systems must take care not to tinker with * attributes they don't manage (such as blocks). */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c index 96d0377..951bb92 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c +++ b/drivers/staging/lustre/lustre/ptlrpc/pack_generic.c @@ -1614,6 +1614,7 @@ static void lustre_swab_obdo(struct obdo *o) __swab32s(&o->o_uid_h); __swab32s(&o->o_gid_h); __swab64s(&o->o_data_version); + __swab32s(&o->o_projid); BUILD_BUG_ON(offsetof(typeof(*o), o_padding_4) == 0); BUILD_BUG_ON(offsetof(typeof(*o), o_padding_5) == 0); BUILD_BUG_ON(offsetof(typeof(*o), o_padding_6) == 0); @@ -1747,7 +1748,12 @@ void lustre_swab_mdt_body(struct mdt_body *b) BUILD_BUG_ON(!offsetof(typeof(*b), mbo_unused3)); __swab32s(&b->mbo_uid_h); __swab32s(&b->mbo_gid_h); - BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_5) == 0); + __swab32s(&b->mbo_projid); + BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_6) == 0); + BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_7) == 0); + BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_8) == 0); + BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_9) == 0); + BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_10) == 0); } void lustre_swab_mdt_ioepoch(struct mdt_ioepoch *b) diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index 09aef9a..b4774d6 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -1228,9 +1228,13 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct obdo, o_data_version)); LASSERTF((int)sizeof(((struct obdo *)0)->o_data_version) == 8, "found %lld\n", (long long)(int)sizeof(((struct obdo *)0)->o_data_version)); - LASSERTF((int)offsetof(struct obdo, o_padding_4) == 184, "found %lld\n", + LASSERTF((int)offsetof(struct obdo, o_projid) == 184, "found %lld\n", + (long long)(int)offsetof(struct obdo, o_projid)); + LASSERTF((int)sizeof(((struct obdo *)0)->o_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct obdo *)0)->o_projid)); + LASSERTF((int)offsetof(struct obdo, o_padding_4) == 188, "found %lld\n", (long long)(int)offsetof(struct obdo, o_padding_4)); - LASSERTF((int)sizeof(((struct obdo *)0)->o_padding_4) == 8, "found %lld\n", + LASSERTF((int)sizeof(((struct obdo *)0)->o_padding_4) == 4, "found %lld\n", (long long)(int)sizeof(((struct obdo *)0)->o_padding_4)); LASSERTF((int)offsetof(struct obdo, o_padding_5) == 192, "found %lld\n", (long long)(int)offsetof(struct obdo, o_padding_5)); @@ -1324,6 +1328,9 @@ void lustre_assert_wire_constants(void) OBD_MD_FLGETATTRLOCK); LASSERTF(OBD_MD_FLDATAVERSION == (0x0010000000000000ULL), "found 0x%.16llxULL\n", OBD_MD_FLDATAVERSION); + LASSERTF(OBD_MD_FLPROJID == (0x0100000000000000ULL), "found 0x%.16llxULL\n", + OBD_MD_FLPROJID); + BUILD_BUG_ON(OBD_FL_INLINEDATA != 0x00000001); BUILD_BUG_ON(OBD_FL_OBDMDEXISTS != 0x00000002); BUILD_BUG_ON(OBD_FL_DELORPHAN != 0x00000004); @@ -1869,10 +1876,10 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct mdt_body, mbo_gid_h)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_gid_h) == 4, "found %lld\n", (long long)(int)sizeof(((struct mdt_body *)0)->mbo_gid_h)); - LASSERTF((int)offsetof(struct mdt_body, mbo_padding_5) == 172, "found %lld\n", - (long long)(int)offsetof(struct mdt_body, mbo_padding_5)); - LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_5) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_body *)0)->mbo_padding_5)); + LASSERTF((int)offsetof(struct mdt_body, mbo_projid) == 172, "found %lld\n", + (long long)(int)offsetof(struct mdt_body, mbo_projid)); + LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct mdt_body *)0)->mbo_projid)); LASSERTF((int)offsetof(struct mdt_body, mbo_padding_6) == 176, "found %lld\n", (long long)(int)offsetof(struct mdt_body, mbo_padding_6)); LASSERTF((int)sizeof(((struct mdt_body *)0)->mbo_padding_6) == 8, "found %lld\n", -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:39 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:39 -0400 Subject: [lustre-devel] [PATCH 0/7] lustre: project quota support and BLKSZGET Message-ID: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Add support for BLKSZGET and project quota support that landed to lustre 2.10. This patch set depends on the earlier patch set sent and are not order independent. Emoly Liu (1): lustre: ioctl: Add BLKSSZGET ioctl support Li Xi (1): lustre: quota: add project quota support for Lustre Oleg Drokin (2): lustre: quota: cleanup codes of quota for new type lustre: quota: add project id support Wang Shilong (3): lustre: quota: add setting/getting project id function lustre: quota: add project inherit attributes lustre: llite: extend inode flags into GET/SETXATTR ioctl .../lustre/include/uapi/linux/lustre/lustre_idl.h | 40 ++++++++-- .../lustre/include/uapi/linux/lustre/lustre_user.h | 15 +++- drivers/staging/lustre/lustre/include/cl_object.h | 6 +- drivers/staging/lustre/lustre/include/obd.h | 4 + drivers/staging/lustre/lustre/llite/dir.c | 28 +++++-- drivers/staging/lustre/lustre/llite/file.c | 88 ++++++++++++++++++++++ .../staging/lustre/lustre/llite/llite_internal.h | 10 ++- drivers/staging/lustre/lustre/llite/llite_lib.c | 17 ++++- drivers/staging/lustre/lustre/llite/vvp_object.c | 9 ++- drivers/staging/lustre/lustre/mdc/mdc_lib.c | 3 + drivers/staging/lustre/lustre/obdclass/obdo.c | 7 ++ drivers/staging/lustre/lustre/osc/osc_cache.c | 1 + drivers/staging/lustre/lustre/osc/osc_quota.c | 46 +++++++---- drivers/staging/lustre/lustre/osc/osc_request.c | 13 ++-- .../staging/lustre/lustre/ptlrpc/pack_generic.c | 8 +- drivers/staging/lustre/lustre/ptlrpc/wiretest.c | 30 +++++--- 16 files changed, 275 insertions(+), 50 deletions(-) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:45 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:45 -0400 Subject: [lustre-devel] [PATCH 6/7] lustre: llite: extend inode flags into GET/SETXATTR ioctl In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-7-git-send-email-jsimmons@infradead.org> From: Wang Shilong This is very useful for projet quota tools to save RPC call to change project inherit attribute together with project ID. Signed-off-by: Wang Shilong WC-bug-id: https://jira.whamcloud.com/browse/LU-10030 Reviewed-on: https://review.whamcloud.com/30072 WC-bug-id: https://jira.whamcloud.com/browse/LU-11165 Reviewed-on: https://review.whamcloud.com/32860 Reviewed-by: Yingjin Qian Reviewed-by: Andreas Dilger Reviewed-by: John L. Hammond Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/file.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 72101bd..f69eefc 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -2178,6 +2178,8 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, struct ptlrpc_request *req = NULL; struct md_op_data *op_data; struct fsxattr fsxattr; + struct cl_object *obj; + struct iattr *attr; int rc = 0; int flags; @@ -2206,8 +2208,23 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req); ptlrpc_req_finished(req); + if (rc) + goto out_fsxattr; + ll_update_inode_flags(inode, op_data->op_attr_flags); + obj = ll_i2info(inode)->lli_clob; + if (!obj) + goto out_fsxattr; + + attr = kzalloc(sizeof(*attr), GFP_KERNEL); + if (!attr) { + rc = -ENOMEM; + goto out_fsxattr; + } + rc = cl_setattr_ost(obj, attr, OP_XVALID_FLAGS, + fsxattr.fsx_xflags); + kfree(attr); out_fsxattr: ll_finish_md_op_data(op_data); return rc; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:41 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:41 -0400 Subject: [lustre-devel] [PATCH 2/7] lustre: quota: add project quota support for Lustre In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-3-git-send-email-jsimmons@infradead.org> From: Li Xi This patch adds necessary support of project quota, so that OSTs can be mounted successfully. Signed-off-by: Li Xi Signed-off-by: Wang Shilong WC-bug-id: https://jira.whamcloud.com/browse/LU-4017 Reviewed-on: https://review.whamcloud.com/23947 Reviewed-by: Niu Yawei Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h | 9 +++++++-- drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h | 2 ++ drivers/staging/lustre/lustre/llite/dir.c | 4 +++- drivers/staging/lustre/lustre/osc/osc_quota.c | 4 ++++ 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index 9430f11..1220acd 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -913,6 +913,9 @@ enum obdo_flags { OBD_FL_IDONLY = 0x00000010, /* set in o_flags only adjust obj id*/ OBD_FL_RECREATE_OBJS = 0x00000020, /* recreate missing obj */ OBD_FL_DEBUG_CHECK = 0x00000040, /* echo client/server debug check */ + OBD_FL_NO_PRJQUOTA = 0x00000080, /* the object's project is over + * quota + */ OBD_FL_NO_USRQUOTA = 0x00000100, /* the object's owner is over quota */ OBD_FL_NO_GRPQUOTA = 0x00000200, /* the object's group is over quota */ OBD_FL_CREATE_CROW = 0x00000400, /* object should be create on write */ @@ -1086,7 +1089,7 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) #define OBD_MD_FLHANDLE (0x00080000ULL) /* file/lock handle */ #define OBD_MD_FLCKSUM (0x00100000ULL) /* bulk data checksum */ #define OBD_MD_FLQOS (0x00200000ULL) /* quality of service stats */ -/*#define OBD_MD_FLOSCOPQ (0x00400000ULL) osc opaque data, never used */ +#define OBD_MD_FLPRJQUOTA (0x00400000ULL) /* over quota flags sent from ost */ /* OBD_MD_FLCOOKIE (0x00800000ULL) obsolete in 2.8 */ #define OBD_MD_FLGROUP (0x01000000ULL) /* group */ #define OBD_MD_FLFID (0x02000000ULL) /* ->ost write inline fid */ @@ -1131,7 +1134,9 @@ static inline __u32 lov_mds_md_size(__u16 stripes, __u32 lmm_magic) #define OBD_MD_DEFAULT_MEA (0x0040000000000000ULL) /* default MEA */ -#define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA) +#define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \ + OBD_MD_FLGRPQUOTA | \ + OBD_MD_FLPRJQUOTA) #define OBD_MD_FLGETATTR (OBD_MD_FLID | OBD_MD_FLATIME | OBD_MD_FLMTIME | \ OBD_MD_FLCTIME | OBD_MD_FLSIZE | OBD_MD_FLBLKSZ | \ diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h index b1961df..9d553ce6 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h @@ -576,6 +576,8 @@ static inline char *qtype_name(int qtype) return "usr"; case GRPQUOTA: return "grp"; + case PRJQUOTA: + return "prj"; } return "unknown"; } diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 7047938..9fa0e2e 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -902,7 +902,7 @@ static int copy_and_ioctl(int cmd, struct obd_export *exp, return rc; } -static inline int check_owner(int type, int id) +static int check_owner(int type, int id) { switch (type) { case USRQUOTA: @@ -913,6 +913,8 @@ static inline int check_owner(int type, int id) if (!in_egroup_p(make_kgid(&init_user_ns, id))) return -EPERM; break; + case PRJQUOTA: + break; } return 0; } diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c index 13ef482..555f1be 100644 --- a/drivers/staging/lustre/lustre/osc/osc_quota.c +++ b/drivers/staging/lustre/lustre/osc/osc_quota.c @@ -85,6 +85,8 @@ static inline u32 md_quota_flag(int qtype) return OBD_MD_FLUSRQUOTA; case GRPQUOTA: return OBD_MD_FLGRPQUOTA; + case PRJQUOTA: + return OBD_MD_FLPRJQUOTA; default: return 0; } @@ -97,6 +99,8 @@ static inline u32 fl_quota_flag(int qtype) return OBD_FL_NO_USRQUOTA; case GRPQUOTA: return OBD_FL_NO_GRPQUOTA; + case PRJQUOTA: + return OBD_FL_NO_PRJQUOTA; default: return 0; } -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:43 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:43 -0400 Subject: [lustre-devel] [PATCH 4/7] lustre: quota: add setting/getting project id function In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-5-git-send-email-jsimmons@infradead.org> From: Wang Shilong Extend Attr RPC to support project ID attribute, new ioctl is introduced to get/set project id, it is kept same ioctl number as VFS, you could use: lsattr -p chattr -p Signed-off-by: Wang Shilong WC-bug-id: https://jira.whamcloud.com/browse/LU-4017 Reviewed-on: https://review.whamcloud.com/26202 Reviewed-on: https://review.whamcloud.com/26577 Reviewed-by: Niu Yawei Reviewed-by: Li Xi Reviewed-by: Oleg Drokin Tested-by: Oleg Drokin Signed-off-by: James Simmons --- .../lustre/include/uapi/linux/lustre/lustre_idl.h | 5 +- drivers/staging/lustre/lustre/include/cl_object.h | 6 ++- drivers/staging/lustre/lustre/include/obd.h | 3 ++ drivers/staging/lustre/lustre/llite/dir.c | 5 +- drivers/staging/lustre/lustre/llite/file.c | 57 ++++++++++++++++++++++ .../staging/lustre/lustre/llite/llite_internal.h | 5 +- drivers/staging/lustre/lustre/llite/vvp_object.c | 5 +- drivers/staging/lustre/lustre/mdc/mdc_lib.c | 3 ++ drivers/staging/lustre/lustre/osc/osc_cache.c | 1 + drivers/staging/lustre/lustre/osc/osc_request.c | 11 +++-- drivers/staging/lustre/lustre/ptlrpc/wiretest.c | 11 +++-- 11 files changed, 97 insertions(+), 15 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index a8ffde2..a7b3168 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1562,7 +1562,7 @@ struct mdt_rec_setattr { __u32 sa_attr_flags; __u32 sa_mode; __u32 sa_bias; /* some operation flags */ - __u32 sa_padding_3; + __u32 sa_projid; __u32 sa_padding_4; __u32 sa_padding_5; }; @@ -1590,7 +1590,8 @@ struct mdt_rec_setattr { #define MDS_ATTR_FROM_OPEN 0x4000ULL /* = 16384, called from open path, * ie O_TRUNC */ -#define MDS_ATTR_BLOCKS 0x8000ULL /* = 32768 */ +#define MDS_ATTR_BLOCKS 0x8000ULL /* = 32768 */ +#define MDS_ATTR_PROJID 0x10000ULL /* = 65536 */ #define MDS_FMODE_CLOSED 00000000 #define MDS_FMODE_EXEC 00000004 diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 9ff1ca5..a1e07f8 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -165,6 +165,9 @@ struct cl_attr { /* nlink of the directory */ __u64 cat_nlink; + + /* Project identifier for quota purpose. */ + u32 cat_projid; }; /** @@ -178,7 +181,8 @@ enum cl_attr_valid { CAT_CTIME = 1 << 5, CAT_BLOCKS = 1 << 6, CAT_UID = 1 << 7, - CAT_GID = 1 << 8 + CAT_GID = BIT(8), + CAT_PROJID = BIT(9), }; /** diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index 81b4750..d6a968c 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -670,6 +670,7 @@ enum op_xvalid { OP_XVALID_BLOCKS = BIT(1), /* 0x0002 */ OP_XVALID_OWNEROVERRIDE = BIT(2), /* 0x0004 */ OP_XVALID_FLAGS = BIT(3), /* 0x0008 */ + OP_XVALID_PROJID = BIT(4), /* 0x0010 */ }; struct lu_context; @@ -770,6 +771,8 @@ struct md_op_data { /* default stripe offset */ __u32 op_default_stripe_offset; + + u32 op_projid; }; struct md_callback { diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 9fa0e2e..f1c1c9c 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1667,7 +1667,10 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return rc; } - + case FS_IOC_FSGETXATTR: + return ll_ioctl_fsgetxattr(inode, cmd, arg); + case FS_IOC_FSSETXATTR: + return ll_ioctl_fssetxattr(inode, cmd, arg); default: return obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL, (void __user *)arg); diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 5df2b87..30a731f 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -2148,6 +2148,59 @@ static int ll_ladvise(struct inode *inode, struct file *file, __u64 flags, return rc; } +int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + struct fsxattr fsxattr; + + if (copy_from_user(&fsxattr, + (const struct fsxattr __user *)arg, + sizeof(fsxattr))) + return -EFAULT; + + fsxattr.fsx_projid = ll_i2info(inode)->lli_projid; + if (copy_to_user((struct fsxattr __user *)arg, + &fsxattr, sizeof(fsxattr))) + return -EFAULT; + + return 0; +} + +int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, + unsigned long arg) +{ + struct ptlrpc_request *req = NULL; + struct md_op_data *op_data; + struct fsxattr fsxattr; + int rc = 0; + + /* only root could change project ID */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + return PTR_ERR(op_data); + + if (copy_from_user(&fsxattr, + (const struct fsxattr __user *)arg, + sizeof(fsxattr))) { + rc = -EFAULT; + goto out_fsxattr; + } + + op_data->op_projid = fsxattr.fsx_projid; + op_data->op_xvalid |= OP_XVALID_PROJID; + rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, + 0, &req); + ptlrpc_req_finished(req); + +out_fsxattr: + ll_finish_md_op_data(op_data); + return rc; +} + static long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2532,6 +2585,10 @@ static int ll_ladvise(struct inode *inode, struct file *file, __u64 flags, kfree(ladvise_hdr); return rc; } + case FS_IOC_FSGETXATTR: + return ll_ioctl_fsgetxattr(inode, cmd, arg); + case FS_IOC_FSSETXATTR: + return ll_ioctl_fssetxattr(inode, cmd, arg); default: { int err; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index ba9ba49..34bcb4b 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -808,7 +808,10 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx, int ll_get_fid_by_name(struct inode *parent, const char *name, int namelen, struct lu_fid *fid, struct inode **inode); int ll_inode_permission(struct inode *inode, int mask); - +int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, + unsigned long arg); +int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, + unsigned long arg); int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry, __u64 flags, struct lov_user_md *lum, int lum_size); diff --git a/drivers/staging/lustre/lustre/llite/vvp_object.c b/drivers/staging/lustre/lustre/llite/vvp_object.c index c1f8b50..e1000f6 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_object.c +++ b/drivers/staging/lustre/lustre/llite/vvp_object.c @@ -95,6 +95,7 @@ static int vvp_attr_get(const struct lu_env *env, struct cl_object *obj, attr->cat_blocks = inode->i_blocks; attr->cat_uid = from_kuid(&init_user_ns, inode->i_uid); attr->cat_gid = from_kgid(&init_user_ns, inode->i_gid); + attr->cat_projid = ll_i2info(inode)->lli_projid; /* KMS is not known by this layer */ return 0; /* layers below have to fill in the rest */ } @@ -116,8 +117,10 @@ static int vvp_attr_update(const struct lu_env *env, struct cl_object *obj, inode->i_ctime.tv_sec = attr->cat_ctime; if (0 && valid & CAT_SIZE) i_size_write(inode, attr->cat_size); + if (valid & CAT_PROJID) + ll_i2info(inode)->lli_projid = attr->cat_projid; /* not currently necessary */ - if (0 && valid & (CAT_UID | CAT_GID | CAT_SIZE)) + if (0 && valid & (CAT_UID | CAT_GID | CAT_SIZE | CAT_PROJID)) mark_inode_dirty(inode); return 0; } diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c index 1ab1ad2..415127f 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c @@ -305,6 +305,8 @@ static inline u64 attr_pack(unsigned int ia_valid, enum op_xvalid ia_xvalid) if (ia_xvalid & OP_XVALID_OWNEROVERRIDE) /* NFSD hack (see bug 5781) */ sa_valid |= MDS_OPEN_OWNEROVERRIDE; + if (ia_xvalid & OP_XVALID_PROJID) + sa_valid |= MDS_ATTR_PROJID; return sa_valid; } @@ -323,6 +325,7 @@ static void mdc_setattr_pack_rec(struct mdt_rec_setattr *rec, rec->sa_mode = op_data->op_attr.ia_mode; rec->sa_uid = from_kuid(&init_user_ns, op_data->op_attr.ia_uid); rec->sa_gid = from_kgid(&init_user_ns, op_data->op_attr.ia_gid); + rec->sa_projid = op_data->op_projid; rec->sa_size = op_data->op_attr.ia_size; rec->sa_blocks = op_data->op_attr_blocks; rec->sa_atime = op_data->op_attr.ia_atime.tv_sec; diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index 5d09a4f..93330cb 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -2467,6 +2467,7 @@ int osc_queue_async_io(const struct lu_env *env, struct cl_io *io, qid[USRQUOTA] = attr->cat_uid; qid[GRPQUOTA] = attr->cat_gid; + qid[PRJQUOTA] = attr->cat_projid; if (rc == 0) rc = osc_quota_chkdq(cli, qid); if (rc) diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c index 1d21159..b28fbac 100644 --- a/drivers/staging/lustre/lustre/osc/osc_request.c +++ b/drivers/staging/lustre/lustre/osc/osc_request.c @@ -1474,14 +1474,15 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, int rc) return -EPROTO; } - /* set/clear over quota flag for a uid/gid */ + /* set/clear over quota flag for a uid/gid/projid */ if (lustre_msg_get_opc(req->rq_reqmsg) == OST_WRITE && body->oa.o_valid & OBD_MD_FLALLQUOTA) { - unsigned int qid[MAXQUOTAS] = { body->oa.o_uid, body->oa.o_gid }; + unsigned int qid[MAXQUOTAS] = { body->oa.o_uid, body->oa.o_gid, + body->oa.o_projid }; - CDEBUG(D_QUOTA, "setdq for [%u %u] with valid %#llx, flags %x\n", - body->oa.o_uid, body->oa.o_gid, body->oa.o_valid, - body->oa.o_flags); + CDEBUG(D_QUOTA, "setdq for [%u %u %u] with valid %#llx, flags %x\n", + body->oa.o_uid, body->oa.o_gid, body->oa.o_projid, + body->oa.o_valid, body->oa.o_flags); osc_quota_setdq(cli, qid, body->oa.o_valid, body->oa.o_flags); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c index b4774d6..3aaaebb 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/wiretest.c +++ b/drivers/staging/lustre/lustre/ptlrpc/wiretest.c @@ -253,6 +253,9 @@ void lustre_assert_wire_constants(void) (long long)MDS_ATTR_FROM_OPEN); LASSERTF(MDS_ATTR_BLOCKS == 0x0000000000008000ULL, "found 0x%.16llxULL\n", (long long)MDS_ATTR_BLOCKS); + LASSERTF(MDS_ATTR_PROJID == 0x0000000000010000ULL, "found 0x%.16llxULL\n", + (long long)MDS_ATTR_PROJID); + LASSERTF(FLD_QUERY == 900, "found %lld\n", (long long)FLD_QUERY); LASSERTF(FLD_FIRST_OPC == 900, "found %lld\n", @@ -2080,10 +2083,10 @@ void lustre_assert_wire_constants(void) (long long)(int)offsetof(struct mdt_rec_setattr, sa_bias)); LASSERTF((int)sizeof(((struct mdt_rec_setattr *)0)->sa_bias) == 4, "found %lld\n", (long long)(int)sizeof(((struct mdt_rec_setattr *)0)->sa_bias)); - LASSERTF((int)offsetof(struct mdt_rec_setattr, sa_padding_3) == 124, "found %lld\n", - (long long)(int)offsetof(struct mdt_rec_setattr, sa_padding_3)); - LASSERTF((int)sizeof(((struct mdt_rec_setattr *)0)->sa_padding_3) == 4, "found %lld\n", - (long long)(int)sizeof(((struct mdt_rec_setattr *)0)->sa_padding_3)); + LASSERTF((int)offsetof(struct mdt_rec_setattr, sa_projid) == 124, "found %lld\n", + (long long)(int)offsetof(struct mdt_rec_setattr, sa_projid)); + LASSERTF((int)sizeof(((struct mdt_rec_setattr *)0)->sa_projid) == 4, "found %lld\n", + (long long)(int)sizeof(((struct mdt_rec_setattr *)0)->sa_projid)); LASSERTF((int)offsetof(struct mdt_rec_setattr, sa_padding_4) == 128, "found %lld\n", (long long)(int)offsetof(struct mdt_rec_setattr, sa_padding_4)); LASSERTF((int)sizeof(((struct mdt_rec_setattr *)0)->sa_padding_4) == 4, "found %lld\n", -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:46 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:46 -0400 Subject: [lustre-devel] [PATCH 7/7] lustre: ioctl: Add BLKSSZGET ioctl support In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-8-git-send-email-jsimmons@infradead.org> From: Emoly Liu Add BLKSSZGET ioctl and return PAGE_SIZE for the minimun alignment from ll_file_ioctl() for this call. Signed-off-by: Emoly Liu WC-bug-id: https://jira.whamcloud.com/browse/LU-9347 Reviewed-on: https://review.whamcloud.com/28578 Reviewed-by: Andreas Dilger Reviewed-by: Bobi Jam Signed-off-by: James Simmons --- drivers/staging/lustre/lustre/llite/file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index f69eefc..d3ddfd2 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -2618,6 +2618,8 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, return ll_ioctl_fsgetxattr(inode, cmd, arg); case FS_IOC_FSSETXATTR: return ll_ioctl_fssetxattr(inode, cmd, arg); + case BLKSSZGET: + return put_user(PAGE_SIZE, (int __user *)arg); default: { int err; -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:00:44 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 15:00:44 -0400 Subject: [lustre-devel] [PATCH 5/7] lustre: quota: add project inherit attributes In-Reply-To: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> References: <1539543646-29717-1-git-send-email-jsimmons@infradead.org> Message-ID: <1539543646-29717-6-git-send-email-jsimmons@infradead.org> From: Wang Shilong Add @LUSTRE_PROJINHERIT_FL inode flag which means creating new objects parents projid, it is disabled in default, unless setting explicitly. It is kept same interface as Ext4/XFS, you could use following ioctl directly: chattr +P Signed-off-by: Wang Shilong WC-bug-id: https://jira.whamcloud.com/browse/LU-4017 Reviewed-on: https://review.whamcloud.com/26463 WC-bug-id: https://jira.whamcloud.com/browse/LU-11154 Reviewed-on: https://review.whamcloud.com/32828 Reviewed-by: Andreas Dilger Reviewed-by: Niu Yawei Reviewed-by: Olaf Weber Reviewed-by: Li Xi Reviewed-by: Oleg Drokin Signed-off-by: James Simmons --- .../lustre/include/uapi/linux/lustre/lustre_idl.h | 17 +++++++++++++++++ drivers/staging/lustre/lustre/llite/file.c | 12 ++++++++++++ drivers/staging/lustre/lustre/llite/llite_internal.h | 3 +++ drivers/staging/lustre/lustre/llite/llite_lib.c | 15 +++++++++++++-- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h index a7b3168..26646f9 100644 --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1454,6 +1454,7 @@ enum { #define LUSTRE_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define LUSTRE_DIRECTIO_FL 0x00100000 /* Use direct i/o */ #define LUSTRE_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */ +#define LUSTRE_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ /* Convert wire LUSTRE_*_FL to corresponding client local VFS S_* values * for the client inode i_flags. The LUSTRE_*_FL are the Lustre wire @@ -1480,6 +1481,22 @@ static inline int ll_inode_to_ext_flags(int iflags) ((iflags & S_IMMUTABLE) ? LUSTRE_IMMUTABLE_FL : 0)); } +static inline int ll_xflags_to_inode_flags(int xflags) +{ + return ((xflags & FS_XFLAG_SYNC) ? S_SYNC : 0) | + ((xflags & FS_XFLAG_NOATIME) ? S_NOATIME : 0) | + ((xflags & FS_XFLAG_APPEND) ? S_APPEND : 0) | + ((xflags & FS_XFLAG_IMMUTABLE) ? S_IMMUTABLE : 0); +} + +static inline int ll_inode_flags_to_xflags(int flags) +{ + return ((flags & S_SYNC) ? FS_XFLAG_SYNC : 0) | + ((flags & S_NOATIME) ? FS_XFLAG_NOATIME : 0) | + ((flags & S_APPEND) ? FS_XFLAG_APPEND : 0) | + ((flags & S_IMMUTABLE) ? FS_XFLAG_IMMUTABLE : 0); +} + /* 64 possible states */ enum md_transient_state { MS_RESTORE = (1 << 0), /* restore is running */ diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 30a731f..72101bd 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -99,6 +99,8 @@ static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data, op_data->op_xvalid |= OP_XVALID_CTIME_SET; op_data->op_attr_blocks = inode->i_blocks; op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags); + if (test_bit(LLIF_PROJECT_INHERIT, &lli->lli_flags)) + op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL; op_data->op_handle = och->och_fh; /* @@ -2151,6 +2153,7 @@ static int ll_ladvise(struct inode *inode, struct file *file, __u64 flags, int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, unsigned long arg) { + struct ll_inode_info *lli = ll_i2info(inode); struct fsxattr fsxattr; if (copy_from_user(&fsxattr, @@ -2158,6 +2161,9 @@ int ll_ioctl_fsgetxattr(struct inode *inode, unsigned int cmd, sizeof(fsxattr))) return -EFAULT; + fsxattr.fsx_xflags = ll_inode_flags_to_xflags(inode->i_flags); + if (test_bit(LLIF_PROJECT_INHERIT, &lli->lli_flags)) + fsxattr.fsx_xflags |= FS_XFLAG_PROJINHERIT; fsxattr.fsx_projid = ll_i2info(inode)->lli_projid; if (copy_to_user((struct fsxattr __user *)arg, &fsxattr, sizeof(fsxattr))) @@ -2173,6 +2179,7 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, struct md_op_data *op_data; struct fsxattr fsxattr; int rc = 0; + int flags; /* only root could change project ID */ if (!capable(CAP_SYS_ADMIN)) @@ -2190,11 +2197,16 @@ int ll_ioctl_fssetxattr(struct inode *inode, unsigned int cmd, goto out_fsxattr; } + flags = ll_xflags_to_inode_flags(fsxattr.fsx_xflags); + op_data->op_attr_flags = ll_inode_to_ext_flags(flags); + if (fsxattr.fsx_xflags & FS_XFLAG_PROJINHERIT) + op_data->op_attr_flags |= LUSTRE_PROJINHERIT_FL; op_data->op_projid = fsxattr.fsx_projid; op_data->op_xvalid |= OP_XVALID_PROJID; rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req); ptlrpc_req_finished(req); + ll_update_inode_flags(inode, op_data->op_attr_flags); out_fsxattr: ll_finish_md_op_data(op_data); diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 34bcb4b..aaddebf 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -108,6 +108,8 @@ enum ll_file_flags { * local inode atime. */ LLIF_UPDATE_ATIME, + /* Project inherit */ + LLIF_PROJECT_INHERIT = 3, }; struct ll_inode_info { @@ -857,6 +859,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, int ll_statfs_internal(struct ll_sb_info *sbi, struct obd_statfs *osfs, u64 max_age, u32 flags); int ll_update_inode(struct inode *inode, struct lustre_md *md); +void ll_update_inode_flags(struct inode *inode, int ext_flags); int ll_read_inode2(struct inode *inode, void *opaque); void ll_delete_inode(struct inode *inode); int ll_iocontrol(struct inode *inode, struct file *file, diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 7320dc8..fac6584 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -1791,6 +1791,17 @@ void ll_inode_size_unlock(struct inode *inode) mutex_unlock(&lli->lli_size_mutex); } +void ll_update_inode_flags(struct inode *inode, int ext_flags) +{ + struct ll_inode_info *lli = ll_i2info(inode); + + inode->i_flags = ll_ext_to_inode_flags(ext_flags); + if (ext_flags & LUSTRE_PROJINHERIT_FL) + set_bit(LLIF_PROJECT_INHERIT, &lli->lli_flags); + else + clear_bit(LLIF_PROJECT_INHERIT, &lli->lli_flags); +} + int ll_update_inode(struct inode *inode, struct lustre_md *md) { struct ll_inode_info *lli = ll_i2info(inode); @@ -1862,7 +1873,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) if (body->mbo_valid & OBD_MD_FLPROJID) lli->lli_projid = body->mbo_projid; if (body->mbo_valid & OBD_MD_FLFLAGS) - inode->i_flags = ll_ext_to_inode_flags(body->mbo_flags); + ll_update_inode_flags(inode, body->mbo_flags); if (body->mbo_valid & OBD_MD_FLNLINK) set_nlink(inode, body->mbo_nlink); if (body->mbo_valid & OBD_MD_FLRDEV) @@ -2024,7 +2035,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, if (rc) return rc; - inode->i_flags = ll_ext_to_inode_flags(flags); + ll_update_inode_flags(inode, flags); obj = ll_i2info(inode)->lli_clob; if (!obj) -- 1.8.3.1 From jsimmons at infradead.org Sun Oct 14 19:08:15 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:08:15 +0100 (BST) Subject: [lustre-devel] [PATCH 01/24] lustre: lnet: add lnet_interfaces_max tunable In-Reply-To: <153895437756.16383.14536895691182127915.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437756.16383.14536895691182127915.stgit@noble> Message-ID: > From: Olaf Weber > > Add an lnet_interfaces_max tunable value, that describes the maximum > number of interfaces per node. This tunable is primarily useful for > sanity checks prior to allocating memory. > > Allow lnet_interfaces_max to be set and get from the sysfs interface. > > Add LNET_INTERFACES_MIN, value 16, as the minimum value. > > Add LNET_INTERFACES_MAX_DEFAULT, value 200, as the default value. This > value was chosen to ensure that the size of an LNet ping message with > any associated LND overhead would fit in 4096 bytes. > > (The LNET_INTERFACES_MAX name was not reused to allow for the early > detection of issues when merging code that uses it.) > > Rename LNET_NUM_INTERFACES to LNET_INTERFACES_NUM Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Signed-off-by: Amir Shehata > Reviewed-on: https://review.whamcloud.com/25770 > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-types.h | 2 + > .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 4 +-- > .../lustre/include/uapi/linux/lnet/lnet-types.h | 7 ++++ > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 + > .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 22 +++++++------- > .../staging/lustre/lnet/klnds/socklnd/socklnd.h | 4 +-- > .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 2 + > .../lustre/lnet/klnds/socklnd/socklnd_proto.c | 4 +-- > drivers/staging/lustre/lnet/lnet/api-ni.c | 32 +++++++++++++++++++- > drivers/staging/lustre/lnet/lnet/config.c | 10 +++--- > 10 files changed, 62 insertions(+), 27 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 7219a7bacf6e..7b11c31f0029 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -371,7 +371,7 @@ struct lnet_ni { > * equivalent interfaces to use > * This is an array because socklnd bonding can still be configured > */ > - char *ni_interfaces[LNET_NUM_INTERFACES]; > + char *ni_interfaces[LNET_INTERFACES_NUM]; > /* original net namespace */ > struct net *ni_net_ns; > }; > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > index 8f03aa3c5676..d88b30d2e76c 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > @@ -81,7 +81,7 @@ struct lnet_ioctl_config_lnd_tunables { > }; > > struct lnet_ioctl_net_config { > - char ni_interfaces[LNET_NUM_INTERFACES][LNET_MAX_STR_LEN]; > + char ni_interfaces[LNET_INTERFACES_NUM][LNET_MAX_STR_LEN]; > __u32 ni_status; > __u32 ni_cpts[LNET_MAX_SHOW_NUM_CPT]; > char cfg_bulk[0]; > @@ -184,7 +184,7 @@ struct lnet_ioctl_element_msg_stats { > struct lnet_ioctl_config_ni { > struct libcfs_ioctl_hdr lic_cfg_hdr; > lnet_nid_t lic_nid; > - char lic_ni_intf[LNET_NUM_INTERFACES][LNET_MAX_STR_LEN]; > + char lic_ni_intf[LNET_INTERFACES_NUM][LNET_MAX_STR_LEN]; > char lic_legacy_ip2nets[LNET_MAX_STR_LEN]; > __u32 lic_cpts[LNET_MAX_SHOW_NUM_CPT]; > __u32 lic_ncpts; > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > index f8a873bab135..6ee60d07ff84 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > @@ -264,7 +264,12 @@ struct lnet_counters { > #define LNET_NI_STATUS_DOWN 0xdeadface > #define LNET_NI_STATUS_INVALID 0x00000000 > > -#define LNET_NUM_INTERFACES 16 > +#define LNET_INTERFACES_NUM 16 > + > +/* The minimum number of interfaces per node supported by LNet. */ > +#define LNET_INTERFACES_MIN 16 > +/* The default - arbitrary - value of the lnet_max_interfaces tunable. */ > +#define LNET_INTERFACES_MAX_DEFAULT 200 > > /** > * Objects maintained by the LNet are accessed through handles. Handle types > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > index c20766379323..bf969b3891a9 100644 > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > @@ -2915,7 +2915,7 @@ static int kiblnd_startup(struct lnet_ni *ni) > if (ni->ni_interfaces[0]) { > /* Use the IPoIB interface specified in 'networks=' */ > > - BUILD_BUG_ON(LNET_NUM_INTERFACES <= 1); > + BUILD_BUG_ON(LNET_INTERFACES_NUM <= 1); > if (ni->ni_interfaces[1]) { > CERROR("Multiple interfaces not supported\n"); > goto failed; > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c > index b2f0148d0087..ff8d73295fff 100644 > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c > @@ -53,7 +53,7 @@ ksocknal_ip2iface(struct lnet_ni *ni, __u32 ip) > struct ksock_interface *iface; > > for (i = 0; i < net->ksnn_ninterfaces; i++) { > - LASSERT(i < LNET_NUM_INTERFACES); > + LASSERT(i < LNET_INTERFACES_NUM); > iface = &net->ksnn_interfaces[i]; > > if (iface->ksni_ipaddr == ip) > @@ -221,7 +221,7 @@ ksocknal_unlink_peer_locked(struct ksock_peer *peer_ni) > struct ksock_interface *iface; > > for (i = 0; i < peer_ni->ksnp_n_passive_ips; i++) { > - LASSERT(i < LNET_NUM_INTERFACES); > + LASSERT(i < LNET_INTERFACES_NUM); > ip = peer_ni->ksnp_passive_ips[i]; > > iface = ksocknal_ip2iface(peer_ni->ksnp_ni, ip); > @@ -689,7 +689,7 @@ ksocknal_local_ipvec(struct lnet_ni *ni, __u32 *ipaddrs) > read_lock(&ksocknal_data.ksnd_global_lock); > > nip = net->ksnn_ninterfaces; > - LASSERT(nip <= LNET_NUM_INTERFACES); > + LASSERT(nip <= LNET_INTERFACES_NUM); > > /* > * Only offer interfaces for additional connections if I have > @@ -770,8 +770,8 @@ ksocknal_select_ips(struct ksock_peer *peer_ni, __u32 *peerips, int n_peerips) > */ > write_lock_bh(global_lock); > > - LASSERT(n_peerips <= LNET_NUM_INTERFACES); > - LASSERT(net->ksnn_ninterfaces <= LNET_NUM_INTERFACES); > + LASSERT(n_peerips <= LNET_INTERFACES_NUM); > + LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM); > > /* > * Only match interfaces for additional connections > @@ -890,7 +890,7 @@ ksocknal_create_routes(struct ksock_peer *peer_ni, int port, > return; > } > > - LASSERT(npeer_ipaddrs <= LNET_NUM_INTERFACES); > + LASSERT(npeer_ipaddrs <= LNET_INTERFACES_NUM); > > for (i = 0; i < npeer_ipaddrs; i++) { > if (newroute) { > @@ -919,7 +919,7 @@ ksocknal_create_routes(struct ksock_peer *peer_ni, int port, > best_nroutes = 0; > best_netmatch = 0; > > - LASSERT(net->ksnn_ninterfaces <= LNET_NUM_INTERFACES); > + LASSERT(net->ksnn_ninterfaces <= LNET_INTERFACES_NUM); > > /* Select interface to connect from */ > for (j = 0; j < net->ksnn_ninterfaces; j++) { > @@ -1060,7 +1060,7 @@ ksocknal_create_conn(struct lnet_ni *ni, struct ksock_route *route, > atomic_set(&conn->ksnc_tx_nob, 0); > > hello = kvzalloc(offsetof(struct ksock_hello_msg, > - kshm_ips[LNET_NUM_INTERFACES]), > + kshm_ips[LNET_INTERFACES_NUM]), > GFP_KERNEL); > if (!hello) { > rc = -ENOMEM; > @@ -1983,7 +1983,7 @@ ksocknal_add_interface(struct lnet_ni *ni, __u32 ipaddress, __u32 netmask) > if (iface) { > /* silently ignore dups */ > rc = 0; > - } else if (net->ksnn_ninterfaces == LNET_NUM_INTERFACES) { > + } else if (net->ksnn_ninterfaces == LNET_INTERFACES_NUM) { > rc = -ENOSPC; > } else { > iface = &net->ksnn_interfaces[net->ksnn_ninterfaces++]; > @@ -2624,7 +2624,7 @@ ksocknal_enumerate_interfaces(struct ksock_net *net, char *iname) > continue; > } > > - if (j == LNET_NUM_INTERFACES) { > + if (j == LNET_INTERFACES_NUM) { > CWARN("Ignoring interface %s (too many interfaces)\n", > name); > continue; > @@ -2812,7 +2812,7 @@ ksocknal_startup(struct lnet_ni *ni) > > net->ksnn_ninterfaces = rc; > } else { > - for (i = 0; i < LNET_NUM_INTERFACES; i++) { > + for (i = 0; i < LNET_INTERFACES_NUM; i++) { > if (!ni->ni_interfaces[i]) > break; > rc = ksocknal_enumerate_interfaces(net, ni->ni_interfaces[i]); > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h > index 82e3523f6463..297d1e5af1bd 100644 > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h > @@ -173,7 +173,7 @@ struct ksock_net { > int ksnn_npeers; /* # peers */ > int ksnn_shutdown; /* shutting down? */ > int ksnn_ninterfaces; /* IP interfaces */ > - struct ksock_interface ksnn_interfaces[LNET_NUM_INTERFACES]; > + struct ksock_interface ksnn_interfaces[LNET_INTERFACES_NUM]; > }; > > /** connd timeout */ > @@ -441,7 +441,7 @@ struct ksock_peer { > int ksnp_n_passive_ips; /* # of... */ > > /* preferred local interfaces */ > - u32 ksnp_passive_ips[LNET_NUM_INTERFACES]; > + u32 ksnp_passive_ips[LNET_INTERFACES_NUM]; > }; > > struct ksock_connreq { > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c > index dc9a12910a8d..c401896bf649 100644 > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c > @@ -1579,7 +1579,7 @@ ksocknal_send_hello(struct lnet_ni *ni, struct ksock_conn *conn, > /* CAVEAT EMPTOR: this byte flips 'ipaddrs' */ > struct ksock_net *net = (struct ksock_net *)ni->ni_data; > > - LASSERT(hello->kshm_nips <= LNET_NUM_INTERFACES); > + LASSERT(hello->kshm_nips <= LNET_INTERFACES_NUM); > > /* rely on caller to hold a ref on socket so it wouldn't disappear */ > LASSERT(conn->ksnc_proto); > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c > index 10a2757895f3..54ec5d0a85c8 100644 > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c > @@ -614,7 +614,7 @@ ksocknal_recv_hello_v1(struct ksock_conn *conn, struct ksock_hello_msg *hello, > hello->kshm_nips = le32_to_cpu(hdr->payload_length) / > sizeof(__u32); > > - if (hello->kshm_nips > LNET_NUM_INTERFACES) { > + if (hello->kshm_nips > LNET_INTERFACES_NUM) { > CERROR("Bad nips %d from ip %pI4h\n", > hello->kshm_nips, &conn->ksnc_ipaddr); > rc = -EPROTO; > @@ -684,7 +684,7 @@ ksocknal_recv_hello_v2(struct ksock_conn *conn, struct ksock_hello_msg *hello, > __swab32s(&hello->kshm_nips); > } > > - if (hello->kshm_nips > LNET_NUM_INTERFACES) { > + if (hello->kshm_nips > LNET_INTERFACES_NUM) { > CERROR("Bad nips %d from ip %pI4h\n", > hello->kshm_nips, &conn->ksnc_ipaddr); > return -EPROTO; > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index b37abdedccaa..6a692d5c4608 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -34,6 +34,7 @@ > #define DEBUG_SUBSYSTEM S_LNET > #include > #include > +#include > > #include > #include > @@ -70,6 +71,13 @@ module_param(lnet_numa_range, uint, 0444); > MODULE_PARM_DESC(lnet_numa_range, > "NUMA range to consider during Multi-Rail selection"); > > +static int lnet_interfaces_max = LNET_INTERFACES_MAX_DEFAULT; > +static int intf_max_set(const char *val, const struct kernel_param *kp); > +module_param_call(lnet_interfaces_max, intf_max_set, param_get_int, > + &lnet_interfaces_max, 0644); > +MODULE_PARM_DESC(lnet_interfaces_max, > + "Maximum number of interfaces in a node."); > + > /* > * This sequence number keeps track of how many times DLC was used to > * update the local NIs. It is incremented when a NI is added or > @@ -82,6 +90,28 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); > static int lnet_ping(struct lnet_process_id id, signed long timeout, > struct lnet_process_id __user *ids, int n_ids); > > +static int > +intf_max_set(const char *val, const struct kernel_param *kp) > +{ > + int value, rc; > + > + rc = kstrtoint(val, 0, &value); > + if (rc) { > + CERROR("Invalid module parameter value for 'lnet_interfaces_max'\n"); > + return rc; > + } > + > + if (value < LNET_INTERFACES_MIN) { > + CWARN("max interfaces provided are too small, setting to %d\n", > + LNET_INTERFACES_MIN); > + value = LNET_INTERFACES_MIN; > + } > + > + *(int *)kp->arg = value; > + > + return 0; > +} > + > static char * > lnet_get_routes(void) > { > @@ -2924,7 +2954,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]); > > /* n_ids limit is arbitrary */ > - if (n_ids <= 0 || n_ids > 20 || id.nid == LNET_NID_ANY) > + if (n_ids <= 0 || n_ids > lnet_interfaces_max || id.nid == LNET_NID_ANY) > return -EINVAL; > > if (id.pid == LNET_PID_ANY) > diff --git a/drivers/staging/lustre/lnet/lnet/config.c b/drivers/staging/lustre/lnet/lnet/config.c > index 3ea56c81ec0e..087d9a8a6b6a 100644 > --- a/drivers/staging/lustre/lnet/lnet/config.c > +++ b/drivers/staging/lustre/lnet/lnet/config.c > @@ -123,10 +123,10 @@ lnet_ni_unique_net(struct list_head *nilist, char *iface) > /* check that the NI is unique to the interfaces with in the same NI. > * This is only a consideration if use_tcp_bonding is set */ > static bool > -lnet_ni_unique_ni(char *iface_list[LNET_NUM_INTERFACES], char *iface) > +lnet_ni_unique_ni(char *iface_list[LNET_INTERFACES_NUM], char *iface) > { > int i; > - for (i = 0; i < LNET_NUM_INTERFACES; i++) { > + for (i = 0; i < LNET_INTERFACES_NUM; i++) { > if (iface_list[i] && > strncmp(iface_list[i], iface, strlen(iface)) == 0) > return false; > @@ -304,7 +304,7 @@ lnet_ni_free(struct lnet_ni *ni) > > kfree(ni->ni_cpts); > > - for (i = 0; i < LNET_NUM_INTERFACES && ni->ni_interfaces[i]; i++) > + for (i = 0; i < LNET_INTERFACES_NUM && ni->ni_interfaces[i]; i++) > kfree(ni->ni_interfaces[i]); > > /* release reference to net namespace */ > @@ -397,11 +397,11 @@ lnet_ni_add_interface(struct lnet_ni *ni, char *iface) > * can free the tokens at the end of the function. > * The newly allocated ni_interfaces[] can be > * freed when freeing the NI */ > - while (niface < LNET_NUM_INTERFACES && > + while (niface < LNET_INTERFACES_NUM && > ni->ni_interfaces[niface]) > niface++; > > - if (niface >= LNET_NUM_INTERFACES) { > + if (niface >= LNET_INTERFACES_NUM) { > LCONSOLE_ERROR_MSG(0x115, "Too many interfaces " > "for net %s\n", > libcfs_net2str(LNET_NIDNET(ni->ni_nid))); > > > From jsimmons at infradead.org Sun Oct 14 19:10:31 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:10:31 +0100 (BST) Subject: [lustre-devel] [PATCH 02/24] lustre: lnet: configure lnet_interfaces_max tunable from dlc In-Reply-To: <153895437761.16383.2145517278397754849.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437761.16383.2145517278397754849.stgit@noble> Message-ID: > From: Olaf Weber > > Added the ability to configure lnet_interfaces_max from DLC. > Combined the configure and show of numa range and max interfaces > under a "global" YAML element when configuring using YAML. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Amir Shehata > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25771 > Signed-off-by: NeilBrown > --- > .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 6 +++--- > drivers/staging/lustre/lnet/lnet/api-ni.c | 16 ++++++++-------- > 2 files changed, 11 insertions(+), 11 deletions(-) > > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > index d88b30d2e76c..706892ca7efb 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-dlc.h > @@ -230,9 +230,9 @@ struct lnet_ioctl_peer_cfg { > void __user *prcfg_bulk; > }; > > -struct lnet_ioctl_numa_range { > - struct libcfs_ioctl_hdr nr_hdr; > - __u32 nr_range; > +struct lnet_ioctl_set_value { > + struct libcfs_ioctl_hdr sv_hdr; > + __u32 sv_value; > }; > > struct lnet_ioctl_lnet_stats { > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 6a692d5c4608..8b6400da2836 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -2708,24 +2708,24 @@ LNetCtl(unsigned int cmd, void *arg) > return rc; > > case IOC_LIBCFS_SET_NUMA_RANGE: { > - struct lnet_ioctl_numa_range *numa; > + struct lnet_ioctl_set_value *numa; > > numa = arg; > - if (numa->nr_hdr.ioc_len != sizeof(*numa)) > + if (numa->sv_hdr.ioc_len != sizeof(*numa)) > return -EINVAL; > - mutex_lock(&the_lnet.ln_api_mutex); > - lnet_numa_range = numa->nr_range; > - mutex_unlock(&the_lnet.ln_api_mutex); > + lnet_net_lock(LNET_LOCK_EX); > + lnet_numa_range = numa->sv_value; > + lnet_net_unlock(LNET_LOCK_EX); > return 0; > } > > case IOC_LIBCFS_GET_NUMA_RANGE: { > - struct lnet_ioctl_numa_range *numa; > + struct lnet_ioctl_set_value *numa; > > numa = arg; > - if (numa->nr_hdr.ioc_len != sizeof(*numa)) > + if (numa->sv_hdr.ioc_len != sizeof(*numa)) > return -EINVAL; > - numa->nr_range = lnet_numa_range; > + numa->sv_value = lnet_numa_range; > return 0; > } > > > > From jsimmons at infradead.org Sun Oct 14 19:29:25 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:29:25 +0100 (BST) Subject: [lustre-devel] [PATCH 03/24] lustre: lnet: add struct lnet_ping_buffer In-Reply-To: <153895437765.16383.7644707942018591818.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437765.16383.7644707942018591818.stgit@noble> Message-ID: > From: Olaf Weber > > The Multi-Rail code will use the ping target buffer also as the > source of data to push to other nodes. This means that there > will be multiple MDs referencing the same buffer, and care must > be taken to ensure that the buffer is not freed while any such > reference remains. > > Encapsulate the struct lnet_ping_info (aka lnet_ping_info_t) in > a struct lnet_ping_buffer. This adds a reference count, and the > number of NIDs for the encapsulated lnet_ping_info has been > sized. > > For sizing the buffer the constant LNET_PINGINFO_SIZE is replaced > with LNET_PING_INFO_SIZE(NNIS). Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25773 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 22 + > .../staging/lustre/include/linux/lnet/lib-types.h | 40 ++ > drivers/staging/lustre/lnet/lnet/api-ni.c | 345 +++++++++++--------- > drivers/staging/lustre/lnet/lnet/router.c | 94 +++-- > 4 files changed, 301 insertions(+), 200 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 16e64d83840d..2e2b5ed27116 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -634,7 +634,27 @@ int lnet_peer_buffer_credits(struct lnet_net *net); > int lnet_router_checker_start(void); > void lnet_router_checker_stop(void); > void lnet_router_ni_update_locked(struct lnet_peer_ni *gw, __u32 net); > -void lnet_swap_pinginfo(struct lnet_ping_info *info); > +void lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf); > + > +int lnet_ping_info_validate(struct lnet_ping_info *pinfo); > +struct lnet_ping_buffer *lnet_ping_buffer_alloc(int nnis, gfp_t gfp); > +void lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf); > + > +static inline void lnet_ping_buffer_addref(struct lnet_ping_buffer *pbuf) > +{ > + atomic_inc(&pbuf->pb_refcnt); > +} > + > +static inline void lnet_ping_buffer_decref(struct lnet_ping_buffer *pbuf) > +{ > + if (atomic_dec_and_test(&pbuf->pb_refcnt)) > + lnet_ping_buffer_free(pbuf); > +} > + > +static inline int lnet_ping_buffer_numref(struct lnet_ping_buffer *pbuf) > +{ > + return atomic_read(&pbuf->pb_refcnt); > +} > > int lnet_parse_ip2nets(char **networksp, char *ip2nets); > int lnet_parse_routes(char *route_str, int *im_a_router); > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 7b11c31f0029..ab8c6d66cdbf 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -387,12 +387,32 @@ struct lnet_ni { > #define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ > #define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ > > -#define LNET_PING_FEAT_MASK (LNET_PING_FEAT_BASE | \ > - LNET_PING_FEAT_NI_STATUS) > +#define LNET_PING_INFO_SIZE(NNIDS) \ > + offsetof(struct lnet_ping_info, pi_ni[NNIDS]) > +#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) > +#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) > + > +/* > + * Descriptor of a ping info buffer: keep a separate indicator of the > + * size and a reference count. The type is used both as a source and > + * sink of data, so we need to keep some information outside of the > + * area that may be overwritten by network data. > + */ > +struct lnet_ping_buffer { > + int pb_nnis; > + atomic_t pb_refcnt; > + struct lnet_ping_info pb_info; > +}; > + > +#define LNET_PING_BUFFER_SIZE(NNIDS) \ > + offsetof(struct lnet_ping_buffer, pb_info.pi_ni[NNIDS]) > +#define LNET_PING_BUFFER_LONI(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_nid) > +#define LNET_PING_BUFFER_SEQNO(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_status) > + > > /* router checker data, per router */ > -#define LNET_MAX_RTR_NIS 16 > -#define LNET_PINGINFO_SIZE offsetof(struct lnet_ping_info, pi_ni[LNET_MAX_RTR_NIS]) > +#define LNET_MAX_RTR_NIS LNET_INTERFACES_MIN > +#define LNET_RTR_PINGINFO_SIZE LNET_PING_INFO_SIZE(LNET_MAX_RTR_NIS) > struct lnet_rc_data { > /* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */ > struct list_head rcd_list; > @@ -401,7 +421,7 @@ struct lnet_rc_data { > /* reference to gateway */ > struct lnet_peer_ni *rcd_gateway; > /* ping buffer */ > - struct lnet_ping_info *rcd_pinginfo; > + struct lnet_ping_buffer *rcd_pingbuffer; > }; > > struct lnet_peer_ni { > @@ -792,9 +812,17 @@ struct lnet { > /* percpt router buffer pools */ > struct lnet_rtrbufpool **ln_rtrpools; > > + /* > + * Ping target / Push source > + * > + * The ping target and push source share a single buffer. The > + * ln_ping_target is protected against concurrent updates by > + * ln_api_mutex. > + */ > struct lnet_handle_md ln_ping_target_md; > struct lnet_handle_eq ln_ping_target_eq; > - struct lnet_ping_info *ln_ping_info; > + struct lnet_ping_buffer *ln_ping_target; > + atomic_t ln_ping_target_seqno; > > /* router checker startup/shutdown state */ > enum lnet_rc_state ln_rc_state; > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 8b6400da2836..ca28ad75fe2b 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -902,25 +902,44 @@ lnet_count_acceptor_nets(void) > return count; > } > > -static struct lnet_ping_info * > -lnet_ping_info_create(int num_ni) > +struct lnet_ping_buffer * > +lnet_ping_buffer_alloc(int nnis, gfp_t gfp) > { > - struct lnet_ping_info *ping_info; > - unsigned int infosz; > + struct lnet_ping_buffer *pbuf; > > - infosz = offsetof(struct lnet_ping_info, pi_ni[num_ni]); > - ping_info = kvzalloc(infosz, GFP_KERNEL); > - if (!ping_info) { > - CERROR("Can't allocate ping info[%d]\n", num_ni); > + pbuf = kmalloc(LNET_PING_BUFFER_SIZE(nnis), gfp); > + if (pbuf) { > + pbuf->pb_nnis = nnis; > + atomic_set(&pbuf->pb_refcnt, 1); > + } > + > + return pbuf; > +} > + > +void > +lnet_ping_buffer_free(struct lnet_ping_buffer *pbuf) > +{ > + LASSERT(lnet_ping_buffer_numref(pbuf) == 0); > + kfree(pbuf); > +} > + > +static struct lnet_ping_buffer * > +lnet_ping_target_create(int nnis) > +{ > + struct lnet_ping_buffer *pbuf; > + > + pbuf = lnet_ping_buffer_alloc(nnis, GFP_KERNEL); > + if (!pbuf) { > + CERROR("Can't allocate ping source [%d]\n", nnis); > return NULL; > } > > - ping_info->pi_nnis = num_ni; > - ping_info->pi_pid = the_lnet.ln_pid; > - ping_info->pi_magic = LNET_PROTO_PING_MAGIC; > - ping_info->pi_features = LNET_PING_FEAT_NI_STATUS; > + pbuf->pb_info.pi_nnis = nnis; > + pbuf->pb_info.pi_pid = the_lnet.ln_pid; > + pbuf->pb_info.pi_magic = LNET_PROTO_PING_MAGIC; > + pbuf->pb_info.pi_features = LNET_PING_FEAT_NI_STATUS; > > - return ping_info; > + return pbuf; > } > > static inline int > @@ -966,14 +985,25 @@ lnet_get_ni_count(void) > return count; > } > > -static inline void > -lnet_ping_info_free(struct lnet_ping_info *pinfo) > +int > +lnet_ping_info_validate(struct lnet_ping_info *pinfo) > { > - kvfree(pinfo); > + if (!pinfo) > + return -EINVAL; > + if (pinfo->pi_magic != LNET_PROTO_PING_MAGIC) > + return -EPROTO; > + if (!(pinfo->pi_features & LNET_PING_FEAT_NI_STATUS)) > + return -EPROTO; > + /* Loopback is guaranteed to be present */ > + if (pinfo->pi_nnis < 1 || pinfo->pi_nnis > lnet_interfaces_max) > + return -ERANGE; > + if (LNET_NETTYP(LNET_NIDNET(LNET_PING_INFO_LONI(pinfo))) != LOLND) > + return -EPROTO; > + return 0; > } > > static void > -lnet_ping_info_destroy(void) > +lnet_ping_target_destroy(void) > { > struct lnet_net *net; > struct lnet_ni *ni; > @@ -988,25 +1018,25 @@ lnet_ping_info_destroy(void) > } > } > > - lnet_ping_info_free(the_lnet.ln_ping_info); > - the_lnet.ln_ping_info = NULL; > + lnet_ping_buffer_decref(the_lnet.ln_ping_target); > + the_lnet.ln_ping_target = NULL; > > lnet_net_unlock(LNET_LOCK_EX); > } > > static void > -lnet_ping_event_handler(struct lnet_event *event) > +lnet_ping_target_event_handler(struct lnet_event *event) > { > - struct lnet_ping_info *pinfo = event->md.user_ptr; > + struct lnet_ping_buffer *pbuf = event->md.user_ptr; > > if (event->unlinked) > - pinfo->pi_features = LNET_PING_FEAT_INVAL; > + lnet_ping_buffer_decref(pbuf); > } > > static int > -lnet_ping_info_setup(struct lnet_ping_info **ppinfo, > - struct lnet_handle_md *md_handle, > - int ni_count, bool set_eq) > +lnet_ping_target_setup(struct lnet_ping_buffer **ppbuf, > + struct lnet_handle_md *ping_mdh, > + int ni_count, bool set_eq) > { > struct lnet_process_id id = { .nid = LNET_NID_ANY, > .pid = LNET_PID_ANY }; > @@ -1015,94 +1045,98 @@ lnet_ping_info_setup(struct lnet_ping_info **ppinfo, > int rc, rc2; > > if (set_eq) { > - rc = LNetEQAlloc(0, lnet_ping_event_handler, > + rc = LNetEQAlloc(0, lnet_ping_target_event_handler, > &the_lnet.ln_ping_target_eq); > if (rc) { > - CERROR("Can't allocate ping EQ: %d\n", rc); > + CERROR("Can't allocate ping buffer EQ: %d\n", rc); > return rc; > } > } > > - *ppinfo = lnet_ping_info_create(ni_count); > - if (!*ppinfo) { > + *ppbuf = lnet_ping_target_create(ni_count); > + if (!*ppbuf) { > rc = -ENOMEM; > - goto failed_0; > + goto fail_free_eq; > } > > + /* Ping target ME/MD */ > rc = LNetMEAttach(LNET_RESERVED_PORTAL, id, > LNET_PROTO_PING_MATCHBITS, 0, > LNET_UNLINK, LNET_INS_AFTER, > &me_handle); > if (rc) { > - CERROR("Can't create ping ME: %d\n", rc); > - goto failed_1; > + CERROR("Can't create ping target ME: %d\n", rc); > + goto fail_decref_ping_buffer; > } > > /* initialize md content */ > - md.start = *ppinfo; > - md.length = offsetof(struct lnet_ping_info, > - pi_ni[(*ppinfo)->pi_nnis]); > + md.start = &(*ppbuf)->pb_info; > + md.length = LNET_PING_INFO_SIZE((*ppbuf)->pb_nnis); > md.threshold = LNET_MD_THRESH_INF; > md.max_size = 0; > md.options = LNET_MD_OP_GET | LNET_MD_TRUNCATE | > LNET_MD_MANAGE_REMOTE; > - md.user_ptr = NULL; > md.eq_handle = the_lnet.ln_ping_target_eq; > - md.user_ptr = *ppinfo; > + md.user_ptr = *ppbuf; > > - rc = LNetMDAttach(me_handle, md, LNET_RETAIN, md_handle); > + rc = LNetMDAttach(me_handle, md, LNET_RETAIN, ping_mdh); > if (rc) { > - CERROR("Can't attach ping MD: %d\n", rc); > - goto failed_2; > + CERROR("Can't attach ping target MD: %d\n", rc); > + goto fail_unlink_ping_me; > } > + lnet_ping_buffer_addref(*ppbuf); > > return 0; > > -failed_2: > +fail_unlink_ping_me: > rc2 = LNetMEUnlink(me_handle); > LASSERT(!rc2); > -failed_1: > - lnet_ping_info_free(*ppinfo); > - *ppinfo = NULL; > -failed_0: > - if (set_eq) > - LNetEQFree(the_lnet.ln_ping_target_eq); > +fail_decref_ping_buffer: > + LASSERT(lnet_ping_buffer_numref(*ppbuf) == 1); > + lnet_ping_buffer_decref(*ppbuf); > + *ppbuf = NULL; > +fail_free_eq: > + if (set_eq) { > + rc2 = LNetEQFree(the_lnet.ln_ping_target_eq); > + LASSERT(rc2 == 0); > + } > return rc; > } > > static void > -lnet_ping_md_unlink(struct lnet_ping_info *pinfo, > - struct lnet_handle_md *md_handle) > +lnet_ping_md_unlink(struct lnet_ping_buffer *pbuf, > + struct lnet_handle_md *ping_mdh) > { > - LNetMDUnlink(*md_handle); > - LNetInvalidateMDHandle(md_handle); > + LNetMDUnlink(*ping_mdh); > + LNetInvalidateMDHandle(ping_mdh); > > - /* NB md could be busy; this just starts the unlink */ > - while (pinfo->pi_features != LNET_PING_FEAT_INVAL) { > - CDEBUG(D_NET, "Still waiting for ping MD to unlink\n"); > + /* NB the MD could be busy; this just starts the unlink */ > + while (lnet_ping_buffer_numref(pbuf) > 1) { > + CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n"); > schedule_timeout_idle(HZ); > } > } > > static void > -lnet_ping_info_install_locked(struct lnet_ping_info *ping_info) > +lnet_ping_target_install_locked(struct lnet_ping_buffer *pbuf) > { > struct lnet_ni_status *ns; > struct lnet_ni *ni; > struct lnet_net *net; > int i = 0; > + int rc; > > list_for_each_entry(net, &the_lnet.ln_nets, net_list) { > list_for_each_entry(ni, &net->net_ni_list, ni_netlist) { > - LASSERT(i < ping_info->pi_nnis); > + LASSERT(i < pbuf->pb_nnis); > > - ns = &ping_info->pi_ni[i]; > + ns = &pbuf->pb_info.pi_ni[i]; > > ns->ns_nid = ni->ni_nid; > > lnet_ni_lock(ni); > ns->ns_status = ni->ni_status ? > - ni->ni_status->ns_status : > + ni->ni_status->ns_status : > LNET_NI_STATUS_UP; > ni->ni_status = ns; > lnet_ni_unlock(ni); > @@ -1110,35 +1144,47 @@ lnet_ping_info_install_locked(struct lnet_ping_info *ping_info) > i++; > } > } > + /* > + * We (ab)use the ns_status of the loopback interface to > + * transmit the sequence number. The first interface listed > + * must be the loopback interface. > + */ > + rc = lnet_ping_info_validate(&pbuf->pb_info); > + if (rc) { > + LCONSOLE_EMERG("Invalid ping target: %d\n", rc); > + LBUG(); > + } > + LNET_PING_BUFFER_SEQNO(pbuf) = > + atomic_inc_return(&the_lnet.ln_ping_target_seqno); > } > > static void > -lnet_ping_target_update(struct lnet_ping_info *pinfo, > - struct lnet_handle_md md_handle) > +lnet_ping_target_update(struct lnet_ping_buffer *pbuf, > + struct lnet_handle_md ping_mdh) > { > - struct lnet_ping_info *old_pinfo = NULL; > - struct lnet_handle_md old_md; > + struct lnet_ping_buffer *old_pbuf = NULL; > + struct lnet_handle_md old_ping_md; > > /* switch the NIs to point to the new ping info created */ > lnet_net_lock(LNET_LOCK_EX); > > if (!the_lnet.ln_routing) > - pinfo->pi_features |= LNET_PING_FEAT_RTE_DISABLED; > - lnet_ping_info_install_locked(pinfo); > + pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; > + lnet_ping_target_install_locked(pbuf); > > - if (the_lnet.ln_ping_info) { > - old_pinfo = the_lnet.ln_ping_info; > - old_md = the_lnet.ln_ping_target_md; > + if (the_lnet.ln_ping_target) { > + old_pbuf = the_lnet.ln_ping_target; > + old_ping_md = the_lnet.ln_ping_target_md; > } > - the_lnet.ln_ping_target_md = md_handle; > - the_lnet.ln_ping_info = pinfo; > + the_lnet.ln_ping_target_md = ping_mdh; > + the_lnet.ln_ping_target = pbuf; > > lnet_net_unlock(LNET_LOCK_EX); > > - if (old_pinfo) { > - /* unlink the old ping info */ > - lnet_ping_md_unlink(old_pinfo, &old_md); > - lnet_ping_info_free(old_pinfo); > + if (old_pbuf) { > + /* unlink and free the old ping info */ > + lnet_ping_md_unlink(old_pbuf, &old_ping_md); > + lnet_ping_buffer_decref(old_pbuf); > } > } > > @@ -1147,13 +1193,13 @@ lnet_ping_target_fini(void) > { > int rc; > > - lnet_ping_md_unlink(the_lnet.ln_ping_info, > + lnet_ping_md_unlink(the_lnet.ln_ping_target, > &the_lnet.ln_ping_target_md); > > rc = LNetEQFree(the_lnet.ln_ping_target_eq); > LASSERT(!rc); > > - lnet_ping_info_destroy(); > + lnet_ping_target_destroy(); > } > > static int > @@ -1745,8 +1791,8 @@ LNetNIInit(lnet_pid_t requested_pid) > int im_a_router = 0; > int rc; > int ni_count; > - struct lnet_ping_info *pinfo; > - struct lnet_handle_md md_handle; > + struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md ping_mdh; > struct list_head net_head; > struct lnet_net *net; > > @@ -1823,11 +1869,11 @@ LNetNIInit(lnet_pid_t requested_pid) > the_lnet.ln_refcount = 1; > /* Now I may use my own API functions... */ > > - rc = lnet_ping_info_setup(&pinfo, &md_handle, ni_count, true); > + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, ni_count, true); > if (rc) > goto err_acceptor_stop; > > - lnet_ping_target_update(pinfo, md_handle); > + lnet_ping_target_update(pbuf, ping_mdh); > > rc = lnet_router_checker_start(); > if (rc) > @@ -1936,7 +1982,10 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni, > } > > cfg_ni->lic_nid = ni->ni_nid; > - cfg_ni->lic_status = ni->ni_status->ns_status; > + if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND) > + cfg_ni->lic_status = LNET_NI_STATUS_UP; > + else > + cfg_ni->lic_status = ni->ni_status->ns_status; > cfg_ni->lic_tcp_bonding = use_tcp_bonding; > cfg_ni->lic_dev_cpt = ni->ni_dev_cpt; > > @@ -2021,7 +2070,10 @@ lnet_fill_ni_info_legacy(struct lnet_ni *ni, > config->cfg_config_u.cfg_net.net_peer_rtr_credits = > ni->ni_net->net_tunables.lct_peer_rtr_credits; > > - net_config->ni_status = ni->ni_status->ns_status; > + if (LNET_NETTYP(LNET_NIDNET(ni->ni_nid)) == LOLND) > + net_config->ni_status = LNET_NI_STATUS_UP; > + else > + net_config->ni_status = ni->ni_status->ns_status; > > if (ni->ni_cpts) { > int num_cpts = min(ni->ni_ncpts, LNET_MAX_SHOW_NUM_CPT); > @@ -2172,8 +2224,8 @@ static int lnet_add_net_common(struct lnet_net *net, > struct lnet_ioctl_config_lnd_tunables *tun) > { > u32 net_id; > - struct lnet_ping_info *pinfo; > - struct lnet_handle_md md_handle; > + struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md ping_mdh; > int rc; > struct lnet_remotenet *rnet; > int net_ni_count; > @@ -2195,7 +2247,7 @@ static int lnet_add_net_common(struct lnet_net *net, > > /* > * make sure you calculate the correct number of slots in the ping > - * info. Since the ping info is a flattened list of all the NIs, > + * buffer. Since the ping info is a flattened list of all the NIs, > * we should allocate enough slots to accomodate the number of NIs > * which will be added. > * > @@ -2204,9 +2256,9 @@ static int lnet_add_net_common(struct lnet_net *net, > */ > net_ni_count = lnet_get_net_ni_count_pre(net); > > - rc = lnet_ping_info_setup(&pinfo, &md_handle, > - net_ni_count + lnet_get_ni_count(), > - false); > + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, > + net_ni_count + lnet_get_ni_count(), > + false); > if (rc < 0) { > lnet_net_free(net); > return rc; > @@ -2257,13 +2309,13 @@ static int lnet_add_net_common(struct lnet_net *net, > lnet_peer_net_added(net); > lnet_net_unlock(LNET_LOCK_EX); > > - lnet_ping_target_update(pinfo, md_handle); > + lnet_ping_target_update(pbuf, ping_mdh); > > return 0; > > failed: > - lnet_ping_md_unlink(pinfo, &md_handle); > - lnet_ping_info_free(pinfo); > + lnet_ping_md_unlink(pbuf, &ping_mdh); > + lnet_ping_buffer_decref(pbuf); > return rc; > } > > @@ -2354,8 +2406,8 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) > struct lnet_net *net; > struct lnet_ni *ni; > u32 net_id = LNET_NIDNET(conf->lic_nid); > - struct lnet_ping_info *pinfo; > - struct lnet_handle_md md_handle; > + struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md ping_mdh; > int rc; > int net_count; > u32 addr; > @@ -2373,7 +2425,7 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) > CERROR("net %s not found\n", > libcfs_net2str(net_id)); > rc = -ENOENT; > - goto net_unlock; > + goto unlock_net; > } > > addr = LNET_NIDADDR(conf->lic_nid); > @@ -2384,20 +2436,20 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) > lnet_net_unlock(0); > > /* create and link a new ping info, before removing the old one */ > - rc = lnet_ping_info_setup(&pinfo, &md_handle, > - lnet_get_ni_count() - net_count, > - false); > + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, > + lnet_get_ni_count() - net_count, > + false); > if (rc != 0) > - goto out; > + goto unlock_api_mutex; > > lnet_shutdown_lndnet(net); > > if (lnet_count_acceptor_nets() == 0) > lnet_acceptor_stop(); > > - lnet_ping_target_update(pinfo, md_handle); > + lnet_ping_target_update(pbuf, ping_mdh); > > - goto out; > + goto unlock_api_mutex; > } > > ni = lnet_nid2ni_locked(conf->lic_nid, 0); > @@ -2405,7 +2457,7 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) > CERROR("nid %s not found\n", > libcfs_nid2str(conf->lic_nid)); > rc = -ENOENT; > - goto net_unlock; > + goto unlock_net; > } > > net_count = lnet_get_net_ni_count_locked(net); > @@ -2413,27 +2465,27 @@ int lnet_dyn_del_ni(struct lnet_ioctl_config_ni *conf) > lnet_net_unlock(0); > > /* create and link a new ping info, before removing the old one */ > - rc = lnet_ping_info_setup(&pinfo, &md_handle, > - lnet_get_ni_count() - 1, false); > + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, > + lnet_get_ni_count() - 1, false); > if (rc != 0) > - goto out; > + goto unlock_api_mutex; > > lnet_shutdown_lndni(ni); > > if (lnet_count_acceptor_nets() == 0) > lnet_acceptor_stop(); > > - lnet_ping_target_update(pinfo, md_handle); > + lnet_ping_target_update(pbuf, ping_mdh); > > /* check if the net is empty and remove it if it is */ > if (net_count == 1) > lnet_shutdown_lndnet(net); > > - goto out; > + goto unlock_api_mutex; > > -net_unlock: > +unlock_net: > lnet_net_unlock(0); > -out: > +unlock_api_mutex: > mutex_unlock(&the_lnet.ln_api_mutex); > > return rc; > @@ -2501,8 +2553,8 @@ int > lnet_dyn_del_net(__u32 net_id) > { > struct lnet_net *net; > - struct lnet_ping_info *pinfo; > - struct lnet_handle_md md_handle; > + struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md ping_mdh; > int rc; > int net_ni_count; > > @@ -2525,8 +2577,8 @@ lnet_dyn_del_net(__u32 net_id) > lnet_net_unlock(0); > > /* create and link a new ping info, before removing the old one */ > - rc = lnet_ping_info_setup(&pinfo, &md_handle, > - lnet_get_ni_count() - net_ni_count, false); > + rc = lnet_ping_target_setup(&pbuf, &ping_mdh, > + lnet_get_ni_count() - net_ni_count, false); > if (rc) > goto out; > > @@ -2535,7 +2587,7 @@ lnet_dyn_del_net(__u32 net_id) > if (!lnet_count_acceptor_nets()) > lnet_acceptor_stop(); > > - lnet_ping_target_update(pinfo, md_handle); > + lnet_ping_target_update(pbuf, ping_mdh); > > out: > mutex_unlock(&the_lnet.ln_api_mutex); > @@ -2943,16 +2995,13 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > int unlinked = 0; > int replied = 0; > const signed long a_long_time = 60*HZ; > - int infosz; > - struct lnet_ping_info *info; > + struct lnet_ping_buffer *pbuf; > struct lnet_process_id tmpid; > int i; > int nob; > int rc; > int rc2; > > - infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]); > - > /* n_ids limit is arbitrary */ > if (n_ids <= 0 || n_ids > lnet_interfaces_max || id.nid == LNET_NID_ANY) > return -EINVAL; > @@ -2960,20 +3009,20 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > if (id.pid == LNET_PID_ANY) > id.pid = LNET_PID_LUSTRE; > > - info = kzalloc(infosz, GFP_KERNEL); > - if (!info) > + pbuf = lnet_ping_buffer_alloc(n_ids, GFP_NOFS); > + if (!pbuf) > return -ENOMEM; > > /* NB 2 events max (including any unlink event) */ > rc = LNetEQAlloc(2, LNET_EQ_HANDLER_NONE, &eqh); > if (rc) { > CERROR("Can't allocate EQ: %d\n", rc); > - goto out_0; > + goto fail_ping_buffer_decref; > } > > /* initialize md content */ > - md.start = info; > - md.length = infosz; > + md.start = &pbuf->pb_info; > + md.length = LNET_PING_INFO_SIZE(n_ids); > md.threshold = 2; /*GET/REPLY*/ > md.max_size = 0; > md.options = LNET_MD_TRUNCATE; > @@ -2983,7 +3032,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > rc = LNetMDBind(md, LNET_UNLINK, &mdh); > if (rc) { > CERROR("Can't bind MD: %d\n", rc); > - goto out_1; > + goto fail_free_eq; > } > > rc = LNetGet(LNET_NID_ANY, mdh, id, > @@ -3044,11 +3093,11 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > CWARN("%s: Unexpected rc >= 0 but no reply!\n", > libcfs_id2str(id)); > rc = -EIO; > - goto out_1; > + goto fail_free_eq; > } > > nob = rc; > - LASSERT(nob >= 0 && nob <= infosz); > + LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids)); > > rc = -EPROTO; /* if I can't parse... */ > > @@ -3056,56 +3105,56 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > /* can't check magic/version */ > CERROR("%s: ping info too short %d\n", > libcfs_id2str(id), nob); > - goto out_1; > + goto fail_free_eq; > } > > - if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { > - lnet_swap_pinginfo(info); > - } else if (info->pi_magic != LNET_PROTO_PING_MAGIC) { > + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) { > + lnet_swap_pinginfo(pbuf); > + } else if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) { > CERROR("%s: Unexpected magic %08x\n", > - libcfs_id2str(id), info->pi_magic); > - goto out_1; > + libcfs_id2str(id), pbuf->pb_info.pi_magic); > + goto fail_free_eq; > } > > - if (!(info->pi_features & LNET_PING_FEAT_NI_STATUS)) { > + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_NI_STATUS)) { > CERROR("%s: ping w/o NI status: 0x%x\n", > - libcfs_id2str(id), info->pi_features); > - goto out_1; > + libcfs_id2str(id), pbuf->pb_info.pi_features); > + goto fail_free_eq; > } > > - if (nob < offsetof(struct lnet_ping_info, pi_ni[0])) { > + if (nob < LNET_PING_INFO_SIZE(0)) { > CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), > - nob, (int)offsetof(struct lnet_ping_info, pi_ni[0])); > - goto out_1; > + nob, (int)LNET_PING_INFO_SIZE(0)); > + goto fail_free_eq; > } > > - if (info->pi_nnis < n_ids) > - n_ids = info->pi_nnis; > + if (pbuf->pb_info.pi_nnis < n_ids) > + n_ids = pbuf->pb_info.pi_nnis; > > - if (nob < offsetof(struct lnet_ping_info, pi_ni[n_ids])) { > + if (nob < LNET_PING_INFO_SIZE(n_ids)) { > CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), > - nob, (int)offsetof(struct lnet_ping_info, pi_ni[n_ids])); > - goto out_1; > + nob, (int)LNET_PING_INFO_SIZE(n_ids)); > + goto fail_free_eq; > } > > rc = -EFAULT; /* If I SEGV... */ > > memset(&tmpid, 0, sizeof(tmpid)); > for (i = 0; i < n_ids; i++) { > - tmpid.pid = info->pi_pid; > - tmpid.nid = info->pi_ni[i].ns_nid; > + tmpid.pid = pbuf->pb_info.pi_pid; > + tmpid.nid = pbuf->pb_info.pi_ni[i].ns_nid; > if (copy_to_user(&ids[i], &tmpid, sizeof(tmpid))) > - goto out_1; > + goto fail_free_eq; > } > - rc = info->pi_nnis; > + rc = pbuf->pb_info.pi_nnis; > > - out_1: > + fail_free_eq: > rc2 = LNetEQFree(eqh); > if (rc2) > CERROR("rc2 %d\n", rc2); > LASSERT(!rc2); > > - out_0: > - kfree(info); > + fail_ping_buffer_decref: > + lnet_ping_buffer_decref(pbuf); > return rc; > } > diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c > index b31a383fe974..e97957ce9252 100644 > --- a/drivers/staging/lustre/lnet/lnet/router.c > +++ b/drivers/staging/lustre/lnet/lnet/router.c > @@ -618,17 +618,21 @@ lnet_get_route(int idx, __u32 *net, __u32 *hops, > } > > void > -lnet_swap_pinginfo(struct lnet_ping_info *info) > +lnet_swap_pinginfo(struct lnet_ping_buffer *pbuf) > { > - int i; > struct lnet_ni_status *stat; > + int nnis; > + int i; > > - __swab32s(&info->pi_magic); > - __swab32s(&info->pi_features); > - __swab32s(&info->pi_pid); > - __swab32s(&info->pi_nnis); > - for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) { > - stat = &info->pi_ni[i]; > + __swab32s(&pbuf->pb_info.pi_magic); > + __swab32s(&pbuf->pb_info.pi_features); > + __swab32s(&pbuf->pb_info.pi_pid); > + __swab32s(&pbuf->pb_info.pi_nnis); > + nnis = pbuf->pb_info.pi_nnis; > + if (nnis > pbuf->pb_nnis) > + nnis = pbuf->pb_nnis; > + for (i = 0; i < nnis; i++) { > + stat = &pbuf->pb_info.pi_ni[i]; > __swab64s(&stat->ns_nid); > __swab32s(&stat->ns_status); > } > @@ -641,11 +645,12 @@ lnet_swap_pinginfo(struct lnet_ping_info *info) > static void > lnet_parse_rc_info(struct lnet_rc_data *rcd) > { > - struct lnet_ping_info *info = rcd->rcd_pinginfo; > + struct lnet_ping_buffer *pbuf = rcd->rcd_pingbuffer; > struct lnet_peer_ni *gw = rcd->rcd_gateway; > struct lnet_route *rte; > + int nnis; > > - if (!gw->lpni_alive) > + if (!gw->lpni_alive || !pbuf) > return; > > /* > @@ -654,51 +659,48 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) > */ > spin_lock(&gw->lpni_lock); > > - if (info->pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) > - lnet_swap_pinginfo(info); > + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) > + lnet_swap_pinginfo(pbuf); > > /* NB always racing with network! */ > - if (info->pi_magic != LNET_PROTO_PING_MAGIC) { > + if (pbuf->pb_info.pi_magic != LNET_PROTO_PING_MAGIC) { > CDEBUG(D_NET, "%s: Unexpected magic %08x\n", > - libcfs_nid2str(gw->lpni_nid), info->pi_magic); > + libcfs_nid2str(gw->lpni_nid), pbuf->pb_info.pi_magic); > gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; > - spin_unlock(&gw->lpni_lock); > - return; > + goto out; > } > > - gw->lpni_ping_feats = info->pi_features; > - if (!(gw->lpni_ping_feats & LNET_PING_FEAT_MASK)) { > - CDEBUG(D_NET, "%s: Unexpected features 0x%x\n", > - libcfs_nid2str(gw->lpni_nid), gw->lpni_ping_feats); > - spin_unlock(&gw->lpni_lock); > - return; /* nothing I can understand */ > - } > + gw->lpni_ping_feats = pbuf->pb_info.pi_features; > > - if (!(gw->lpni_ping_feats & LNET_PING_FEAT_NI_STATUS)) { > - spin_unlock(&gw->lpni_lock); > - return; /* can't carry NI status info */ > - } > + /* Without NI status info there's nothing more to do. */ > + if (!(gw->lpni_ping_feats & LNET_PING_FEAT_NI_STATUS)) > + goto out; > + > + /* Determine the number of NIs for which there is data. */ > + nnis = pbuf->pb_info.pi_nnis; > + if (pbuf->pb_nnis < nnis) > + nnis = pbuf->pb_nnis; > > list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) { > int down = 0; > int up = 0; > int i; > > + /* If routing disabled then the route is down. */ > if (gw->lpni_ping_feats & LNET_PING_FEAT_RTE_DISABLED) { > rte->lr_downis = 1; > continue; > } > > - for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) { > - struct lnet_ni_status *stat = &info->pi_ni[i]; > + for (i = 0; i < nnis; i++) { > + struct lnet_ni_status *stat = &pbuf->pb_info.pi_ni[i]; > lnet_nid_t nid = stat->ns_nid; > > if (nid == LNET_NID_ANY) { > CDEBUG(D_NET, "%s: unexpected LNET_NID_ANY\n", > libcfs_nid2str(gw->lpni_nid)); > gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; > - spin_unlock(&gw->lpni_lock); > - return; > + goto out; > } > > if (LNET_NETTYP(LNET_NIDNET(nid)) == LOLND) > @@ -720,8 +722,7 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) > CDEBUG(D_NET, "%s: Unexpected status 0x%x\n", > libcfs_nid2str(gw->lpni_nid), stat->ns_status); > gw->lpni_ping_feats = LNET_PING_FEAT_INVAL; > - spin_unlock(&gw->lpni_lock); > - return; > + goto out; > } > > if (up) { /* ignore downed NIs if NI for dest network is up */ > @@ -737,7 +738,7 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) > > rte->lr_downis = down; > } > - > +out: > spin_unlock(&gw->lpni_lock); > } > > @@ -903,7 +904,8 @@ lnet_destroy_rc_data(struct lnet_rc_data *rcd) > lnet_net_unlock(cpt); > } > > - kfree(rcd->rcd_pinginfo); > + if (rcd->rcd_pingbuffer) > + lnet_ping_buffer_decref(rcd->rcd_pingbuffer); > > kfree(rcd); > } > @@ -912,7 +914,7 @@ static struct lnet_rc_data * > lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > { > struct lnet_rc_data *rcd = NULL; > - struct lnet_ping_info *pi; > + struct lnet_ping_buffer *pbuf; > struct lnet_md md; > int rc; > int i; > @@ -926,19 +928,19 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > LNetInvalidateMDHandle(&rcd->rcd_mdh); > INIT_LIST_HEAD(&rcd->rcd_list); > > - pi = kzalloc(LNET_PINGINFO_SIZE, GFP_NOFS); > - if (!pi) > + pbuf = lnet_ping_buffer_alloc(LNET_MAX_RTR_NIS, GFP_NOFS); > + if (!pbuf) > goto out; > > for (i = 0; i < LNET_MAX_RTR_NIS; i++) { > - pi->pi_ni[i].ns_nid = LNET_NID_ANY; > - pi->pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; > + pbuf->pb_info.pi_ni[i].ns_nid = LNET_NID_ANY; > + pbuf->pb_info.pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; > } > - rcd->rcd_pinginfo = pi; > + rcd->rcd_pingbuffer = pbuf; > > - md.start = pi; > + md.start = &pbuf->pb_info; > md.user_ptr = rcd; > - md.length = LNET_PINGINFO_SIZE; > + md.length = LNET_RTR_PINGINFO_SIZE; > md.threshold = LNET_MD_THRESH_INF; > md.options = LNET_MD_TRUNCATE; > md.eq_handle = the_lnet.ln_rc_eqh; > @@ -1714,7 +1716,8 @@ lnet_rtrpools_enable(void) > lnet_net_lock(LNET_LOCK_EX); > the_lnet.ln_routing = 1; > > - the_lnet.ln_ping_info->pi_features &= ~LNET_PING_FEAT_RTE_DISABLED; > + the_lnet.ln_ping_target->pb_info.pi_features &= > + ~LNET_PING_FEAT_RTE_DISABLED; > lnet_net_unlock(LNET_LOCK_EX); > > return rc; > @@ -1728,7 +1731,8 @@ lnet_rtrpools_disable(void) > > lnet_net_lock(LNET_LOCK_EX); > the_lnet.ln_routing = 0; > - the_lnet.ln_ping_info->pi_features |= LNET_PING_FEAT_RTE_DISABLED; > + the_lnet.ln_ping_target->pb_info.pi_features |= > + LNET_PING_FEAT_RTE_DISABLED; > > tiny_router_buffers = 0; > small_router_buffers = 0; > > > From jsimmons at infradead.org Sun Oct 14 19:32:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:32:51 +0100 (BST) Subject: [lustre-devel] [PATCH 04/24] lustre: lnet: automatic sizing of router pinger buffers In-Reply-To: <153895437770.16383.3391026679795909640.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437770.16383.3391026679795909640.stgit@noble> Message-ID: > From: Olaf Weber > > The router pinger uses fixed-size buffers to receive the data > returned by a ping. When a router has more than 16 interfaces > (including loopback) this means the data for some interfaces > is dropped. > > Detect this situation, and track the number of remote NIs in > the lnet_rc_data_t structure. lnet_create_rc_data_locked() > becomes lnet_update_rc_data_locked(), and modified to replace > an existing ping buffer if one is present. It is now also > called by lnet_ping_router_locked() when the existing ping > buffer is too small. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25774 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-types.h | 4 - > drivers/staging/lustre/lnet/lnet/router.c | 90 +++++++++++++------- > 2 files changed, 60 insertions(+), 34 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index ab8c6d66cdbf..d1d17ededd06 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -411,8 +411,6 @@ struct lnet_ping_buffer { > > > /* router checker data, per router */ > -#define LNET_MAX_RTR_NIS LNET_INTERFACES_MIN > -#define LNET_RTR_PINGINFO_SIZE LNET_PING_INFO_SIZE(LNET_MAX_RTR_NIS) > struct lnet_rc_data { > /* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */ > struct list_head rcd_list; > @@ -422,6 +420,8 @@ struct lnet_rc_data { > struct lnet_peer_ni *rcd_gateway; > /* ping buffer */ > struct lnet_ping_buffer *rcd_pingbuffer; > + /* desired size of buffer */ > + int rcd_nnis; > }; > > struct lnet_peer_ni { > diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c > index e97957ce9252..86cce27e10d8 100644 > --- a/drivers/staging/lustre/lnet/lnet/router.c > +++ b/drivers/staging/lustre/lnet/lnet/router.c > @@ -678,8 +678,11 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) > > /* Determine the number of NIs for which there is data. */ > nnis = pbuf->pb_info.pi_nnis; > - if (pbuf->pb_nnis < nnis) > + if (pbuf->pb_nnis < nnis) { > + if (rcd->rcd_nnis < nnis) > + rcd->rcd_nnis = nnis; > nnis = pbuf->pb_nnis; > + } > > list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) { > int down = 0; > @@ -911,28 +914,47 @@ lnet_destroy_rc_data(struct lnet_rc_data *rcd) > } > > static struct lnet_rc_data * > -lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > +lnet_update_rc_data_locked(struct lnet_peer_ni *gateway) > { > - struct lnet_rc_data *rcd = NULL; > - struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md mdh; > + struct lnet_rc_data *rcd; > + struct lnet_ping_buffer *pbuf = NULL; > struct lnet_md md; > + int nnis = LNET_INTERFACES_MIN; > int rc; > int i; > > + rcd = gateway->lpni_rcd; > + if (rcd) { > + nnis = rcd->rcd_nnis; > + mdh = rcd->rcd_mdh; > + LNetInvalidateMDHandle(&rcd->rcd_mdh); > + pbuf = rcd->rcd_pingbuffer; > + rcd->rcd_pingbuffer = NULL; > + } else { > + LNetInvalidateMDHandle(&mdh); > + } > + > lnet_net_unlock(gateway->lpni_cpt); > > - rcd = kzalloc(sizeof(*rcd), GFP_NOFS); > - if (!rcd) > - goto out; > + if (rcd) { > + LNetMDUnlink(mdh); > + lnet_ping_buffer_decref(pbuf); > + } else { > + rcd = kzalloc(sizeof(*rcd), GFP_NOFS); > + if (!rcd) > + goto out; > > - LNetInvalidateMDHandle(&rcd->rcd_mdh); > - INIT_LIST_HEAD(&rcd->rcd_list); > + LNetInvalidateMDHandle(&rcd->rcd_mdh); > + INIT_LIST_HEAD(&rcd->rcd_list); > + rcd->rcd_nnis = nnis; > + } > > - pbuf = lnet_ping_buffer_alloc(LNET_MAX_RTR_NIS, GFP_NOFS); > + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); > if (!pbuf) > goto out; > > - for (i = 0; i < LNET_MAX_RTR_NIS; i++) { > + for (i = 0; i < nnis; i++) { > pbuf->pb_info.pi_ni[i].ns_nid = LNET_NID_ANY; > pbuf->pb_info.pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; > } > @@ -940,7 +962,7 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > > md.start = &pbuf->pb_info; > md.user_ptr = rcd; > - md.length = LNET_RTR_PINGINFO_SIZE; > + md.length = LNET_PING_INFO_SIZE(nnis); > md.threshold = LNET_MD_THRESH_INF; > md.options = LNET_MD_TRUNCATE; > md.eq_handle = the_lnet.ln_rc_eqh; > @@ -949,33 +971,37 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > rc = LNetMDBind(md, LNET_UNLINK, &rcd->rcd_mdh); > if (rc < 0) { > CERROR("Can't bind MD: %d\n", rc); > - goto out; > + goto out_ping_buffer_decref; > } > LASSERT(!rc); > > lnet_net_lock(gateway->lpni_cpt); > - /* router table changed or someone has created rcd for this gateway */ > - if (!lnet_isrouter(gateway) || gateway->lpni_rcd) { > - lnet_net_unlock(gateway->lpni_cpt); > - goto out; > + /* Check if this is still a router. */ > + if (!lnet_isrouter(gateway)) > + goto out_unlock; > + /* Check if someone else installed router data. */ > + if (gateway->lpni_rcd && gateway->lpni_rcd != rcd) > + goto out_unlock; > + > + /* Install and/or update the router data. */ > + if (!gateway->lpni_rcd) { > + lnet_peer_ni_addref_locked(gateway); > + rcd->rcd_gateway = gateway; > + gateway->lpni_rcd = rcd; > } > - > - lnet_peer_ni_addref_locked(gateway); > - rcd->rcd_gateway = gateway; > - gateway->lpni_rcd = rcd; > gateway->lpni_ping_notsent = 0; > > return rcd; > > - out: > - if (rcd) { > - if (!LNetMDHandleIsInvalid(rcd->rcd_mdh)) { > - rc = LNetMDUnlink(rcd->rcd_mdh); > - LASSERT(!rc); > - } > +out_unlock: > + lnet_net_unlock(gateway->lpni_cpt); > + rc = LNetMDUnlink(mdh); > + LASSERT(!rc); > +out_ping_buffer_decref: > + lnet_ping_buffer_decref(pbuf); > +out: > + if (rcd && rcd != gateway->lpni_rcd) > lnet_destroy_rc_data(rcd); > - } > - > lnet_net_lock(gateway->lpni_cpt); > return gateway->lpni_rcd; > } > @@ -1018,9 +1044,9 @@ lnet_ping_router_locked(struct lnet_peer_ni *rtr) > return; > } > > - rcd = rtr->lpni_rcd ? > - rtr->lpni_rcd : lnet_create_rc_data_locked(rtr); > - > + rcd = rtr->lpni_rcd; > + if (!rcd || rcd->rcd_nnis > rcd->rcd_pingbuffer->pb_nnis) > + rcd = lnet_update_rc_data_locked(rtr); > if (!rcd) > return; > > > > From jsimmons at infradead.org Sun Oct 14 19:33:31 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:33:31 +0100 (BST) Subject: [lustre-devel] [PATCH 04/24] lustre: lnet: automatic sizing of router pinger buffers In-Reply-To: <153895437770.16383.3391026679795909640.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437770.16383.3391026679795909640.stgit@noble> Message-ID: > From: Olaf Weber > > The router pinger uses fixed-size buffers to receive the data > returned by a ping. When a router has more than 16 interfaces > (including loopback) this means the data for some interfaces > is dropped. > > Detect this situation, and track the number of remote NIs in > the lnet_rc_data_t structure. lnet_create_rc_data_locked() > becomes lnet_update_rc_data_locked(), and modified to replace > an existing ping buffer if one is present. It is now also > called by lnet_ping_router_locked() when the existing ping > buffer is too small. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25774 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-types.h | 4 - > drivers/staging/lustre/lnet/lnet/router.c | 90 +++++++++++++------- > 2 files changed, 60 insertions(+), 34 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index ab8c6d66cdbf..d1d17ededd06 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -411,8 +411,6 @@ struct lnet_ping_buffer { > > > /* router checker data, per router */ > -#define LNET_MAX_RTR_NIS LNET_INTERFACES_MIN > -#define LNET_RTR_PINGINFO_SIZE LNET_PING_INFO_SIZE(LNET_MAX_RTR_NIS) > struct lnet_rc_data { > /* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */ > struct list_head rcd_list; > @@ -422,6 +420,8 @@ struct lnet_rc_data { > struct lnet_peer_ni *rcd_gateway; > /* ping buffer */ > struct lnet_ping_buffer *rcd_pingbuffer; > + /* desired size of buffer */ > + int rcd_nnis; > }; > > struct lnet_peer_ni { > diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c > index e97957ce9252..86cce27e10d8 100644 > --- a/drivers/staging/lustre/lnet/lnet/router.c > +++ b/drivers/staging/lustre/lnet/lnet/router.c > @@ -678,8 +678,11 @@ lnet_parse_rc_info(struct lnet_rc_data *rcd) > > /* Determine the number of NIs for which there is data. */ > nnis = pbuf->pb_info.pi_nnis; > - if (pbuf->pb_nnis < nnis) > + if (pbuf->pb_nnis < nnis) { > + if (rcd->rcd_nnis < nnis) > + rcd->rcd_nnis = nnis; > nnis = pbuf->pb_nnis; > + } > > list_for_each_entry(rte, &gw->lpni_routes, lr_gwlist) { > int down = 0; > @@ -911,28 +914,47 @@ lnet_destroy_rc_data(struct lnet_rc_data *rcd) > } > > static struct lnet_rc_data * > -lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > +lnet_update_rc_data_locked(struct lnet_peer_ni *gateway) > { > - struct lnet_rc_data *rcd = NULL; > - struct lnet_ping_buffer *pbuf; > + struct lnet_handle_md mdh; > + struct lnet_rc_data *rcd; > + struct lnet_ping_buffer *pbuf = NULL; > struct lnet_md md; > + int nnis = LNET_INTERFACES_MIN; > int rc; > int i; > > + rcd = gateway->lpni_rcd; > + if (rcd) { > + nnis = rcd->rcd_nnis; > + mdh = rcd->rcd_mdh; > + LNetInvalidateMDHandle(&rcd->rcd_mdh); > + pbuf = rcd->rcd_pingbuffer; > + rcd->rcd_pingbuffer = NULL; > + } else { > + LNetInvalidateMDHandle(&mdh); > + } > + > lnet_net_unlock(gateway->lpni_cpt); > > - rcd = kzalloc(sizeof(*rcd), GFP_NOFS); > - if (!rcd) > - goto out; > + if (rcd) { > + LNetMDUnlink(mdh); > + lnet_ping_buffer_decref(pbuf); > + } else { > + rcd = kzalloc(sizeof(*rcd), GFP_NOFS); > + if (!rcd) > + goto out; > > - LNetInvalidateMDHandle(&rcd->rcd_mdh); > - INIT_LIST_HEAD(&rcd->rcd_list); > + LNetInvalidateMDHandle(&rcd->rcd_mdh); > + INIT_LIST_HEAD(&rcd->rcd_list); > + rcd->rcd_nnis = nnis; > + } > > - pbuf = lnet_ping_buffer_alloc(LNET_MAX_RTR_NIS, GFP_NOFS); > + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); > if (!pbuf) > goto out; > > - for (i = 0; i < LNET_MAX_RTR_NIS; i++) { > + for (i = 0; i < nnis; i++) { > pbuf->pb_info.pi_ni[i].ns_nid = LNET_NID_ANY; > pbuf->pb_info.pi_ni[i].ns_status = LNET_NI_STATUS_INVALID; > } > @@ -940,7 +962,7 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > > md.start = &pbuf->pb_info; > md.user_ptr = rcd; > - md.length = LNET_RTR_PINGINFO_SIZE; > + md.length = LNET_PING_INFO_SIZE(nnis); > md.threshold = LNET_MD_THRESH_INF; > md.options = LNET_MD_TRUNCATE; > md.eq_handle = the_lnet.ln_rc_eqh; > @@ -949,33 +971,37 @@ lnet_create_rc_data_locked(struct lnet_peer_ni *gateway) > rc = LNetMDBind(md, LNET_UNLINK, &rcd->rcd_mdh); > if (rc < 0) { > CERROR("Can't bind MD: %d\n", rc); > - goto out; > + goto out_ping_buffer_decref; > } > LASSERT(!rc); > > lnet_net_lock(gateway->lpni_cpt); > - /* router table changed or someone has created rcd for this gateway */ > - if (!lnet_isrouter(gateway) || gateway->lpni_rcd) { > - lnet_net_unlock(gateway->lpni_cpt); > - goto out; > + /* Check if this is still a router. */ > + if (!lnet_isrouter(gateway)) > + goto out_unlock; > + /* Check if someone else installed router data. */ > + if (gateway->lpni_rcd && gateway->lpni_rcd != rcd) > + goto out_unlock; > + > + /* Install and/or update the router data. */ > + if (!gateway->lpni_rcd) { > + lnet_peer_ni_addref_locked(gateway); > + rcd->rcd_gateway = gateway; > + gateway->lpni_rcd = rcd; > } > - > - lnet_peer_ni_addref_locked(gateway); > - rcd->rcd_gateway = gateway; > - gateway->lpni_rcd = rcd; > gateway->lpni_ping_notsent = 0; > > return rcd; > > - out: > - if (rcd) { > - if (!LNetMDHandleIsInvalid(rcd->rcd_mdh)) { > - rc = LNetMDUnlink(rcd->rcd_mdh); > - LASSERT(!rc); > - } > +out_unlock: > + lnet_net_unlock(gateway->lpni_cpt); > + rc = LNetMDUnlink(mdh); > + LASSERT(!rc); > +out_ping_buffer_decref: > + lnet_ping_buffer_decref(pbuf); > +out: > + if (rcd && rcd != gateway->lpni_rcd) > lnet_destroy_rc_data(rcd); > - } > - > lnet_net_lock(gateway->lpni_cpt); > return gateway->lpni_rcd; > } > @@ -1018,9 +1044,9 @@ lnet_ping_router_locked(struct lnet_peer_ni *rtr) > return; > } > > - rcd = rtr->lpni_rcd ? > - rtr->lpni_rcd : lnet_create_rc_data_locked(rtr); > - > + rcd = rtr->lpni_rcd; > + if (!rcd || rcd->rcd_nnis > rcd->rcd_pingbuffer->pb_nnis) > + rcd = lnet_update_rc_data_locked(rtr); > if (!rcd) > return; > > > > From jsimmons at infradead.org Sun Oct 14 19:34:36 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:34:36 +0100 (BST) Subject: [lustre-devel] [PATCH 05/24] lustre: lnet: add Multi-Rail and Discovery ping feature bits In-Reply-To: <153895437774.16383.2810116639916310757.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437774.16383.2810116639916310757.stgit@noble> Message-ID: > From: Olaf Weber > > Claim ping features bit for Multi-Rail and Discovery. > > Assert in lnet_ping_target_update() that no unknown bits will > be send over the wire. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25775 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-types.h | 16 ++++++++++++++++ > drivers/staging/lustre/lnet/lnet/api-ni.c | 5 +++++ > 2 files changed, 21 insertions(+) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index d1d17ededd06..f4467a3bbfd1 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -386,6 +386,22 @@ struct lnet_ni { > #define LNET_PING_FEAT_BASE BIT(0) /* just a ping */ > #define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ > #define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ > +#define LNET_PING_FEAT_MULTI_RAIL BIT(3) /* Multi-Rail aware */ > +#define LNET_PING_FEAT_DISCOVERY BIT(4) /* Supports Discovery */ > + > +/* > + * All ping feature bits fit to hit the wire. > + * In lnet_assert_wire_constants() this is compared against its open-coded > + * value, and in lnet_ping_target_update() it is used to verify that no > + * unknown bits have been set. > + * New feature bits can be added, just be aware that this does change the > + * over-the-wire protocol. > + */ > +#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ > + LNET_PING_FEAT_NI_STATUS | \ > + LNET_PING_FEAT_RTE_DISABLED | \ > + LNET_PING_FEAT_MULTI_RAIL | \ > + LNET_PING_FEAT_DISCOVERY) > > #define LNET_PING_INFO_SIZE(NNIDS) \ > offsetof(struct lnet_ping_info, pi_ni[NNIDS]) > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index ca28ad75fe2b..68af723bc6a1 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -1170,6 +1170,11 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, > > if (!the_lnet.ln_routing) > pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; > + > + /* Ensure only known feature bits have been set. */ > + LASSERT(pbuf->pb_info.pi_features & LNET_PING_FEAT_BITS); > + LASSERT(!(pbuf->pb_info.pi_features & ~LNET_PING_FEAT_BITS)); > + > lnet_ping_target_install_locked(pbuf); > > if (the_lnet.ln_ping_target) { > > > From jsimmons at infradead.org Sun Oct 14 19:36:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:36:51 +0100 (BST) Subject: [lustre-devel] [PATCH 06/24] lustre: lnet: add sanity checks on ping-related constants In-Reply-To: <153895437778.16383.4176394927995685300.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437778.16383.4176394927995685300.stgit@noble> Message-ID: > From: Olaf Weber > > Add sanity checks for LNet ping related data structures and > constants to wirecheck.c, and update the generated code in > lnet_assert_wire_constants(). > > In order for the structures and macros to be visible to > wirecheck.c, which is a userspace program, they were moved > from kernel-only lnet/lib-types.h to lnet/types.h Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25776 > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-types.h | 30 ---------------- > .../lustre/include/uapi/linux/lnet/lnet-types.h | 30 ++++++++++++++++ > drivers/staging/lustre/lnet/lnet/api-ni.c | 38 ++++++++++++++++++++ > 3 files changed, 68 insertions(+), 30 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index f4467a3bbfd1..f28fa5342914 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -378,36 +378,6 @@ struct lnet_ni { > > #define LNET_PROTO_PING_MATCHBITS 0x8000000000000000LL > > -/* > - * NB: value of these features equal to LNET_PROTO_PING_VERSION_x > - * of old LNet, so there shouldn't be any compatibility issue > - */ > -#define LNET_PING_FEAT_INVAL (0) /* no feature */ > -#define LNET_PING_FEAT_BASE BIT(0) /* just a ping */ > -#define LNET_PING_FEAT_NI_STATUS BIT(1) /* return NI status */ > -#define LNET_PING_FEAT_RTE_DISABLED BIT(2) /* Routing enabled */ > -#define LNET_PING_FEAT_MULTI_RAIL BIT(3) /* Multi-Rail aware */ > -#define LNET_PING_FEAT_DISCOVERY BIT(4) /* Supports Discovery */ > - > -/* > - * All ping feature bits fit to hit the wire. > - * In lnet_assert_wire_constants() this is compared against its open-coded > - * value, and in lnet_ping_target_update() it is used to verify that no > - * unknown bits have been set. > - * New feature bits can be added, just be aware that this does change the > - * over-the-wire protocol. > - */ > -#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ > - LNET_PING_FEAT_NI_STATUS | \ > - LNET_PING_FEAT_RTE_DISABLED | \ > - LNET_PING_FEAT_MULTI_RAIL | \ > - LNET_PING_FEAT_DISCOVERY) > - > -#define LNET_PING_INFO_SIZE(NNIDS) \ > - offsetof(struct lnet_ping_info, pi_ni[NNIDS]) > -#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) > -#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) > - > /* > * Descriptor of a ping info buffer: keep a separate indicator of the > * size and a reference count. The type is used both as a source and > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > index 6ee60d07ff84..e0e4fd259795 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > @@ -190,6 +190,31 @@ struct lnet_hdr { > } msg; > } __packed; > > +/* > + * NB: value of these features equal to LNET_PROTO_PING_VERSION_x > + * of old LNet, so there shouldn't be any compatibility issue > + */ > +#define LNET_PING_FEAT_INVAL (0) /* no feature */ > +#define LNET_PING_FEAT_BASE (1 << 0) /* just a ping */ > +#define LNET_PING_FEAT_NI_STATUS (1 << 1) /* return NI status */ > +#define LNET_PING_FEAT_RTE_DISABLED (1 << 2) /* Routing enabled */ > +#define LNET_PING_FEAT_MULTI_RAIL (1 << 3) /* Multi-Rail aware */ > +#define LNET_PING_FEAT_DISCOVERY (1 << 4) /* Supports Discovery */ > + > +/* > + * All ping feature bits fit to hit the wire. > + * In lnet_assert_wire_constants() this is compared against its open-coded > + * value, and in lnet_ping_target_update() it is used to verify that no > + * unknown bits have been set. > + * New feature bits can be added, just be aware that this does change the > + * over-the-wire protocol. > + */ > +#define LNET_PING_FEAT_BITS (LNET_PING_FEAT_BASE | \ > + LNET_PING_FEAT_NI_STATUS | \ > + LNET_PING_FEAT_RTE_DISABLED | \ > + LNET_PING_FEAT_MULTI_RAIL | \ > + LNET_PING_FEAT_DISCOVERY) > + > /* > * A HELLO message contains a magic number and protocol version > * code in the header's dest_nid, the peer's NID in the src_nid, and > @@ -246,6 +271,11 @@ struct lnet_ping_info { > struct lnet_ni_status pi_ni[0]; > } __packed; > > +#define LNET_PING_INFO_SIZE(NNIDS) \ > + offsetof(struct lnet_ping_info, pi_ni[NNIDS]) > +#define LNET_PING_INFO_LONI(PINFO) ((PINFO)->pi_ni[0].ns_nid) > +#define LNET_PING_INFO_SEQNO(PINFO) ((PINFO)->pi_ni[0].ns_status) > + > struct lnet_counters { > __u32 msgs_alloc; > __u32 msgs_max; > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 68af723bc6a1..d81501f4c282 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -313,6 +313,44 @@ static void lnet_assert_wire_constants(void) > BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.incarnation) != 8); > BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.type) != 40); > BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.type) != 4); > + > + /* Checks for struct lnet_ni_status and related constants */ > + BUILD_BUG_ON(LNET_NI_STATUS_INVALID != 0x00000000); > + BUILD_BUG_ON(LNET_NI_STATUS_UP != 0x15aac0de); > + BUILD_BUG_ON(LNET_NI_STATUS_DOWN != 0xdeadface); > + > + /* Checks for struct lnet_ni_status */ > + BUILD_BUG_ON((int)sizeof(struct lnet_ni_status) != 16); > + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_nid) != 0); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_nid) != 8); > + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_status) != 8); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_status) != 4); > + BUILD_BUG_ON((int)offsetof(struct lnet_ni_status, ns_unused) != 12); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ni_status *)0)->ns_unused) != 4); > + > + /* Checks for struct lnet_ping_info and related constants */ > + BUILD_BUG_ON(LNET_PROTO_PING_MAGIC != 0x70696E67); > + BUILD_BUG_ON(LNET_PING_FEAT_INVAL != 0); > + BUILD_BUG_ON(LNET_PING_FEAT_BASE != 1); > + BUILD_BUG_ON(LNET_PING_FEAT_NI_STATUS != 2); > + BUILD_BUG_ON(LNET_PING_FEAT_RTE_DISABLED != 4); > + BUILD_BUG_ON(LNET_PING_FEAT_MULTI_RAIL != 8); > + BUILD_BUG_ON(LNET_PING_FEAT_DISCOVERY != 16); > + BUILD_BUG_ON(LNET_PING_FEAT_BITS != 31); > + > + /* Checks for struct lnet_ping_info */ > + BUILD_BUG_ON((int)sizeof(struct lnet_ping_info) != 16); > + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_magic) != 0); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_magic) != 4); > + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_features) != 4); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_features) > + != 4); > + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_pid) != 8); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_pid) != 4); > + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_nnis) != 12); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_nnis) != 4); > + BUILD_BUG_ON((int)offsetof(struct lnet_ping_info, pi_ni) != 16); > + BUILD_BUG_ON((int)sizeof(((struct lnet_ping_info *)0)->pi_ni) != 0); > } > > static struct lnet_lnd * > > > From jsimmons at infradead.org Sun Oct 14 19:38:42 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:38:42 +0100 (BST) Subject: [lustre-devel] [PATCH 07/24] lustre: lnet: cleanup of lnet_peer_ni_addref/decref_locked() In-Reply-To: <153895437782.16383.10279057472731467540.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437782.16383.10279057472731467540.stgit@noble> Message-ID: > From: Olaf Weber > > Address style issues in lnet_peer_ni_addref_locked() and > lnet_peer_ni_decref_locked(). In the latter routine, replace > a sequence of atomic_dec()/atomic_read() with atomic_dec_and_test(). Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25777 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 2e2b5ed27116..f15f5c9c9a25 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -323,8 +323,7 @@ static inline void > lnet_peer_ni_decref_locked(struct lnet_peer_ni *lp) > { > LASSERT(atomic_read(&lp->lpni_refcount) > 0); > - atomic_dec(&lp->lpni_refcount); > - if (atomic_read(&lp->lpni_refcount) == 0) > + if (atomic_dec_and_test(&lp->lpni_refcount)) > lnet_destroy_peer_ni_locked(lp); > } > > > > From jsimmons at infradead.org Sun Oct 14 19:39:14 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:39:14 +0100 (BST) Subject: [lustre-devel] [PATCH 07/24] lustre: lnet: cleanup of lnet_peer_ni_addref/decref_locked() In-Reply-To: <153895437782.16383.10279057472731467540.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437782.16383.10279057472731467540.stgit@noble> Message-ID: > From: Olaf Weber > > Address style issues in lnet_peer_ni_addref_locked() and > lnet_peer_ni_decref_locked(). In the latter routine, replace > a sequence of atomic_dec()/atomic_read() with atomic_dec_and_test(). Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25777 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 2e2b5ed27116..f15f5c9c9a25 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -323,8 +323,7 @@ static inline void > lnet_peer_ni_decref_locked(struct lnet_peer_ni *lp) > { > LASSERT(atomic_read(&lp->lpni_refcount) > 0); > - atomic_dec(&lp->lpni_refcount); > - if (atomic_read(&lp->lpni_refcount) == 0) > + if (atomic_dec_and_test(&lp->lpni_refcount)) > lnet_destroy_peer_ni_locked(lp); > } > > > > From jsimmons at infradead.org Sun Oct 14 19:55:18 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:55:18 +0100 (BST) Subject: [lustre-devel] [PATCH 08/24] lustre: lnet: rename lnet_add/del_peer_ni_to/from_peer() In-Reply-To: <153895437785.16383.10650578259435328953.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437785.16383.10650578259435328953.stgit@noble> Message-ID: > From: Olaf Weber > > Rename lnet_add_peer_ni_to_peer() to lnet_add_peer_ni(), and > lnet_del_peer_ni_from_peer() to lnet_del_peer_ni(). This brings > the function names closer to the ioctls they implement: > IOCTL_LIBCFS_ADD_PEER_NI and IOCTL_LIBCFS_DEL_PEER_NI. These > names are also a more accturate description their effect: adding > or deleting an lnet_peer_ni to LNet. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25778 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 4 ++-- > drivers/staging/lustre/lnet/lnet/api-ni.c | 10 +++++---- > drivers/staging/lustre/lnet/lnet/peer.c | 22 +++++++++++++++----- > 3 files changed, 23 insertions(+), 13 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index f15f5c9c9a25..69f45a76f1cc 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -682,8 +682,8 @@ struct lnet_peer_net *lnet_peer_get_net_locked(struct lnet_peer *peer, > u32 net_id); > bool lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, > struct lnet_ni *ni); > -int lnet_add_peer_ni_to_peer(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); > -int lnet_del_peer_ni_from_peer(lnet_nid_t key_nid, lnet_nid_t nid); > +int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); > +int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); > int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > bool *mr, > struct lnet_peer_ni_credit_info __user *peer_ni_info, > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index d81501f4c282..d64ae2939abc 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -2848,9 +2848,9 @@ LNetCtl(unsigned int cmd, void *arg) > return -EINVAL; > > mutex_lock(&the_lnet.ln_api_mutex); > - rc = lnet_add_peer_ni_to_peer(cfg->prcfg_prim_nid, > - cfg->prcfg_cfg_nid, > - cfg->prcfg_mr); > + rc = lnet_add_peer_ni(cfg->prcfg_prim_nid, > + cfg->prcfg_cfg_nid, > + cfg->prcfg_mr); > mutex_unlock(&the_lnet.ln_api_mutex); > return rc; > } > @@ -2862,8 +2862,8 @@ LNetCtl(unsigned int cmd, void *arg) > return -EINVAL; > > mutex_lock(&the_lnet.ln_api_mutex); > - rc = lnet_del_peer_ni_from_peer(cfg->prcfg_prim_nid, > - cfg->prcfg_cfg_nid); > + rc = lnet_del_peer_ni(cfg->prcfg_prim_nid, > + cfg->prcfg_cfg_nid); > mutex_unlock(&the_lnet.ln_api_mutex); > return rc; > } > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index ebb84356302f..bbf07008dbb0 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -891,14 +891,16 @@ lnet_peer_ni_add_non_mr(lnet_nid_t nid) > } > > /* > + * Implementation of IOC_LIBCFS_ADD_PEER_NI. > + * > * This API handles the following combinations: > - * Create a primary NI if only the prim_nid is provided > - * Create or add an lpni to a primary NI. Primary NI must've already > - * been created > - * Create a non-MR peer. > + * Create a primary NI if only the prim_nid is provided > + * Create or add an lpni to a primary NI. Primary NI must've already > + * been created > + * Create a non-MR peer. > */ > int > -lnet_add_peer_ni_to_peer(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > +lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > { > /* > * Caller trying to setup an MR like peer hierarchy but > @@ -929,8 +931,16 @@ lnet_add_peer_ni_to_peer(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > return 0; > } > > +/* > + * Implementation of IOC_LIBCFS_DEL_PEER_NI. > + * > + * This API handles the following combinations: > + * Delete a NI from a peer if both prim_nid and nid are provided. > + * Delete a peer if only prim_nid is provided. > + * Delete a peer if its primary nid is provided. > + */ > int > -lnet_del_peer_ni_from_peer(lnet_nid_t prim_nid, lnet_nid_t nid) > +lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) > { > lnet_nid_t local_nid; > struct lnet_peer *peer; > > > From jsimmons at infradead.org Sun Oct 14 19:58:21 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 20:58:21 +0100 (BST) Subject: [lustre-devel] [PATCH 09/24] lustre: lnet: refactor lnet_del_peer_ni() In-Reply-To: <153895437789.16383.3567353433359493775.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437789.16383.3567353433359493775.stgit@noble> Message-ID: > From: Olaf Weber > > Refactor lnet_del_peer_ni(). In particular break out the code > that removes an lnet_peer_ni from an lnet_peer and put it into > a separate function, lnet_peer_del_nid(). Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25779 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > drivers/staging/lustre/lnet/lnet/peer.c | 96 +++++++++++++++++++++++-------- > 1 file changed, 71 insertions(+), 25 deletions(-) > > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index bbf07008dbb0..30a2486712e4 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -254,7 +254,7 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) > * > * The last reference may be lost in a place where the > * lnet_net_lock locks only a single cpt, and that cpt may not > - * be lpni->lpni_cpt. So the zombie list of this peer_table > + * be lpni->lpni_cpt. So the zombie list of lnet_peer_table > * has its own lock. > */ > spin_lock(&ptable->pt_zombie_lock); > @@ -340,6 +340,61 @@ lnet_peer_del_locked(struct lnet_peer *peer) > return rc2; > } > > +static int > +lnet_peer_del(struct lnet_peer *peer) > +{ > + lnet_net_lock(LNET_LOCK_EX); > + lnet_peer_del_locked(peer); > + lnet_net_unlock(LNET_LOCK_EX); > + > + return 0; > +} > + > +/* > + * Delete a NID from a peer. > + * Implements a few sanity checks. > + * Call with ln_api_mutex held. > + */ > +static int > +lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) > +{ > + struct lnet_peer *lp2; > + struct lnet_peer_ni *lpni; > + > + lpni = lnet_find_peer_ni_locked(nid); > + if (!lpni) { > + CERROR("Cannot remove unknown nid %s from peer %s\n", > + libcfs_nid2str(nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -ENOENT; > + } > + lnet_peer_ni_decref_locked(lpni); > + lp2 = lpni->lpni_peer_net->lpn_peer; > + if (lp2 != lp) { > + CERROR("Nid %s is attached to peer %s, not peer %s\n", > + libcfs_nid2str(nid), > + libcfs_nid2str(lp2->lp_primary_nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -EINVAL; > + } > + > + /* > + * This function only allows deletion of the primary NID if it > + * is the only NID. > + */ > + if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { > + CERROR("Cannot delete primary NID %s from multi-NID peer\n", > + libcfs_nid2str(nid)); > + return -EINVAL; > + } > + > + lnet_net_lock(LNET_LOCK_EX); > + lnet_peer_ni_del_locked(lpni); > + lnet_net_unlock(LNET_LOCK_EX); > + > + return 0; > +} > + > static void > lnet_peer_table_cleanup_locked(struct lnet_net *net, > struct lnet_peer_table *ptable) > @@ -938,45 +993,36 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > * Delete a NI from a peer if both prim_nid and nid are provided. > * Delete a peer if only prim_nid is provided. > * Delete a peer if its primary nid is provided. > + * > + * The caller must hold ln_api_mutex. This prevents the peer from > + * being modified/deleted by a different thread. > */ > int > lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) > { > - lnet_nid_t local_nid; > - struct lnet_peer *peer; > + struct lnet_peer *lp; > struct lnet_peer_ni *lpni; > - int rc; > > if (prim_nid == LNET_NID_ANY) > return -EINVAL; > > - local_nid = (nid != LNET_NID_ANY) ? nid : prim_nid; > - > - lpni = lnet_find_peer_ni_locked(local_nid); > + lpni = lnet_find_peer_ni_locked(prim_nid); > if (!lpni) > - return -EINVAL; > + return -ENOENT; > lnet_peer_ni_decref_locked(lpni); > + lp = lpni->lpni_peer_net->lpn_peer; > > - peer = lpni->lpni_peer_net->lpn_peer; > - LASSERT(peer); > - > - if (peer->lp_primary_nid == lpni->lpni_nid) { > - /* > - * deleting the primary ni is equivalent to deleting the > - * entire peer > - */ > - lnet_net_lock(LNET_LOCK_EX); > - rc = lnet_peer_del_locked(peer); > - lnet_net_unlock(LNET_LOCK_EX); > - > - return rc; > + if (prim_nid != lp->lp_primary_nid) { > + CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", > + libcfs_nid2str(prim_nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -ENODEV; > } > > - lnet_net_lock(LNET_LOCK_EX); > - rc = lnet_peer_ni_del_locked(lpni); > - lnet_net_unlock(LNET_LOCK_EX); > + if (nid == LNET_NID_ANY || nid == lp->lp_primary_nid) > + return lnet_peer_del(lp); > > - return rc; > + return lnet_peer_del_nid(lp, nid); > } > > void > > > From jsimmons at infradead.org Sun Oct 14 20:02:56 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 21:02:56 +0100 (BST) Subject: [lustre-devel] [PATCH 10/24] lustre: lnet: refactor lnet_add_peer_ni() In-Reply-To: <153895437792.16383.4508869255214195437.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437792.16383.4508869255214195437.stgit@noble> Message-ID: > From: Olaf Weber > > Refactor lnet_add_peer_ni() and the functions called by it. In > particular, lnet_peer_add_nid() adds an lnet_peer_ni to an > existing lnet_peer, lnet_peer_add() adds a new lnet_peer. > > lnet_find_or_create_peer_locked() is removed. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25780 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 1 > drivers/staging/lustre/lnet/lnet/lib-move.c | 13 + > drivers/staging/lustre/lnet/lnet/peer.c | 230 +++++++------------- > 3 files changed, 92 insertions(+), 152 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 69f45a76f1cc..fc748ffa251d 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -668,7 +668,6 @@ u32 lnet_get_dlc_seq_locked(void); > struct lnet_peer_ni *lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > struct lnet_peer_net *peer_net, > struct lnet_peer_ni *prev); > -struct lnet_peer *lnet_find_or_create_peer_locked(lnet_nid_t dst_nid, int cpt); > struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index e8c021622f91..59ae8d0649e5 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -1262,11 +1262,18 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > return -ESHUTDOWN; > } > > - peer = lnet_find_or_create_peer_locked(dst_nid, cpt); > - if (IS_ERR(peer)) { > + /* > + * lnet_nid2peerni_locked() is the path that will find an > + * existing peer_ni, or create one and mark it as having been > + * created due to network traffic. > + */ > + lpni = lnet_nid2peerni_locked(dst_nid, cpt); > + if (IS_ERR(lpni)) { > lnet_net_unlock(cpt); > - return PTR_ERR(peer); > + return PTR_ERR(lpni); > } > + peer = lpni->lpni_peer_net->lpn_peer; > + lnet_peer_ni_decref_locked(lpni); > > /* If peer is not healthy then can not send anything to it */ > if (!lnet_is_peer_healthy_locked(peer)) { > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 30a2486712e4..6b7ca5c361b8 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -541,25 +541,6 @@ lnet_find_peer_ni_locked(lnet_nid_t nid) > return lpni; > } > > -struct lnet_peer * > -lnet_find_or_create_peer_locked(lnet_nid_t dst_nid, int cpt) > -{ > - struct lnet_peer_ni *lpni; > - struct lnet_peer *lp; > - > - lpni = lnet_find_peer_ni_locked(dst_nid); > - if (!lpni) { > - lpni = lnet_nid2peerni_locked(dst_nid, cpt); > - if (IS_ERR(lpni)) > - return ERR_CAST(lpni); > - } > - > - lp = lpni->lpni_peer_net->lpn_peer; > - lnet_peer_ni_decref_locked(lpni); > - > - return lp; > -} > - > struct lnet_peer_ni * > lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, > struct lnet_peer **lp) > @@ -774,131 +755,95 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni > return -ENOMEM; > } > > +/* > + * Create a new peer, with nid as its primary nid. > + * > + * It is not an error if the peer already exists, provided that the > + * given nid is the primary NID. > + * > + * Call with the lnet_api_mutex held. > + */ > static int > -lnet_add_prim_lpni(lnet_nid_t nid) > +lnet_peer_add(lnet_nid_t nid, bool mr) > { > - int rc; > - struct lnet_peer *peer; > + struct lnet_peer *lp; > struct lnet_peer_ni *lpni; > > LASSERT(nid != LNET_NID_ANY); > > /* > - * lookup the NID and its peer > - * if the peer doesn't exist, create it. > - * if this is a non-MR peer then change its state to MR and exit. > - * if this is an MR peer and it's a primary NI: NO-OP. > - * if this is an MR peer and it's not a primary NI. Operation not > - * allowed. > - * > - * The adding and deleting of peer nis is being serialized through > - * the api_mutex. So we can look up peers with the mutex locked > - * safely. Only when we need to change the ptable, do we need to > - * exclusively lock the lnet_net_lock() > + * No need for the lnet_net_lock here, because the > + * lnet_api_mutex is held. > */ > lpni = lnet_find_peer_ni_locked(nid); > if (!lpni) { > - rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); > + int rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); > if (rc != 0) > return rc; > lpni = lnet_find_peer_ni_locked(nid); > + LASSERT(lpni); > } > - > - LASSERT(lpni); > - > + lp = lpni->lpni_peer_net->lpn_peer; > lnet_peer_ni_decref_locked(lpni); > > - peer = lpni->lpni_peer_net->lpn_peer; > - > - /* > - * If we found a lpni with the same nid as the NID we're trying to > - * create, then we're trying to create an already existing lpni > - * that belongs to a different peer > - */ > - if (peer->lp_primary_nid != nid) > + /* A found peer must have this primary NID */ > + if (lp->lp_primary_nid != nid) > return -EEXIST; > > /* > - * if we found an lpni that is not a multi-rail, which could occur > + * If we found an lpni that is not a multi-rail, which could occur > * if lpni is already created as a non-mr lpni or we just created > * it, then make sure you indicate that this lpni is a primary mr > * capable peer. > * > * TODO: update flags if necessary > */ > - if (!peer->lp_multi_rail && peer->lp_primary_nid == nid) > - peer->lp_multi_rail = true; > + if (mr && !lp->lp_multi_rail) { > + lp->lp_multi_rail = true; > + } else if (!mr && lp->lp_multi_rail) { > + /* The mr state is sticky. */ > + CDEBUG(D_NET, "Cannot clear multi-flag from peer %s\n", > + libcfs_nid2str(nid)); > + } > > - return rc; > + return 0; > } > > static int > -lnet_add_peer_ni_to_prim_lpni(lnet_nid_t prim_nid, lnet_nid_t nid) > +lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > { > - struct lnet_peer *peer, *primary_peer; > - struct lnet_peer_ni *lpni = NULL, *klpni = NULL; > - > - LASSERT(prim_nid != LNET_NID_ANY && nid != LNET_NID_ANY); > + struct lnet_peer_ni *lpni; > > - /* > - * key nid must be created by this point. If not then this > - * operation is not permitted > - */ > - klpni = lnet_find_peer_ni_locked(prim_nid); > - if (!klpni) > - return -ENOENT; > + LASSERT(lp); > + LASSERT(nid != LNET_NID_ANY); > > - lnet_peer_ni_decref_locked(klpni); > + if (!mr && !lp->lp_multi_rail) { > + CERROR("Cannot add nid %s to non-multi-rail peer %s\n", > + libcfs_nid2str(nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -EPERM; > + } > > - primary_peer = klpni->lpni_peer_net->lpn_peer; > + if (!lp->lp_multi_rail) > + lp->lp_multi_rail = true; > > lpni = lnet_find_peer_ni_locked(nid); > - if (lpni) { > - lnet_peer_ni_decref_locked(lpni); > - > - peer = lpni->lpni_peer_net->lpn_peer; > - /* > - * lpni already exists in the system but it belongs to > - * a different peer. We can't re-added it > - */ > - if (peer->lp_primary_nid != prim_nid && peer->lp_multi_rail) { > - CERROR("Cannot add NID %s owned by peer %s to peer %s\n", > - libcfs_nid2str(lpni->lpni_nid), > - libcfs_nid2str(peer->lp_primary_nid), > - libcfs_nid2str(prim_nid)); > - return -EEXIST; > - } else if (peer->lp_primary_nid == prim_nid) { > - /* > - * found a peer_ni that is already part of the > - * peer. This is a no-op operation. > - */ > - return 0; > - } > - > - /* > - * TODO: else if (peer->lp_primary_nid != prim_nid && > - * !peer->lp_multi_rail) > - * peer is not an MR peer and it will be moved in the next > - * step to klpni, so update its flags accordingly. > - * lnet_move_peer_ni() > - */ > - > - /* > - * TODO: call lnet_update_peer() from here to update the > - * flags. This is the case when the lpni you're trying to > - * add is already part of the peer. This could've been > - * added by the DD previously, so go ahead and do any > - * updates to the state if necessary > - */ > + if (!lpni) > + return lnet_peer_setup_hierarchy(lp, NULL, nid); > > + if (lpni->lpni_peer_net->lpn_peer != lp) { > + struct lnet_peer *lp2 = lpni->lpni_peer_net->lpn_peer; > + CERROR("Cannot add NID %s owned by peer %s to peer %s\n", > + libcfs_nid2str(lpni->lpni_nid), > + libcfs_nid2str(lp2->lp_primary_nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -EEXIST; > } > > - /* > - * When we get here we either have found an existing lpni, which > - * we can switch to the new peer. Or we need to create one and > - * add it to the new peer > - */ > - return lnet_peer_setup_hierarchy(primary_peer, lpni, nid); > + CDEBUG(D_NET, "NID %s is already owned by peer %s\n", > + libcfs_nid2str(lpni->lpni_nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return 0; > } > > /* > @@ -929,61 +874,50 @@ lnet_peer_ni_traffic_add(lnet_nid_t nid) > return rc; > } > > -static int > -lnet_peer_ni_add_non_mr(lnet_nid_t nid) > -{ > - struct lnet_peer_ni *lpni; > - > - lpni = lnet_find_peer_ni_locked(nid); > - if (lpni) { > - CERROR("Cannot add %s as non-mr when it already exists\n", > - libcfs_nid2str(nid)); > - lnet_peer_ni_decref_locked(lpni); > - return -EEXIST; > - } > - > - return lnet_peer_setup_hierarchy(NULL, NULL, nid); > -} > - > /* > * Implementation of IOC_LIBCFS_ADD_PEER_NI. > * > * This API handles the following combinations: > - * Create a primary NI if only the prim_nid is provided > - * Create or add an lpni to a primary NI. Primary NI must've already > - * been created > - * Create a non-MR peer. > + * Create a peer with its primary NI if only the prim_nid is provided > + * Add a NID to a peer identified by the prim_nid. The peer identified > + * by the prim_nid must already exist. > + * The peer being created may be non-MR. > + * > + * The caller must hold ln_api_mutex. This prevents the peer from > + * being created/modified/deleted by a different thread. > */ > int > lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > { > + struct lnet_peer *lp = NULL; > + struct lnet_peer_ni *lpni; > + > + /* The prim_nid must always be specified */ > + if (prim_nid == LNET_NID_ANY) > + return -EINVAL; > + > /* > - * Caller trying to setup an MR like peer hierarchy but > - * specifying it to be non-MR. This is not allowed. > + * If nid isn't specified, we must create a new peer with > + * prim_nid as its primary nid. > */ > - if (prim_nid != LNET_NID_ANY && > - nid != LNET_NID_ANY && !mr) > - return -EPERM; > - > - /* Add the primary NID of a peer */ > - if (prim_nid != LNET_NID_ANY && > - nid == LNET_NID_ANY && mr) > - return lnet_add_prim_lpni(prim_nid); > + if (nid == LNET_NID_ANY) > + return lnet_peer_add(prim_nid, mr); > > - /* Add a NID to an existing peer */ > - if (prim_nid != LNET_NID_ANY && > - nid != LNET_NID_ANY && mr) > - return lnet_add_peer_ni_to_prim_lpni(prim_nid, nid); > + /* Look up the prim_nid, which must exist. */ > + lpni = lnet_find_peer_ni_locked(prim_nid); > + if (!lpni) > + return -ENOENT; > + lnet_peer_ni_decref_locked(lpni); > + lp = lpni->lpni_peer_net->lpn_peer; > > - /* Add a non-MR peer NI */ > - if (((prim_nid != LNET_NID_ANY && > - nid == LNET_NID_ANY) || > - (prim_nid == LNET_NID_ANY && > - nid != LNET_NID_ANY)) && !mr) > - return lnet_peer_ni_add_non_mr(prim_nid != LNET_NID_ANY ? > - prim_nid : nid); > + if (lp->lp_primary_nid != prim_nid) { > + CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", > + libcfs_nid2str(prim_nid), > + libcfs_nid2str(lp->lp_primary_nid)); > + return -ENODEV; > + } > > - return 0; > + return lnet_peer_add_nid(lp, nid, mr); > } > > /* > > > From jsimmons at infradead.org Sun Oct 14 20:11:20 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 21:11:20 +0100 (BST) Subject: [lustre-devel] [PATCH 11/24] lustre: lnet: introduce LNET_PEER_MULTI_RAIL flag bit In-Reply-To: <153895437796.16383.5518559009775786439.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437796.16383.5518559009775786439.stgit@noble> Message-ID: > From: Olaf Weber > > Add lp_state as a flag word to lnet_peer, and add lp_lock > to protect it. This lock needs to be taken whenever the > field is updated, because setting or clearing a bit is > a read-modify-write cycle. > > The lp_multi_rail is removed, its function is replaced by > the new LNET_PEER_MULTI_RAIL flag bit. > > The helper lnet_peer_is_multi_rail() tests the bit. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25781 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 6 +++++ > .../staging/lustre/include/linux/lnet/lib-types.h | 11 ++++++++-- > drivers/staging/lustre/lnet/lnet/lib-move.c | 9 +++++--- > drivers/staging/lustre/lnet/lnet/peer.c | 22 +++++++++++++------- > 4 files changed, 34 insertions(+), 14 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index fc748ffa251d..75b47628c70e 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -757,4 +757,10 @@ lnet_peer_set_alive(struct lnet_peer_ni *lp) > lnet_notify_locked(lp, 0, 1, lp->lpni_last_alive); > } > > +static inline bool > +lnet_peer_is_multi_rail(struct lnet_peer *lp) > +{ > + return lp->lp_state & LNET_PEER_MULTI_RAIL; > +} > + > #endif > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index f28fa5342914..602978a1c86e 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -467,6 +467,8 @@ struct lnet_peer_ni { > atomic_t lpni_refcount; > /* CPT this peer attached on */ > int lpni_cpt; > + /* state flags -- protected by lpni_lock */ > + unsigned int lpni_state; > /* # refs from lnet_route::lr_gateway */ > int lpni_rtr_refcount; > /* sequence number used to round robin over peer nis within a net */ > @@ -497,10 +499,15 @@ struct lnet_peer { > /* primary NID of the peer */ > lnet_nid_t lp_primary_nid; > > - /* peer is Multi-Rail enabled peer */ > - bool lp_multi_rail; > + /* lock protecting peer state flags */ > + spinlock_t lp_lock; > + > + /* peer state flags */ > + unsigned int lp_state; > }; > > +#define LNET_PEER_MULTI_RAIL BIT(0) > + > struct lnet_peer_net { > /* chain on peer block */ > struct list_head lpn_on_peer_list; > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 59ae8d0649e5..0d0ad30bb164 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -1281,7 +1281,8 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > return -EHOSTUNREACH; > } > > - if (!peer->lp_multi_rail && lnet_get_num_peer_nis(peer) > 1) { > + if (!lnet_peer_is_multi_rail(peer) && > + lnet_get_num_peer_nis(peer) > 1) { > lnet_net_unlock(cpt); > CERROR("peer %s is declared to be non MR capable, yet configured with more than one NID\n", > libcfs_nid2str(dst_nid)); > @@ -1307,7 +1308,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > > if (msg->msg_type == LNET_MSG_REPLY || > msg->msg_type == LNET_MSG_ACK || > - !peer->lp_multi_rail || > + !lnet_peer_is_multi_rail(peer) || > best_ni) { > /* > * for replies we want to respond on the same peer_ni we > @@ -1354,7 +1355,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > * then use the best_gw found to send > * the message to > */ > - if (!peer->lp_multi_rail) > + if (!lnet_peer_is_multi_rail(peer)) > best_lpni = best_gw; > else > best_lpni = NULL; > @@ -1375,7 +1376,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > * if the peer is not MR capable, then we should always send to it > * using the first NI in the NET we determined. > */ > - if (!peer->lp_multi_rail) { > + if (!lnet_peer_is_multi_rail(peer)) { > if (!best_lpni) { > lnet_net_unlock(cpt); > CERROR("no route to %s\n", > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 6b7ca5c361b8..cc2b926b76e4 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -182,6 +182,7 @@ lnet_peer_alloc(lnet_nid_t nid) > > INIT_LIST_HEAD(&lp->lp_on_lnet_peer_list); > INIT_LIST_HEAD(&lp->lp_peer_nets); > + spin_lock_init(&lp->lp_lock); > lp->lp_primary_nid = nid; > > /* TODO: update flags */ > @@ -798,13 +799,15 @@ lnet_peer_add(lnet_nid_t nid, bool mr) > * > * TODO: update flags if necessary > */ > - if (mr && !lp->lp_multi_rail) { > - lp->lp_multi_rail = true; > - } else if (!mr && lp->lp_multi_rail) { > + spin_lock(&lp->lp_lock); > + if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { > /* The mr state is sticky. */ > - CDEBUG(D_NET, "Cannot clear multi-flag from peer %s\n", > + CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", > libcfs_nid2str(nid)); > } > + spin_unlock(&lp->lp_lock); > > return 0; > } > @@ -817,15 +820,18 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > LASSERT(lp); > LASSERT(nid != LNET_NID_ANY); > > - if (!mr && !lp->lp_multi_rail) { > + spin_lock(&lp->lp_lock); > + if (!mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + spin_unlock(&lp->lp_lock); > CERROR("Cannot add nid %s to non-multi-rail peer %s\n", > libcfs_nid2str(nid), > libcfs_nid2str(lp->lp_primary_nid)); > return -EPERM; > } > > - if (!lp->lp_multi_rail) > - lp->lp_multi_rail = true; > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + spin_unlock(&lp->lp_lock); > > lpni = lnet_find_peer_ni_locked(nid); > if (!lpni) > @@ -1183,7 +1189,7 @@ int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > return -ENOENT; > > *primary_nid = lp->lp_primary_nid; > - *mr = lp->lp_multi_rail; > + *mr = lnet_peer_is_multi_rail(lp); > *nid = lpni->lpni_nid; > snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, "NA"); > if (lnet_isrouter(lpni) || > > > From jsimmons at infradead.org Sun Oct 14 20:20:15 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 21:20:15 +0100 (BST) Subject: [lustre-devel] [PATCH 12/24] lustre: lnet: preferred NIs for non-Multi-Rail peers In-Reply-To: <153895437800.16383.15417431282816541221.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437800.16383.15417431282816541221.stgit@noble> Message-ID: > From: Olaf Weber > > When a node sends a message to a peer NI, there may be > a preferred local NI that should be the source of the > message. This is in particular the case for non-Multi- > Rail (NMR) peers, as an NMR peer depends in some cases > on the source address of a message to correctly identify > its origin. (This as opposed to using a UUID provided by > a higher protocol layer.) > > Implement this by keeping an array of preferred local > NIDs in the lnet_peer_ni structure. The case where only > a single NID needs to be stored is optimized so that this > can be done without needing to allocate any memory. > > A flag in the lnet_peer_ni, LNET_PEER_NI_NON_MR_PREF, > indicates that the preferred NI was automatically added > for an NMR peer. Note that a peer which has not been > explicitly configured as Multi-Rail will be treated as > non-Multi-Rail until proven otherwise. These automatic > preferences will be cleared if the peer is changed to > Multi-Rail. > > - lnet_peer_ni_set_non_mr_pref_nid() > set NMR preferred NI for peer_ni > - lnet_peer_ni_clr_non_mr_pref_nid() > clear NMR preferred NI for peer_ni > - lnet_peer_clr_non_mr_pref_nids() > clear NMR preferred NIs for all peer_ni > > - lnet_peer_add_pref_nid() > add a preferred NID > - lnet_peer_del_pref_nid() > delete a preferred NID Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25782 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 7 - > .../staging/lustre/include/linux/lnet/lib-types.h | 10 + > drivers/staging/lustre/lnet/lnet/lib-move.c | 49 +++- > drivers/staging/lustre/lnet/lnet/peer.c | 257 +++++++++++++++++++- > 4 files changed, 285 insertions(+), 38 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 75b47628c70e..2864bd8a403b 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -668,7 +668,8 @@ u32 lnet_get_dlc_seq_locked(void); > struct lnet_peer_ni *lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > struct lnet_peer_net *peer_net, > struct lnet_peer_ni *prev); > -struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, int cpt); > +struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, > + int cpt); > struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); > void lnet_peer_net_added(struct lnet_net *net); > @@ -679,8 +680,8 @@ int lnet_peer_tables_create(void); > void lnet_debug_peer(lnet_nid_t nid); > struct lnet_peer_net *lnet_peer_get_net_locked(struct lnet_peer *peer, > u32 net_id); > -bool lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, > - struct lnet_ni *ni); > +bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); > +int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); > int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); > int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); > int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 602978a1c86e..eff2aed5e5c1 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -481,14 +481,20 @@ struct lnet_peer_ni { > unsigned int lpni_ping_feats; > /* routers on this peer */ > struct list_head lpni_routes; > - /* array of preferred local nids */ > - lnet_nid_t *lpni_pref_nids; > + /* preferred local nids: if only one, use lpni_pref.nid */ > + union lpni_pref { > + lnet_nid_t nid; > + lnet_nid_t *nids; > + } lpni_pref; > /* number of preferred NIDs in lnpi_pref_nids */ > u32 lpni_pref_nnids; > /* router checker state */ > struct lnet_rc_data *lpni_rcd; > }; > > +/* Preferred path added due to traffic on non-MR peer_ni */ > +#define LNET_PEER_NI_NON_MR_PREF BIT(0) > + > struct lnet_peer { > /* chain on global peer list */ > struct list_head lp_on_lnet_peer_list; > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 0d0ad30bb164..99d8b22356bb 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -1267,7 +1267,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > * existing peer_ni, or create one and mark it as having been > * created due to network traffic. > */ > - lpni = lnet_nid2peerni_locked(dst_nid, cpt); > + lpni = lnet_nid2peerni_locked(dst_nid, LNET_NID_ANY, cpt); > if (IS_ERR(lpni)) { > lnet_net_unlock(cpt); > return PTR_ERR(lpni); > @@ -1281,14 +1281,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > return -EHOSTUNREACH; > } > > - if (!lnet_peer_is_multi_rail(peer) && > - lnet_get_num_peer_nis(peer) > 1) { > - lnet_net_unlock(cpt); > - CERROR("peer %s is declared to be non MR capable, yet configured with more than one NID\n", > - libcfs_nid2str(dst_nid)); > - return -EINVAL; > - } > - > /* > * STEP 1: first jab at determining best_ni > * if src_nid is explicitly specified, then best_ni is already > @@ -1373,8 +1365,14 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > } > > /* > - * if the peer is not MR capable, then we should always send to it > - * using the first NI in the NET we determined. > + * We must use a consistent source address when sending to a > + * non-MR peer. However, a non-MR peer can have multiple NIDs > + * on multiple networks, and we may even need to talk to this > + * peer on multiple networks -- certain types of > + * load-balancing configuration do this. > + * > + * So we need to pick the NI the peer prefers for this > + * particular network. > */ > if (!lnet_peer_is_multi_rail(peer)) { > if (!best_lpni) { > @@ -1384,10 +1382,26 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > return -EHOSTUNREACH; > } > > - /* best ni could be set because src_nid was provided */ > + /* best ni is already set if src_nid was provided */ > + if (!best_ni) { > + /* Get the target peer_ni */ > + peer_net = lnet_peer_get_net_locked( > + peer, LNET_NIDNET(best_lpni->lpni_nid)); > + list_for_each_entry(lpni, &peer_net->lpn_peer_nis, > + lpni_on_peer_net_list) { > + if (lpni->lpni_pref_nnids == 0) > + continue; > + LASSERT(lpni->lpni_pref_nnids == 1); > + best_ni = lnet_nid2ni_locked( > + lpni->lpni_pref.nid, cpt); > + break; > + } > + } > + /* if best_ni is still not set just pick one */ > if (!best_ni) { > best_ni = lnet_net2ni_locked( > best_lpni->lpni_net->net_id, cpt); > + /* If there is no best_ni we don't have a route */ > if (!best_ni) { > lnet_net_unlock(cpt); > CERROR("no path to %s from net %s\n", > @@ -1395,7 +1409,13 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > libcfs_net2str(best_lpni->lpni_net->net_id)); > return -EHOSTUNREACH; > } > + lpni = list_entry(peer_net->lpn_peer_nis.next, > + struct lnet_peer_ni, > + lpni_on_peer_net_list); > } > + /* Set preferred NI if necessary. */ > + if (lpni->lpni_pref_nnids == 0) > + lnet_peer_ni_set_non_mr_pref_nid(lpni, best_ni->ni_nid); > } > > /* > @@ -1593,7 +1613,8 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > */ > if (!lnet_is_peer_ni_healthy_locked(lpni)) > continue; > - ni_is_pref = lnet_peer_is_ni_pref_locked(lpni, best_ni); > + ni_is_pref = lnet_peer_is_pref_nid_locked(lpni, > + best_ni->ni_nid); > > /* if this is a preferred peer use it */ > if (!preferred && ni_is_pref) { > @@ -2380,7 +2401,7 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid, > } > > lnet_net_lock(cpt); > - lpni = lnet_nid2peerni_locked(from_nid, cpt); > + lpni = lnet_nid2peerni_locked(from_nid, ni->ni_nid, cpt); > if (IS_ERR(lpni)) { > lnet_net_unlock(cpt); > CERROR("%s, src %s: Dropping %s (error %ld looking up sender)\n", > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index cc2b926b76e4..44a2bf641260 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -617,18 +617,233 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > return lpni; > } > > +/* > + * Test whether a ni is a preferred ni for this peer_ni, e.g, whether > + * this is a preferred point-to-point path. Call with lnet_net_lock in > + * shared mmode. > + */ > bool > -lnet_peer_is_ni_pref_locked(struct lnet_peer_ni *lpni, struct lnet_ni *ni) > +lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid) > { > int i; > > + if (lpni->lpni_pref_nnids == 0) > + return false; > + if (lpni->lpni_pref_nnids == 1) > + return lpni->lpni_pref.nid == nid; > for (i = 0; i < lpni->lpni_pref_nnids; i++) { > - if (lpni->lpni_pref_nids[i] == ni->ni_nid) > + if (lpni->lpni_pref.nids[i] == nid) > return true; > } > return false; > } > > +/* > + * Set a single ni as preferred, provided no preferred ni is already > + * defined. Only to be used for non-multi-rail peer_ni. > + */ > +int > +lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) > +{ > + int rc = 0; > + > + spin_lock(&lpni->lpni_lock); > + if (nid == LNET_NID_ANY) { > + rc = -EINVAL; > + } else if (lpni->lpni_pref_nnids > 0) { > + rc = -EPERM; > + } else if (lpni->lpni_pref_nnids == 0) { > + lpni->lpni_pref.nid = nid; > + lpni->lpni_pref_nnids = 1; > + lpni->lpni_state |= LNET_PEER_NI_NON_MR_PREF; > + } > + spin_unlock(&lpni->lpni_lock); > + > + CDEBUG(D_NET, "peer %s nid %s: %d\n", > + libcfs_nid2str(lpni->lpni_nid), libcfs_nid2str(nid), rc); > + return rc; > +} > + > +/* > + * Clear the preferred NID from a non-multi-rail peer_ni, provided > + * this preference was set by lnet_peer_ni_set_non_mr_pref_nid(). > + */ > +int > +lnet_peer_ni_clr_non_mr_pref_nid(struct lnet_peer_ni *lpni) > +{ > + int rc = 0; > + > + spin_lock(&lpni->lpni_lock); > + if (lpni->lpni_state & LNET_PEER_NI_NON_MR_PREF) { > + lpni->lpni_pref_nnids = 0; > + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; > + } else if (lpni->lpni_pref_nnids == 0) { > + rc = -ENOENT; > + } else { > + rc = -EPERM; > + } > + spin_unlock(&lpni->lpni_lock); > + > + CDEBUG(D_NET, "peer %s: %d\n", > + libcfs_nid2str(lpni->lpni_nid), rc); > + return rc; > +} > + > +/* > + * Clear the preferred NIDs from a non-multi-rail peer. > + */ > +void > +lnet_peer_clr_non_mr_pref_nids(struct lnet_peer *lp) > +{ > + struct lnet_peer_ni *lpni = NULL; > + > + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) > + lnet_peer_ni_clr_non_mr_pref_nid(lpni); > +} > + > +int > +lnet_peer_add_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) > +{ > + lnet_nid_t *nids = NULL; > + lnet_nid_t *oldnids = NULL; > + struct lnet_peer *lp = lpni->lpni_peer_net->lpn_peer; > + int size; > + int i; > + int rc = 0; > + > + if (nid == LNET_NID_ANY) { > + rc = -EINVAL; > + goto out; > + } > + > + if (lpni->lpni_pref_nnids == 1 && lpni->lpni_pref.nid == nid) { > + rc = -EEXIST; > + goto out; > + } > + > + /* A non-MR node may have only one preferred NI per peer_ni */ > + if (lpni->lpni_pref_nnids > 0) { > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + rc = -EPERM; > + goto out; > + } > + } > + > + if (lpni->lpni_pref_nnids != 0) { > + size = sizeof(*nids) * (lpni->lpni_pref_nnids + 1); > + nids = kzalloc_cpt(size, GFP_KERNEL, lpni->lpni_cpt); > + if (!nids) { > + rc = -ENOMEM; > + goto out; > + } > + for (i = 0; i < lpni->lpni_pref_nnids; i++) { > + if (lpni->lpni_pref.nids[i] == nid) { > + kfree(nids); > + rc = -EEXIST; > + goto out; > + } > + nids[i] = lpni->lpni_pref.nids[i]; > + } > + nids[i] = nid; > + } > + > + lnet_net_lock(LNET_LOCK_EX); > + spin_lock(&lpni->lpni_lock); > + if (lpni->lpni_pref_nnids == 0) { > + lpni->lpni_pref.nid = nid; > + } else { > + oldnids = lpni->lpni_pref.nids; > + lpni->lpni_pref.nids = nids; > + } > + lpni->lpni_pref_nnids++; > + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; > + spin_unlock(&lpni->lpni_lock); > + lnet_net_unlock(LNET_LOCK_EX); > + > + kfree(oldnids); > +out: > + if (rc == -EEXIST && (lpni->lpni_state & LNET_PEER_NI_NON_MR_PREF)) { > + spin_lock(&lpni->lpni_lock); > + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; > + spin_unlock(&lpni->lpni_lock); > + } > + CDEBUG(D_NET, "peer %s nid %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), rc); > + return rc; > +} > + > +int > +lnet_peer_del_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid) > +{ > + lnet_nid_t *nids = NULL; > + lnet_nid_t *oldnids = NULL; > + struct lnet_peer *lp = lpni->lpni_peer_net->lpn_peer; > + int size; > + int i, j; > + int rc = 0; > + > + if (lpni->lpni_pref_nnids == 0) { > + rc = -ENOENT; > + goto out; > + } > + > + if (lpni->lpni_pref_nnids == 1) { > + if (lpni->lpni_pref.nid != nid) { > + rc = -ENOENT; > + goto out; > + } > + } else if (lpni->lpni_pref_nnids == 2) { > + if (lpni->lpni_pref.nids[0] != nid && > + lpni->lpni_pref.nids[1] != nid) { > + rc = -ENOENT; > + goto out; > + } > + } else { > + size = sizeof(*nids) * (lpni->lpni_pref_nnids - 1); > + nids = kzalloc_cpt(size, GFP_KERNEL, lpni->lpni_cpt); > + if (!nids) { > + rc = -ENOMEM; > + goto out; > + } > + for (i = 0, j = 0; i < lpni->lpni_pref_nnids; i++) { > + if (lpni->lpni_pref.nids[i] != nid) > + continue; > + nids[j++] = lpni->lpni_pref.nids[i]; > + } > + /* Check if we actually removed a nid. */ > + if (j == lpni->lpni_pref_nnids) { > + kfree(nids); > + rc = -ENOENT; > + goto out; > + } > + } > + > + lnet_net_lock(LNET_LOCK_EX); > + spin_lock(&lpni->lpni_lock); > + if (lpni->lpni_pref_nnids == 1) { > + lpni->lpni_pref.nid = LNET_NID_ANY; > + } else if (lpni->lpni_pref_nnids == 2) { > + oldnids = lpni->lpni_pref.nids; > + if (oldnids[0] == nid) > + lpni->lpni_pref.nid = oldnids[1]; > + else > + lpni->lpni_pref.nid = oldnids[2]; > + } else { > + oldnids = lpni->lpni_pref.nids; > + lpni->lpni_pref.nids = nids; > + } > + lpni->lpni_pref_nnids--; > + lpni->lpni_state &= ~LNET_PEER_NI_NON_MR_PREF; > + spin_unlock(&lpni->lpni_lock); > + lnet_net_unlock(LNET_LOCK_EX); > + > + kfree(oldnids); > +out: > + CDEBUG(D_NET, "peer %s nid %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), rc); > + return rc; > +} > + > lnet_nid_t > lnet_peer_primary_nid_locked(lnet_nid_t nid) > { > @@ -653,7 +868,7 @@ LNetPrimaryNID(lnet_nid_t nid) > int cpt; > > cpt = lnet_net_lock_current(); > - lpni = lnet_nid2peerni_locked(nid, cpt); > + lpni = lnet_nid2peerni_locked(nid, LNET_NID_ANY, cpt); > if (IS_ERR(lpni)) { > rc = PTR_ERR(lpni); > goto out_unlock; > @@ -802,6 +1017,7 @@ lnet_peer_add(lnet_nid_t nid, bool mr) > spin_lock(&lp->lp_lock); > if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { > /* The mr state is sticky. */ > CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", > @@ -829,8 +1045,10 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > return -EPERM; > } > > - if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > + } > spin_unlock(&lp->lp_lock); > > lpni = lnet_find_peer_ni_locked(nid); > @@ -856,28 +1074,27 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > * lpni creation initiated due to traffic either sending or receiving. > */ > static int > -lnet_peer_ni_traffic_add(lnet_nid_t nid) > +lnet_peer_ni_traffic_add(lnet_nid_t nid, lnet_nid_t pref) > { > struct lnet_peer_ni *lpni; > - int rc = 0; > + int rc; > > if (nid == LNET_NID_ANY) > return -EINVAL; > > /* lnet_net_lock is not needed here because ln_api_lock is held */ > lpni = lnet_find_peer_ni_locked(nid); > - if (lpni) { > - /* > - * TODO: lnet_update_primary_nid() but not all of it > - * only indicate if we're converting this to MR capable > - * Can happen due to DD > - */ > - lnet_peer_ni_decref_locked(lpni); > - } else { > + if (!lpni) { > rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); > + if (rc) > + return rc; > + lpni = lnet_find_peer_ni_locked(nid); > } > + if (pref != LNET_NID_ANY) > + lnet_peer_ni_set_non_mr_pref_nid(lpni, pref); > + lnet_peer_ni_decref_locked(lpni); > > - return rc; > + return 0; > } > > /* > @@ -984,6 +1201,8 @@ lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) > ptable->pt_zombies--; > spin_unlock(&ptable->pt_zombie_lock); > > + if (lpni->lpni_pref_nnids > 1) > + kfree(lpni->lpni_pref.nids); > kfree(lpni); > } > > @@ -1006,7 +1225,7 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) > > lnet_net_unlock(cpt); > > - rc = lnet_peer_ni_traffic_add(nid); > + rc = lnet_peer_ni_traffic_add(nid, LNET_NID_ANY); > if (rc) { > lpni = ERR_PTR(rc); > goto out_net_relock; > @@ -1022,7 +1241,7 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) > } > > struct lnet_peer_ni * > -lnet_nid2peerni_locked(lnet_nid_t nid, int cpt) > +lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) > { > struct lnet_peer_ni *lpni = NULL; > int rc; > @@ -1061,7 +1280,7 @@ lnet_nid2peerni_locked(lnet_nid_t nid, int cpt) > goto out_mutex_unlock; > } > > - rc = lnet_peer_ni_traffic_add(nid); > + rc = lnet_peer_ni_traffic_add(nid, pref); > if (rc) { > lpni = ERR_PTR(rc); > goto out_mutex_unlock; > @@ -1087,7 +1306,7 @@ lnet_debug_peer(lnet_nid_t nid) > cpt = lnet_cpt_of_nid(nid, NULL); > lnet_net_lock(cpt); > > - lp = lnet_nid2peerni_locked(nid, cpt); > + lp = lnet_nid2peerni_locked(nid, LNET_NID_ANY, cpt); > if (IS_ERR(lp)) { > lnet_net_unlock(cpt); > CDEBUG(D_WARNING, "No peer %s\n", libcfs_nid2str(nid)); > > > From jsimmons at infradead.org Sun Oct 14 20:32:07 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 21:32:07 +0100 (BST) Subject: [lustre-devel] [PATCH 13/24] lustre: lnet: add LNET_PEER_CONFIGURED flag In-Reply-To: <153895437804.16383.1008375422641070080.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437804.16383.1008375422641070080.stgit@noble> Message-ID: > From: Olaf Weber > > Add the LNET_PEER_CONFIGURED flag, which indicates that a peer > has been configured by DLC. This is used to enforce that only > DLC can modify such a peer. > > This includes some further refactoring of the code that creates > or modifies peers to ensure that the flag is properly passed > through, set, and cleared. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25783 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 12 + > .../staging/lustre/include/linux/lnet/lib-types.h | 1 > drivers/staging/lustre/lnet/lnet/peer.c | 426 +++++++++++++------- > 3 files changed, 290 insertions(+), 149 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 2864bd8a403b..563417510722 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -764,4 +764,16 @@ lnet_peer_is_multi_rail(struct lnet_peer *lp) > return lp->lp_state & LNET_PEER_MULTI_RAIL; > } > > +static inline bool > +lnet_peer_ni_is_configured(struct lnet_peer_ni *lpni) > +{ > + return lpni->lpni_peer_net->lpn_peer->lp_state & LNET_PEER_CONFIGURED; > +} > + > +static inline bool > +lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) > +{ > + return lpni->lpni_nid == lpni->lpni_peer_net->lpn_peer->lp_primary_nid; > +} > + > #endif > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index eff2aed5e5c1..d1721fd01d93 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -513,6 +513,7 @@ struct lnet_peer { > }; > > #define LNET_PEER_MULTI_RAIL BIT(0) > +#define LNET_PEER_CONFIGURED BIT(1) > > struct lnet_peer_net { > /* chain on peer block */ > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 44a2bf641260..09c1b5516f6b 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -191,10 +191,10 @@ lnet_peer_alloc(lnet_nid_t nid) > } > > static void > -lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) > +lnet_peer_detach_peer_ni(struct lnet_peer_ni *lpni) > { > - struct lnet_peer_net *peer_net; > - struct lnet_peer *peer; > + struct lnet_peer_net *lpn; > + struct lnet_peer *lp; > > /* TODO: could the below situation happen? accessing an already > * destroyed peer? > @@ -203,24 +203,28 @@ lnet_try_destroy_peer_hierarchy_locked(struct lnet_peer_ni *lpni) > !lpni->lpni_peer_net->lpn_peer) > return; > > - peer_net = lpni->lpni_peer_net; > - peer = lpni->lpni_peer_net->lpn_peer; > + lpn = lpni->lpni_peer_net; > + lp = lpni->lpni_peer_net->lpn_peer; > + > + CDEBUG(D_NET, "peer %s NID %s\n", > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(lpni->lpni_nid)); > > list_del_init(&lpni->lpni_on_peer_net_list); > lpni->lpni_peer_net = NULL; > > - /* if peer_net is empty, then remove it from the peer */ > - if (list_empty(&peer_net->lpn_peer_nis)) { > - list_del_init(&peer_net->lpn_on_peer_list); > - peer_net->lpn_peer = NULL; > - kfree(peer_net); > + /* if lpn is empty, then remove it from the peer */ > + if (list_empty(&lpn->lpn_peer_nis)) { > + list_del_init(&lpn->lpn_on_peer_list); > + lpn->lpn_peer = NULL; > + kfree(lpn); > > /* If the peer is empty then remove it from the > * the_lnet.ln_peers. > */ > - if (list_empty(&peer->lp_peer_nets)) { > - list_del_init(&peer->lp_on_lnet_peer_list); > - kfree(peer); > + if (list_empty(&lp->lp_peer_nets)) { > + list_del_init(&lp->lp_on_lnet_peer_list); > + kfree(lp); > } > } > } > @@ -263,10 +267,10 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) > ptable->pt_zombies++; > spin_unlock(&ptable->pt_zombie_lock); > > - /* no need to keep this peer on the hierarchy anymore */ > - lnet_try_destroy_peer_hierarchy_locked(lpni); > + /* no need to keep this peer_ni on the hierarchy anymore */ > + lnet_peer_detach_peer_ni(lpni); > > - /* decrement reference on peer */ > + /* decrement reference on peer_ni */ > lnet_peer_ni_decref_locked(lpni); > > return 0; > @@ -329,6 +333,8 @@ lnet_peer_del_locked(struct lnet_peer *peer) > struct lnet_peer_ni *lpni = NULL, *lpni2; > int rc = 0, rc2 = 0; > > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(peer->lp_primary_nid)); > + > lpni = lnet_get_next_peer_ni_locked(peer, NULL, lpni); > while (lpni) { > lpni2 = lnet_get_next_peer_ni_locked(peer, NULL, lpni); > @@ -352,31 +358,36 @@ lnet_peer_del(struct lnet_peer *peer) > } > > /* > - * Delete a NID from a peer. > - * Implements a few sanity checks. > - * Call with ln_api_mutex held. > + * Delete a NID from a peer. Call with ln_api_mutex held. > + * > + * Error codes: > + * -EPERM: Non-DLC deletion from DLC-configured peer. > + * -ENOENT: No lnet_peer_ni corresponding to the nid. > + * -ECHILD: The lnet_peer_ni isn't connected to the peer. > + * -EBUSY: The lnet_peer_ni is the primary, and not the only peer_ni. > */ > static int > -lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) > +lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) > { > - struct lnet_peer *lp2; > struct lnet_peer_ni *lpni; > + lnet_nid_t primary_nid = lp->lp_primary_nid; > + int rc = 0; > > + if (!(flags & LNET_PEER_CONFIGURED)) { > + if (lp->lp_state & LNET_PEER_CONFIGURED) { > + rc = -EPERM; > + goto out; > + } > + } > lpni = lnet_find_peer_ni_locked(nid); > if (!lpni) { > - CERROR("Cannot remove unknown nid %s from peer %s\n", > - libcfs_nid2str(nid), > - libcfs_nid2str(lp->lp_primary_nid)); > - return -ENOENT; > + rc = -ENOENT; > + goto out; > } > lnet_peer_ni_decref_locked(lpni); > - lp2 = lpni->lpni_peer_net->lpn_peer; > - if (lp2 != lp) { > - CERROR("Nid %s is attached to peer %s, not peer %s\n", > - libcfs_nid2str(nid), > - libcfs_nid2str(lp2->lp_primary_nid), > - libcfs_nid2str(lp->lp_primary_nid)); > - return -EINVAL; > + if (lp != lpni->lpni_peer_net->lpn_peer) { > + rc = -ECHILD; > + goto out; > } > > /* > @@ -384,16 +395,19 @@ lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid) > * is the only NID. > */ > if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { > - CERROR("Cannot delete primary NID %s from multi-NID peer\n", > - libcfs_nid2str(nid)); > - return -EINVAL; > + rc = -EBUSY; > + goto out; > } > > lnet_net_lock(LNET_LOCK_EX); > lnet_peer_ni_del_locked(lpni); > lnet_net_unlock(LNET_LOCK_EX); > > - return 0; > +out: > + CDEBUG(D_NET, "peer %s NID %s flags %#x: %d\n", > + libcfs_nid2str(primary_nid), libcfs_nid2str(nid), flags, rc); > + > + return rc; > } > > static void > @@ -895,46 +909,27 @@ lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) > return NULL; > } > > +/* > + * Always returns 0, but it the last function called from functions > + * that do return an int, so returning 0 here allows the compiler to > + * do a tail call. > + */ > static int > -lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni > - *lpni, > - lnet_nid_t nid) > +lnet_peer_attach_peer_ni(struct lnet_peer *lp, > + struct lnet_peer_net *lpn, > + struct lnet_peer_ni *lpni, > + unsigned int flags) > { > - struct lnet_peer_net *lpn = NULL; > struct lnet_peer_table *ptable; > - u32 net_id = LNET_NIDNET(nid); > - > - /* > - * Create the peer_ni, peer_net, and peer if they don't exist > - * yet. > - */ > - if (lp) { > - lpn = lnet_peer_get_net_locked(lp, net_id); > - } else { > - lp = lnet_peer_alloc(nid); > - if (!lp) > - goto out_enomem; > - } > - > - if (!lpn) { > - lpn = lnet_peer_net_alloc(net_id); > - if (!lpn) > - goto out_maybe_free_lp; > - } > - > - if (!lpni) { > - lpni = lnet_peer_ni_alloc(nid); > - if (!lpni) > - goto out_maybe_free_lpn; > - } > > /* Install the new peer_ni */ > lnet_net_lock(LNET_LOCK_EX); > /* Add peer_ni to global peer table hash, if necessary. */ > if (list_empty(&lpni->lpni_hashlist)) { > + int hash = lnet_nid2peerhash(lpni->lpni_nid); > + > ptable = the_lnet.ln_peer_tables[lpni->lpni_cpt]; > - list_add_tail(&lpni->lpni_hashlist, > - &ptable->pt_hash[lnet_nid2peerhash(nid)]); > + list_add_tail(&lpni->lpni_hashlist, &ptable->pt_hash[hash]); > ptable->pt_version++; > atomic_inc(&ptable->pt_number); > atomic_inc(&lpni->lpni_refcount); > @@ -942,7 +937,7 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni > > /* Detach the peer_ni from an existing peer, if necessary. */ > if (lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer != lp) > - lnet_try_destroy_peer_hierarchy_locked(lpni); > + lnet_peer_detach_peer_ni(lpni); > > /* Add peer_ni to peer_net */ > lpni->lpni_peer_net = lpn; > @@ -957,33 +952,42 @@ lnet_peer_setup_hierarchy(struct lnet_peer *lp, struct lnet_peer_ni > /* Add peer to global peer list */ > if (list_empty(&lp->lp_on_lnet_peer_list)) > list_add_tail(&lp->lp_on_lnet_peer_list, &the_lnet.ln_peers); > + > + /* Update peer state */ > + spin_lock(&lp->lp_lock); > + if (flags & LNET_PEER_CONFIGURED) { > + if (!(lp->lp_state & LNET_PEER_CONFIGURED)) > + lp->lp_state |= LNET_PEER_CONFIGURED; > + } > + if (flags & LNET_PEER_MULTI_RAIL) { > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > + } > + } > + spin_unlock(&lp->lp_lock); > + > lnet_net_unlock(LNET_LOCK_EX); > > - return 0; > + CDEBUG(D_NET, "peer %s NID %s flags %#x\n", > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(lpni->lpni_nid), flags); > > -out_maybe_free_lpn: > - if (list_empty(&lpn->lpn_on_peer_list)) > - kfree(lpn); > -out_maybe_free_lp: > - if (list_empty(&lp->lp_on_lnet_peer_list)) > - kfree(lp); > -out_enomem: > - return -ENOMEM; > + return 0; > } > > /* > * Create a new peer, with nid as its primary nid. > * > - * It is not an error if the peer already exists, provided that the > - * given nid is the primary NID. > - * > * Call with the lnet_api_mutex held. > */ > static int > -lnet_peer_add(lnet_nid_t nid, bool mr) > +lnet_peer_add(lnet_nid_t nid, unsigned int flags) > { > struct lnet_peer *lp; > + struct lnet_peer_net *lpn; > struct lnet_peer_ni *lpni; > + int rc = 0; > > LASSERT(nid != LNET_NID_ANY); > > @@ -992,82 +996,153 @@ lnet_peer_add(lnet_nid_t nid, bool mr) > * lnet_api_mutex is held. > */ > lpni = lnet_find_peer_ni_locked(nid); > - if (!lpni) { > - int rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); > - if (rc != 0) > - return rc; > - lpni = lnet_find_peer_ni_locked(nid); > - LASSERT(lpni); > + if (lpni) { > + /* A peer with this NID already exists. */ > + lp = lpni->lpni_peer_net->lpn_peer; > + lnet_peer_ni_decref_locked(lpni); > + /* > + * This is an error if the peer was configured and the > + * primary NID differs or an attempt is made to change > + * the Multi-Rail flag. Otherwise the assumption is > + * that an existing peer is being modified. > + */ > + if (lp->lp_state & LNET_PEER_CONFIGURED) { > + if (lp->lp_primary_nid != nid) > + rc = -EEXIST; > + else if ((lp->lp_state ^ flags) & LNET_PEER_MULTI_RAIL) > + rc = -EPERM; > + goto out; > + } > + /* Delete and recreate as a configured peer. */ > + lnet_peer_del(lp); > } > - lp = lpni->lpni_peer_net->lpn_peer; > - lnet_peer_ni_decref_locked(lpni); > > - /* A found peer must have this primary NID */ > - if (lp->lp_primary_nid != nid) > - return -EEXIST; > + /* Create peer, peer_net, and peer_ni. */ > + rc = -ENOMEM; > + lp = lnet_peer_alloc(nid); > + if (!lp) > + goto out; > + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); > + if (!lpn) > + goto out_free_lp; > + lpni = lnet_peer_ni_alloc(nid); > + if (!lpni) > + goto out_free_lpn; > > - /* > - * If we found an lpni that is not a multi-rail, which could occur > - * if lpni is already created as a non-mr lpni or we just created > - * it, then make sure you indicate that this lpni is a primary mr > - * capable peer. > - * > - * TODO: update flags if necessary > - */ > - spin_lock(&lp->lp_lock); > - if (mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > - lp->lp_state |= LNET_PEER_MULTI_RAIL; > - lnet_peer_clr_non_mr_pref_nids(lp); > - } else if (!mr && (lp->lp_state & LNET_PEER_MULTI_RAIL)) { > - /* The mr state is sticky. */ > - CDEBUG(D_NET, "Cannot clear multi-rail flag from peer %s\n", > - libcfs_nid2str(nid)); > - } > - spin_unlock(&lp->lp_lock); > + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); > > - return 0; > +out_free_lpn: > + kfree(lpn); > +out_free_lp: > + kfree(lp); > +out: > + CDEBUG(D_NET, "peer %s NID flags %#x: %d\n", > + libcfs_nid2str(nid), flags, rc); > + return rc; > } > > +/* > + * Add a NID to a peer. Call with ln_api_mutex held. > + * > + * Error codes: > + * -EPERM: Non-DLC addition to a DLC-configured peer. > + * -EEXIST: The NID was configured by DLC for a different peer. > + * -ENOMEM: Out of memory. > + * -ENOTUNIQ: Adding a second peer NID on a single network on a > + * non-multi-rail peer. > + */ > static int > -lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > +lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) > { > + struct lnet_peer_net *lpn; > struct lnet_peer_ni *lpni; > + int rc = 0; > > LASSERT(lp); > LASSERT(nid != LNET_NID_ANY); > > - spin_lock(&lp->lp_lock); > - if (!mr && !(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > - spin_unlock(&lp->lp_lock); > - CERROR("Cannot add nid %s to non-multi-rail peer %s\n", > - libcfs_nid2str(nid), > - libcfs_nid2str(lp->lp_primary_nid)); > - return -EPERM; > + /* A configured peer can only be updated through configuration. */ > + if (!(flags & LNET_PEER_CONFIGURED)) { > + if (lp->lp_state & LNET_PEER_CONFIGURED) { > + rc = -EPERM; > + goto out; > + } > } > > - if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > - lp->lp_state |= LNET_PEER_MULTI_RAIL; > - lnet_peer_clr_non_mr_pref_nids(lp); > + /* > + * The MULTI_RAIL flag can be set but not cleared, because > + * that would leave the peer struct in an invalid state. > + */ > + if (flags & LNET_PEER_MULTI_RAIL) { > + spin_lock(&lp->lp_lock); > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > + } > + spin_unlock(&lp->lp_lock); > + } else if (lp->lp_state & LNET_PEER_MULTI_RAIL) { > + rc = -EPERM; > + goto out; > } > - spin_unlock(&lp->lp_lock); > > lpni = lnet_find_peer_ni_locked(nid); > - if (!lpni) > - return lnet_peer_setup_hierarchy(lp, NULL, nid); > + if (lpni) { > + /* > + * A peer_ni already exists. This is only a problem if > + * it is not connected to this peer and was configured > + * by DLC. > + */ > + lnet_peer_ni_decref_locked(lpni); > + if (lpni->lpni_peer_net->lpn_peer == lp) > + goto out; > + if (lnet_peer_ni_is_configured(lpni)) { > + rc = -EEXIST; > + goto out; > + } > + /* If this is the primary NID, destroy the peer. */ > + if (lnet_peer_ni_is_primary(lpni)) { > + lnet_peer_del(lpni->lpni_peer_net->lpn_peer); > + lpni = lnet_peer_ni_alloc(nid); > + if (!lpni) { > + rc = -ENOMEM; > + goto out; > + } > + } > + } else { > + lpni = lnet_peer_ni_alloc(nid); > + if (!lpni) { > + rc = -ENOMEM; > + goto out; > + } > + } > > - if (lpni->lpni_peer_net->lpn_peer != lp) { > - struct lnet_peer *lp2 = lpni->lpni_peer_net->lpn_peer; > - CERROR("Cannot add NID %s owned by peer %s to peer %s\n", > - libcfs_nid2str(lpni->lpni_nid), > - libcfs_nid2str(lp2->lp_primary_nid), > - libcfs_nid2str(lp->lp_primary_nid)); > - return -EEXIST; > + /* > + * Get the peer_net. Check that we're not adding a second > + * peer_ni on a peer_net of a non-multi-rail peer. > + */ > + lpn = lnet_peer_get_net_locked(lp, LNET_NIDNET(nid)); > + if (!lpn) { > + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); > + if (!lpn) { > + rc = -ENOMEM; > + goto out_free_lpni; > + } > + } else if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + rc = -ENOTUNIQ; > + goto out_free_lpni; > } > > - CDEBUG(D_NET, "NID %s is already owned by peer %s\n", > - libcfs_nid2str(lpni->lpni_nid), > - libcfs_nid2str(lp->lp_primary_nid)); > - return 0; > + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); > + > +out_free_lpni: > + /* If the peer_ni was allocated above its peer_net pointer is NULL */ > + if (!lpni->lpni_peer_net) > + kfree(lpni); > +out: > + CDEBUG(D_NET, "peer %s NID %s flags %#x: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), libcfs_nid2str(nid), > + flags, rc); > + return rc; > } > > /* > @@ -1076,25 +1151,53 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, bool mr) > static int > lnet_peer_ni_traffic_add(lnet_nid_t nid, lnet_nid_t pref) > { > + struct lnet_peer *lp; > + struct lnet_peer_net *lpn; > struct lnet_peer_ni *lpni; > - int rc; > + unsigned int flags = 0; > + int rc = 0; > > - if (nid == LNET_NID_ANY) > - return -EINVAL; > + if (nid == LNET_NID_ANY) { > + rc = -EINVAL; > + goto out; > + } > > /* lnet_net_lock is not needed here because ln_api_lock is held */ > lpni = lnet_find_peer_ni_locked(nid); > - if (!lpni) { > - rc = lnet_peer_setup_hierarchy(NULL, NULL, nid); > - if (rc) > - return rc; > - lpni = lnet_find_peer_ni_locked(nid); > + if (lpni) { > + /* > + * We must have raced with another thread. Since we > + * know next to nothing about a peer_ni created by > + * traffic, we just assume everything is ok and > + * return. > + */ > + lnet_peer_ni_decref_locked(lpni); > + goto out; > } > + > + /* Create peer, peer_net, and peer_ni. */ > + rc = -ENOMEM; > + lp = lnet_peer_alloc(nid); > + if (!lp) > + goto out; > + lpn = lnet_peer_net_alloc(LNET_NIDNET(nid)); > + if (!lpn) > + goto out_free_lp; > + lpni = lnet_peer_ni_alloc(nid); > + if (!lpni) > + goto out_free_lpn; > if (pref != LNET_NID_ANY) > lnet_peer_ni_set_non_mr_pref_nid(lpni, pref); > - lnet_peer_ni_decref_locked(lpni); > > - return 0; > + return lnet_peer_attach_peer_ni(lp, lpn, lpni, flags); > + > +out_free_lpn: > + kfree(lpn); > +out_free_lp: > + kfree(lp); > +out: > + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(nid), rc); > + return rc; > } > > /* > @@ -1114,17 +1217,22 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > { > struct lnet_peer *lp = NULL; > struct lnet_peer_ni *lpni; > + unsigned int flags; > > /* The prim_nid must always be specified */ > if (prim_nid == LNET_NID_ANY) > return -EINVAL; > > + flags = LNET_PEER_CONFIGURED; > + if (mr) > + flags |= LNET_PEER_MULTI_RAIL; > + > /* > * If nid isn't specified, we must create a new peer with > * prim_nid as its primary nid. > */ > if (nid == LNET_NID_ANY) > - return lnet_peer_add(prim_nid, mr); > + return lnet_peer_add(prim_nid, flags); > > /* Look up the prim_nid, which must exist. */ > lpni = lnet_find_peer_ni_locked(prim_nid); > @@ -1133,6 +1241,14 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > lnet_peer_ni_decref_locked(lpni); > lp = lpni->lpni_peer_net->lpn_peer; > > + /* Peer must have been configured. */ > + if (!(lp->lp_state & LNET_PEER_CONFIGURED)) { > + CDEBUG(D_NET, "peer %s was not configured\n", > + libcfs_nid2str(prim_nid)); > + return -ENOENT; > + } > + > + /* Primary NID must match */ > if (lp->lp_primary_nid != prim_nid) { > CDEBUG(D_NET, "prim_nid %s is not primary for peer %s\n", > libcfs_nid2str(prim_nid), > @@ -1140,7 +1256,14 @@ lnet_add_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid, bool mr) > return -ENODEV; > } > > - return lnet_peer_add_nid(lp, nid, mr); > + /* Multi-Rail flag must match. */ > + if ((lp->lp_state ^ flags) & LNET_PEER_MULTI_RAIL) { > + CDEBUG(D_NET, "multi-rail state mismatch for peer %s\n", > + libcfs_nid2str(prim_nid)); > + return -EPERM; > + } > + > + return lnet_peer_add_nid(lp, nid, flags); > } > > /* > @@ -1159,6 +1282,7 @@ lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) > { > struct lnet_peer *lp; > struct lnet_peer_ni *lpni; > + unsigned int flags; > > if (prim_nid == LNET_NID_ANY) > return -EINVAL; > @@ -1179,7 +1303,11 @@ lnet_del_peer_ni(lnet_nid_t prim_nid, lnet_nid_t nid) > if (nid == LNET_NID_ANY || nid == lp->lp_primary_nid) > return lnet_peer_del(lp); > > - return lnet_peer_del_nid(lp, nid); > + flags = LNET_PEER_CONFIGURED; > + if (lp->lp_state & LNET_PEER_MULTI_RAIL) > + flags |= LNET_PEER_MULTI_RAIL; > + > + return lnet_peer_del_nid(lp, nid, flags); > } > > void > > > From jsimmons at infradead.org Sun Oct 14 22:42:22 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 23:42:22 +0100 (BST) Subject: [lustre-devel] [PATCH 14/24] lustre: lnet: reference counts on lnet_peer/lnet_peer_net In-Reply-To: <153895437808.16383.1725584261522697360.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437808.16383.1725584261522697360.stgit@noble> Message-ID: > From: Olaf Weber > > Peer discovery will be keeping track of lnet_peer structures, > so there will be references to an lnet_peer independent of > the references implied by lnet_peer_ni structures. Manage > this by adding explicit reference counts to lnet_peer_net and > lnet_peer. > > Each lnet_peer_net has a hold on the lnet_peer it links to > with its lpn_peer pointer. This hold is only removed when that > pointer is assigned a new value or the lnet_peer_net is freed. > Just removing an lnet_peer_net from the lp_peer_nets list does > not release this hold, it just prevents new lookups of the > lnet_peer_net via the lnet_peer. > > Each lnet_peer_ni has a hold on the lnet_peer_net it links to > with its lpni_peer_net pointer. This hold is only removed when > that pointer is assigned a new value or the lnet_peer_ni is > freed. Just removing an lnet_peer_ni from the lpn_peer_nis > list does not release this hold, it just prevents new lookups > of the lnet_peer_ni via the lnet_peer_net. > > This ensures that given a lnet_peer_ni *lpni, we can rely on > lpni->lpni_peer_net->lpn_peer pointing to a valid lnet_peer. > > Keep a count of the total number of lnet_peer_ni attached to > an lnet_peer in lp_nnis. > > Split the global ln_peers list into per-lnet_peer_table lists. > The CPT of the peer table in which the lnet_peer is linked is > stored in lp_cpt. > > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25784 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 49 +++-- > .../staging/lustre/include/linux/lnet/lib-types.h | 50 ++++- > drivers/staging/lustre/lnet/lnet/api-ni.c | 1 > drivers/staging/lustre/lnet/lnet/lib-move.c | 8 - > drivers/staging/lustre/lnet/lnet/peer.c | 210 ++++++++++++++------ > 5 files changed, 227 insertions(+), 91 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 563417510722..aad25eb0011b 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -310,6 +310,36 @@ lnet_handle2me(struct lnet_handle_me *handle) > return lh_entry(lh, struct lnet_me, me_lh); > } > > +static inline void > +lnet_peer_net_addref_locked(struct lnet_peer_net *lpn) > +{ > + atomic_inc(&lpn->lpn_refcount); > +} > + > +void lnet_destroy_peer_net_locked(struct lnet_peer_net *lpn); > + > +static inline void > +lnet_peer_net_decref_locked(struct lnet_peer_net *lpn) > +{ > + if (atomic_dec_and_test(&lpn->lpn_refcount)) > + lnet_destroy_peer_net_locked(lpn); > +} > + > +static inline void > +lnet_peer_addref_locked(struct lnet_peer *lp) > +{ > + atomic_inc(&lp->lp_refcount); > +} > + > +void lnet_destroy_peer_locked(struct lnet_peer *lp); > + > +static inline void > +lnet_peer_decref_locked(struct lnet_peer *lp) > +{ > + if (atomic_dec_and_test(&lp->lp_refcount)) > + lnet_destroy_peer_locked(lp); > +} > + > static inline void > lnet_peer_ni_addref_locked(struct lnet_peer_ni *lp) > { > @@ -695,21 +725,6 @@ int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > __u32 *peer_rtr_credits, __u32 *peer_min_rtr_credtis, > __u32 *peer_tx_qnob); > > -static inline __u32 > -lnet_get_num_peer_nis(struct lnet_peer *peer) > -{ > - struct lnet_peer_net *lpn; > - struct lnet_peer_ni *lpni; > - __u32 count = 0; > - > - list_for_each_entry(lpn, &peer->lp_peer_nets, lpn_on_peer_list) > - list_for_each_entry(lpni, &lpn->lpn_peer_nis, > - lpni_on_peer_net_list) > - count++; > - > - return count; > -} > - > static inline bool > lnet_is_peer_ni_healthy_locked(struct lnet_peer_ni *lpni) > { > @@ -728,7 +743,7 @@ lnet_is_peer_net_healthy_locked(struct lnet_peer_net *peer_net) > struct lnet_peer_ni *lpni; > > list_for_each_entry(lpni, &peer_net->lpn_peer_nis, > - lpni_on_peer_net_list) { > + lpni_peer_nis) { > if (lnet_is_peer_ni_healthy_locked(lpni)) > return true; > } > @@ -741,7 +756,7 @@ lnet_is_peer_healthy_locked(struct lnet_peer *peer) > { > struct lnet_peer_net *peer_net; > > - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { > + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { > if (lnet_is_peer_net_healthy_locked(peer_net)) > return true; > } > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index d1721fd01d93..260619e19bde 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -411,7 +411,8 @@ struct lnet_rc_data { > }; > > struct lnet_peer_ni { > - struct list_head lpni_on_peer_net_list; > + /* chain on lpn_peer_nis */ > + struct list_head lpni_peer_nis; > /* chain on remote peer list */ > struct list_head lpni_on_remote_peer_ni_list; > /* chain on peer hash */ > @@ -496,8 +497,8 @@ struct lnet_peer_ni { > #define LNET_PEER_NI_NON_MR_PREF BIT(0) > > struct lnet_peer { > - /* chain on global peer list */ > - struct list_head lp_on_lnet_peer_list; > + /* chain on pt_peer_list */ > + struct list_head lp_peer_list; > > /* list of peer nets */ > struct list_head lp_peer_nets; > @@ -505,6 +506,15 @@ struct lnet_peer { > /* primary NID of the peer */ > lnet_nid_t lp_primary_nid; > > + /* CPT of peer_table */ > + int lp_cpt; > + > + /* number of NIDs on this peer */ > + int lp_nnis; > + > + /* reference count */ > + atomic_t lp_refcount; > + > /* lock protecting peer state flags */ > spinlock_t lp_lock; > > @@ -516,8 +526,8 @@ struct lnet_peer { > #define LNET_PEER_CONFIGURED BIT(1) > > struct lnet_peer_net { > - /* chain on peer block */ > - struct list_head lpn_on_peer_list; > + /* chain on lp_peer_nets */ > + struct list_head lpn_peer_nets; > > /* list of peer_nis on this network */ > struct list_head lpn_peer_nis; > @@ -527,21 +537,45 @@ struct lnet_peer_net { > > /* Net ID */ > __u32 lpn_net_id; > + > + /* reference count */ > + atomic_t lpn_refcount; > }; > > /* peer hash size */ > #define LNET_PEER_HASH_BITS 9 > #define LNET_PEER_HASH_SIZE (1 << LNET_PEER_HASH_BITS) > > -/* peer hash table */ > +/* > + * peer hash table - one per CPT > + * > + * protected by lnet_net_lock/EX for update > + * pt_version > + * pt_number > + * pt_hash[...] > + * pt_peer_list > + * pt_peers > + * pt_peer_nnids > + * protected by pt_zombie_lock: > + * pt_zombie_list > + * pt_zombies > + * > + * pt_zombie lock nests inside lnet_net_lock > + */ > struct lnet_peer_table { > /* /proc validity stamp */ > int pt_version; > /* # peers extant */ > atomic_t pt_number; > + /* peers */ > + struct list_head pt_peer_list; > + /* # peers */ > + int pt_peers; > + /* # NIDS on listed peers */ > + int pt_peer_nnids; > /* # zombies to go to deathrow (and not there yet) */ > int pt_zombies; > - /* zombie peers */ > + /* zombie peers_ni */ > struct list_head pt_zombie_list; > /* protect list and count */ > spinlock_t pt_zombie_lock; > @@ -785,8 +819,6 @@ struct lnet { > struct lnet_msg_container **ln_msg_containers; > struct lnet_counters **ln_counters; > struct lnet_peer_table **ln_peer_tables; > - /* list of configured or discovered peers */ > - struct list_head ln_peers; > /* list of peer nis not on a local network */ > struct list_head ln_remote_peer_ni_list; > /* failure simulation */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index d64ae2939abc..c48bcb8722a0 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -625,7 +625,6 @@ lnet_prepare(lnet_pid_t requested_pid) > the_lnet.ln_pid = requested_pid; > > INIT_LIST_HEAD(&the_lnet.ln_test_peers); > - INIT_LIST_HEAD(&the_lnet.ln_peers); > INIT_LIST_HEAD(&the_lnet.ln_remote_peer_ni_list); > INIT_LIST_HEAD(&the_lnet.ln_nets); > INIT_LIST_HEAD(&the_lnet.ln_routers); > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 99d8b22356bb..4c1eef907dc7 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -1388,7 +1388,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > peer_net = lnet_peer_get_net_locked( > peer, LNET_NIDNET(best_lpni->lpni_nid)); > list_for_each_entry(lpni, &peer_net->lpn_peer_nis, > - lpni_on_peer_net_list) { > + lpni_peer_nis) { > if (lpni->lpni_pref_nnids == 0) > continue; > LASSERT(lpni->lpni_pref_nnids == 1); > @@ -1411,7 +1411,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > } > lpni = list_entry(peer_net->lpn_peer_nis.next, > struct lnet_peer_ni, > - lpni_on_peer_net_list); > + lpni_peer_nis); > } > /* Set preferred NI if necessary. */ > if (lpni->lpni_pref_nnids == 0) > @@ -1443,7 +1443,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > * then the best route is chosen. If all routes are equal then > * they are used in round robin. > */ > - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { > + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { > if (!lnet_is_peer_net_healthy_locked(peer_net)) > continue; > > @@ -1453,7 +1453,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > > lpni = list_entry(peer_net->lpn_peer_nis.next, > struct lnet_peer_ni, > - lpni_on_peer_net_list); > + lpni_peer_nis); > > net_gw = lnet_find_route_locked(NULL, > lpni->lpni_nid, > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 09c1b5516f6b..d7a0a2f3bdd9 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c INIT_LIST_HEAD(&ptable->pt_peer_list); seems to be missing from lnet_peer_tables_create(). This is in the patch merged into lustre-testing. Other than that it looks okay. > @@ -118,7 +118,7 @@ lnet_peer_ni_alloc(lnet_nid_t nid) > INIT_LIST_HEAD(&lpni->lpni_rtrq); > INIT_LIST_HEAD(&lpni->lpni_routes); > INIT_LIST_HEAD(&lpni->lpni_hashlist); > - INIT_LIST_HEAD(&lpni->lpni_on_peer_net_list); > + INIT_LIST_HEAD(&lpni->lpni_peer_nis); > INIT_LIST_HEAD(&lpni->lpni_on_remote_peer_ni_list); > > spin_lock_init(&lpni->lpni_lock); > @@ -150,7 +150,7 @@ lnet_peer_ni_alloc(lnet_nid_t nid) > &the_lnet.ln_remote_peer_ni_list); > } > > - /* TODO: update flags */ > + CDEBUG(D_NET, "%p nid %s\n", lpni, libcfs_nid2str(lpni->lpni_nid)); > > return lpni; > } > @@ -164,13 +164,32 @@ lnet_peer_net_alloc(u32 net_id) > if (!lpn) > return NULL; > > - INIT_LIST_HEAD(&lpn->lpn_on_peer_list); > + INIT_LIST_HEAD(&lpn->lpn_peer_nets); > INIT_LIST_HEAD(&lpn->lpn_peer_nis); > lpn->lpn_net_id = net_id; > > + CDEBUG(D_NET, "%p net %s\n", lpn, libcfs_net2str(lpn->lpn_net_id)); > + > return lpn; > } > > +void > +lnet_destroy_peer_net_locked(struct lnet_peer_net *lpn) > +{ > + struct lnet_peer *lp; > + > + CDEBUG(D_NET, "%p net %s\n", lpn, libcfs_net2str(lpn->lpn_net_id)); > + > + LASSERT(atomic_read(&lpn->lpn_refcount) == 0); > + LASSERT(list_empty(&lpn->lpn_peer_nis)); > + LASSERT(list_empty(&lpn->lpn_peer_nets)); > + lp = lpn->lpn_peer; > + lpn->lpn_peer = NULL; > + kfree(lpn); > + > + lnet_peer_decref_locked(lp); > +} > + > static struct lnet_peer * > lnet_peer_alloc(lnet_nid_t nid) > { > @@ -180,53 +199,73 @@ lnet_peer_alloc(lnet_nid_t nid) > if (!lp) > return NULL; > > - INIT_LIST_HEAD(&lp->lp_on_lnet_peer_list); > + INIT_LIST_HEAD(&lp->lp_peer_list); > INIT_LIST_HEAD(&lp->lp_peer_nets); > spin_lock_init(&lp->lp_lock); > lp->lp_primary_nid = nid; > + lp->lp_cpt = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); > > - /* TODO: update flags */ > + CDEBUG(D_NET, "%p nid %s\n", lp, libcfs_nid2str(lp->lp_primary_nid)); > > return lp; > } > > +void > +lnet_destroy_peer_locked(struct lnet_peer *lp) > +{ > + CDEBUG(D_NET, "%p nid %s\n", lp, libcfs_nid2str(lp->lp_primary_nid)); > + > + LASSERT(atomic_read(&lp->lp_refcount) == 0); > + LASSERT(list_empty(&lp->lp_peer_nets)); > + LASSERT(list_empty(&lp->lp_peer_list)); > + > + kfree(lp); > +} > + > +/* > + * Detach a peer_ni from its peer_net. If this was the last peer_ni on > + * that peer_net, detach the peer_net from the peer. > + * > + * Call with lnet_net_lock/EX held > + */ > static void > -lnet_peer_detach_peer_ni(struct lnet_peer_ni *lpni) > +lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) > { > + struct lnet_peer_table *ptable; > struct lnet_peer_net *lpn; > struct lnet_peer *lp; > > - /* TODO: could the below situation happen? accessing an already > - * destroyed peer? > + /* > + * Belts and suspenders: gracefully handle teardown of a > + * partially connected peer_ni. > */ > - if (!lpni->lpni_peer_net || > - !lpni->lpni_peer_net->lpn_peer) > - return; > - > lpn = lpni->lpni_peer_net; > - lp = lpni->lpni_peer_net->lpn_peer; > > - CDEBUG(D_NET, "peer %s NID %s\n", > - libcfs_nid2str(lp->lp_primary_nid), > - libcfs_nid2str(lpni->lpni_nid)); > - > - list_del_init(&lpni->lpni_on_peer_net_list); > - lpni->lpni_peer_net = NULL; > + list_del_init(&lpni->lpni_peer_nis); > + /* > + * If there are no lpni's left, we detach lpn from > + * lp_peer_nets, so it cannot be found anymore. > + */ > + if (list_empty(&lpn->lpn_peer_nis)) > + list_del_init(&lpn->lpn_peer_nets); > > - /* if lpn is empty, then remove it from the peer */ > - if (list_empty(&lpn->lpn_peer_nis)) { > - list_del_init(&lpn->lpn_on_peer_list); > - lpn->lpn_peer = NULL; > - kfree(lpn); > + /* Update peer NID count. */ > + lp = lpn->lpn_peer; > + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; > + lp->lp_nnis--; > + ptable->pt_peer_nnids--; > > - /* If the peer is empty then remove it from the > - * the_lnet.ln_peers. > - */ > - if (list_empty(&lp->lp_peer_nets)) { > - list_del_init(&lp->lp_on_lnet_peer_list); > - kfree(lp); > - } > + /* > + * If there are no more peer nets, make the peer unfindable > + * via the peer_tables. > + */ > + if (list_empty(&lp->lp_peer_nets)) { > + list_del_init(&lp->lp_peer_list); > + ptable->pt_peers--; > } > + CDEBUG(D_NET, "peer %s NID %s\n", > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(lpni->lpni_nid)); > } > > /* called with lnet_net_lock LNET_LOCK_EX held */ > @@ -268,9 +307,9 @@ lnet_peer_ni_del_locked(struct lnet_peer_ni *lpni) > spin_unlock(&ptable->pt_zombie_lock); > > /* no need to keep this peer_ni on the hierarchy anymore */ > - lnet_peer_detach_peer_ni(lpni); > + lnet_peer_detach_peer_ni_locked(lpni); > > - /* decrement reference on peer_ni */ > + /* remove hashlist reference on peer_ni */ > lnet_peer_ni_decref_locked(lpni); > > return 0; > @@ -319,6 +358,8 @@ lnet_peer_tables_create(void) > spin_lock_init(&ptable->pt_zombie_lock); > INIT_LIST_HEAD(&ptable->pt_zombie_list); > > + INIT_LIST_HEAD(&ptable->pt_peer_list); > + > for (j = 0; j < LNET_PEER_HASH_SIZE; j++) > INIT_LIST_HEAD(&hash[j]); > ptable->pt_hash = hash; /* sign of initialization */ > @@ -394,7 +435,7 @@ lnet_peer_del_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) > * This function only allows deletion of the primary NID if it > * is the only NID. > */ > - if (nid == lp->lp_primary_nid && lnet_get_num_peer_nis(lp) != 1) { > + if (nid == lp->lp_primary_nid && lp->lp_nnis != 1) { > rc = -EBUSY; > goto out; > } > @@ -560,15 +601,34 @@ struct lnet_peer_ni * > lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, > struct lnet_peer **lp) > { > + struct lnet_peer_table *ptable; > struct lnet_peer_ni *lpni; > + int lncpt; > + int cpt; > + > + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); > > - list_for_each_entry((*lp), &the_lnet.ln_peers, lp_on_lnet_peer_list) { > + for (cpt = 0; cpt < lncpt; cpt++) { > + ptable = the_lnet.ln_peer_tables[cpt]; > + if (ptable->pt_peer_nnids > idx) > + break; > + idx -= ptable->pt_peer_nnids; > + } > + if (cpt >= lncpt) > + return NULL; > + > + list_for_each_entry((*lp), &ptable->pt_peer_list, lp_peer_list) { > + if ((*lp)->lp_nnis <= idx) { > + idx -= (*lp)->lp_nnis; > + continue; > + } > list_for_each_entry((*lpn), &((*lp)->lp_peer_nets), > - lpn_on_peer_list) { > + lpn_peer_nets) { > list_for_each_entry(lpni, &((*lpn)->lpn_peer_nis), > - lpni_on_peer_net_list) > + lpni_peer_nis) { > if (idx-- == 0) > return lpni; > + } > } > } > > @@ -584,18 +644,21 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > struct lnet_peer_net *net = peer_net; > > if (!prev) { > - if (!net) > + if (!net) { > + if (list_empty(&peer->lp_peer_nets)) > + return NULL; > + > net = list_entry(peer->lp_peer_nets.next, > struct lnet_peer_net, > - lpn_on_peer_list); > + lpn_peer_nets); > + } > lpni = list_entry(net->lpn_peer_nis.next, struct lnet_peer_ni, > - lpni_on_peer_net_list); > + lpni_peer_nis); > > return lpni; > } > > - if (prev->lpni_on_peer_net_list.next == > - &prev->lpni_peer_net->lpn_peer_nis) { > + if (prev->lpni_peer_nis.next == &prev->lpni_peer_net->lpn_peer_nis) { > /* > * if you reached the end of the peer ni list and the peer > * net is specified then there are no more peer nis in that > @@ -608,25 +671,25 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > * we reached the end of this net ni list. move to the > * next net > */ > - if (prev->lpni_peer_net->lpn_on_peer_list.next == > + if (prev->lpni_peer_net->lpn_peer_nets.next == > &peer->lp_peer_nets) > /* no more nets and no more NIs. */ > return NULL; > > /* get the next net */ > - net = list_entry(prev->lpni_peer_net->lpn_on_peer_list.next, > + net = list_entry(prev->lpni_peer_net->lpn_peer_nets.next, > struct lnet_peer_net, > - lpn_on_peer_list); > + lpn_peer_nets); > /* get the ni on it */ > lpni = list_entry(net->lpn_peer_nis.next, struct lnet_peer_ni, > - lpni_on_peer_net_list); > + lpni_peer_nis); > > return lpni; > } > > /* there are more nis left */ > - lpni = list_entry(prev->lpni_on_peer_net_list.next, > - struct lnet_peer_ni, lpni_on_peer_net_list); > + lpni = list_entry(prev->lpni_peer_nis.next, > + struct lnet_peer_ni, lpni_peer_nis); > > return lpni; > } > @@ -902,7 +965,7 @@ struct lnet_peer_net * > lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) > { > struct lnet_peer_net *peer_net; > - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { > + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { > if (peer_net->lpn_net_id == net_id) > return peer_net; > } > @@ -910,15 +973,20 @@ lnet_peer_get_net_locked(struct lnet_peer *peer, u32 net_id) > } > > /* > - * Always returns 0, but it the last function called from functions > + * Attach a peer_ni to a peer_net and peer. This function assumes > + * peer_ni is not already attached to the peer_net/peer. The peer_ni > + * may be attached to a different peer, in which case it will be > + * properly detached first. The whole operation is done atomically. > + * > + * Always returns 0. This is the last function called from functions > * that do return an int, so returning 0 here allows the compiler to > * do a tail call. > */ > static int > lnet_peer_attach_peer_ni(struct lnet_peer *lp, > - struct lnet_peer_net *lpn, > - struct lnet_peer_ni *lpni, > - unsigned int flags) > + struct lnet_peer_net *lpn, > + struct lnet_peer_ni *lpni, > + unsigned int flags) > { > struct lnet_peer_table *ptable; > > @@ -932,26 +1000,38 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, > list_add_tail(&lpni->lpni_hashlist, &ptable->pt_hash[hash]); > ptable->pt_version++; > atomic_inc(&ptable->pt_number); > + /* This is the 1st refcount on lpni. */ > atomic_inc(&lpni->lpni_refcount); > } > > /* Detach the peer_ni from an existing peer, if necessary. */ > - if (lpni->lpni_peer_net && lpni->lpni_peer_net->lpn_peer != lp) > - lnet_peer_detach_peer_ni(lpni); > + if (lpni->lpni_peer_net) { > + LASSERT(lpni->lpni_peer_net != lpn); > + LASSERT(lpni->lpni_peer_net->lpn_peer != lp); > + lnet_peer_detach_peer_ni_locked(lpni); > + lnet_peer_net_decref_locked(lpni->lpni_peer_net); > + lpni->lpni_peer_net = NULL; > + } > > /* Add peer_ni to peer_net */ > lpni->lpni_peer_net = lpn; > - list_add_tail(&lpni->lpni_on_peer_net_list, &lpn->lpn_peer_nis); > + list_add_tail(&lpni->lpni_peer_nis, &lpn->lpn_peer_nis); > + lnet_peer_net_addref_locked(lpn); > > /* Add peer_net to peer */ > if (!lpn->lpn_peer) { > lpn->lpn_peer = lp; > - list_add_tail(&lpn->lpn_on_peer_list, &lp->lp_peer_nets); > + list_add_tail(&lpn->lpn_peer_nets, &lp->lp_peer_nets); > + lnet_peer_addref_locked(lp); > + } > + > + /* Add peer to global peer list, if necessary */ > + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; > + if (list_empty(&lp->lp_peer_list)) { > + list_add_tail(&lp->lp_peer_list, &ptable->pt_peer_list); > + ptable->pt_peers++; > } > > - /* Add peer to global peer list */ > - if (list_empty(&lp->lp_on_lnet_peer_list)) > - list_add_tail(&lp->lp_on_lnet_peer_list, &the_lnet.ln_peers); > > /* Update peer state */ > spin_lock(&lp->lp_lock); > @@ -967,6 +1047,8 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, > } > spin_unlock(&lp->lp_lock); > > + lp->lp_nnis++; > + the_lnet.ln_peer_tables[lp->lp_cpt]->pt_peer_nnids++; > lnet_net_unlock(LNET_LOCK_EX); > > CDEBUG(D_NET, "peer %s NID %s flags %#x\n", > @@ -1314,12 +1396,17 @@ void > lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) > { > struct lnet_peer_table *ptable; > + struct lnet_peer_net *lpn; > + > + CDEBUG(D_NET, "%p nid %s\n", lpni, libcfs_nid2str(lpni->lpni_nid)); > > LASSERT(atomic_read(&lpni->lpni_refcount) == 0); > LASSERT(lpni->lpni_rtr_refcount == 0); > LASSERT(list_empty(&lpni->lpni_txq)); > LASSERT(lpni->lpni_txqnob == 0); > > + lpn = lpni->lpni_peer_net; > + lpni->lpni_peer_net = NULL; > lpni->lpni_net = NULL; > > /* remove the peer ni from the zombie list */ > @@ -1332,6 +1419,8 @@ lnet_destroy_peer_ni_locked(struct lnet_peer_ni *lpni) > if (lpni->lpni_pref_nnids > 1) > kfree(lpni->lpni_pref.nids); > kfree(lpni); > + > + lnet_peer_net_decref_locked(lpn); > } > > struct lnet_peer_ni * > @@ -1518,6 +1607,7 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > return found ? 0 : -ENOENT; > } > > +/* ln_api_mutex is held, which keeps the peer list stable */ > int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > bool *mr, > struct lnet_peer_ni_credit_info __user *peer_ni_info, > > > From jsimmons at infradead.org Sun Oct 14 22:44:12 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 23:44:12 +0100 (BST) Subject: [lustre-devel] [PATCH 15/24] lustre: lnet: add msg_type to lnet_event In-Reply-To: <153895437812.16383.7373974293282162856.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437812.16383.7373974293282162856.stgit@noble> Message-ID: > From: Olaf Weber > > Add a msg_type field to the lnet_event structure. This makes > it possible for an event handler to tell whether LNET_EVENT_SEND > corresponds to a GET or a PUT message. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25785 > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../lustre/include/uapi/linux/lnet/lnet-types.h | 5 +++++ > drivers/staging/lustre/lnet/lnet/lib-msg.c | 1 + > 2 files changed, 6 insertions(+) > > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > index e0e4fd259795..1ecf18e4a278 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > @@ -650,6 +650,11 @@ struct lnet_event { > * \see LNetPut > */ > __u64 hdr_data; > + /** > + * The message type, to ensure a handler for LNET_EVENT_SEND can > + * distinguish between LNET_MSG_GET and LNET_MSG_PUT. > + */ > + __u32 msg_type; > /** > * Indicates the completion status of the operation. It's 0 for > * successful operations, otherwise it's an error code. > diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c > index 1817e54a16a5..db13d01d366f 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c > @@ -63,6 +63,7 @@ lnet_build_msg_event(struct lnet_msg *msg, enum lnet_event_kind ev_type) > LASSERT(!msg->msg_routing); > > ev->type = ev_type; > + ev->msg_type = msg->msg_type; > > if (ev_type == LNET_EVENT_SEND) { > /* event for active message */ > > > From jsimmons at infradead.org Sun Oct 14 22:44:30 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 23:44:30 +0100 (BST) Subject: [lustre-devel] [PATCH 15/24] lustre: lnet: add msg_type to lnet_event In-Reply-To: <153895437812.16383.7373974293282162856.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437812.16383.7373974293282162856.stgit@noble> Message-ID: > From: Olaf Weber > > Add a msg_type field to the lnet_event structure. This makes > it possible for an event handler to tell whether LNET_EVENT_SEND > corresponds to a GET or a PUT message. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25785 > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../lustre/include/uapi/linux/lnet/lnet-types.h | 5 +++++ > drivers/staging/lustre/lnet/lnet/lib-msg.c | 1 + > 2 files changed, 6 insertions(+) > > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > index e0e4fd259795..1ecf18e4a278 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/lnet-types.h > @@ -650,6 +650,11 @@ struct lnet_event { > * \see LNetPut > */ > __u64 hdr_data; > + /** > + * The message type, to ensure a handler for LNET_EVENT_SEND can > + * distinguish between LNET_MSG_GET and LNET_MSG_PUT. > + */ > + __u32 msg_type; > /** > * Indicates the completion status of the operation. It's 0 for > * successful operations, otherwise it's an error code. > diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c > index 1817e54a16a5..db13d01d366f 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c > @@ -63,6 +63,7 @@ lnet_build_msg_event(struct lnet_msg *msg, enum lnet_event_kind ev_type) > LASSERT(!msg->msg_routing); > > ev->type = ev_type; > + ev->msg_type = msg->msg_type; > > if (ev_type == LNET_EVENT_SEND) { > /* event for active message */ > > > From jsimmons at infradead.org Sun Oct 14 22:51:53 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 23:51:53 +0100 (BST) Subject: [lustre-devel] [PATCH 16/24] lustre: lnet: add discovery thread In-Reply-To: <153895437816.16383.10343171262123774566.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437816.16383.10343171262123774566.stgit@noble> Message-ID: > From: Olaf Weber > > Add the discovery thread, which will be used to handle peer > discovery. This change adds the thread and the infrastructure > that starts and stops it. The thread itself does trivial work. > > Peer Discovery gets its own event queue (ln_dc_eqh), a queue > for peers that are to be discovered (ln_dc_request), a queue > for peers waiting for an event (ln_dc_working), a wait queue > head so the thread can sleep (ln_dc_waitq), and start/stop > state (ln_dc_state). > > Peer discovery is started from lnet_select_pathway(), for > GET and PUT messages not sent to the LNET_RESERVED_PORTAL. > This criterion means that discovery will not be triggered by > the messages used in discovery, and neither will an LNet ping > trigger it. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Signed-off-by: Amir Shehata > Reviewed-on: https://review.whamcloud.com/25786 > Reviewed-by: Olaf Weber > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 6 > .../staging/lustre/include/linux/lnet/lib-types.h | 71 ++++ > drivers/staging/lustre/lnet/lnet/api-ni.c | 31 ++ > drivers/staging/lustre/lnet/lnet/lib-move.c | 45 ++- > drivers/staging/lustre/lnet/lnet/peer.c | 325 ++++++++++++++++++++ > 5 files changed, 468 insertions(+), 10 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index aad25eb0011b..848d622911a4 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -438,6 +438,7 @@ bool lnet_is_ni_healthy_locked(struct lnet_ni *ni); > struct lnet_net *lnet_get_net_locked(u32 net_id); > > extern unsigned int lnet_numa_range; > +extern unsigned int lnet_peer_discovery_disabled; > extern int portal_rotor; > > int lnet_lib_init(void); > @@ -704,6 +705,9 @@ struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); > void lnet_peer_net_added(struct lnet_net *net); > lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); > +int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt); > +int lnet_peer_discovery_start(void); > +void lnet_peer_discovery_stop(void); > void lnet_peer_tables_cleanup(struct lnet_net *net); > void lnet_peer_uninit(void); > int lnet_peer_tables_create(void); > @@ -791,4 +795,6 @@ lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) > return lpni->lpni_nid == lpni->lpni_peer_net->lpn_peer->lp_primary_nid; > } > > +bool lnet_peer_is_uptodate(struct lnet_peer *lp); > + > #endif > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 260619e19bde..6394a3af50b7 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -520,10 +520,61 @@ struct lnet_peer { > > /* peer state flags */ > unsigned int lp_state; > + > + /* link on discovery-related lists */ > + struct list_head lp_dc_list; > + > + /* tasks waiting on discovery of this peer */ > + wait_queue_head_t lp_dc_waitq; > }; > > -#define LNET_PEER_MULTI_RAIL BIT(0) > -#define LNET_PEER_CONFIGURED BIT(1) > +/* > + * The status flags in lp_state. Their semantics have chosen so that > + * lp_state can be zero-initialized. > + * > + * A peer is marked MULTI_RAIL in two cases: it was configured using DLC > + * as multi-rail aware, or the LNET_PING_FEAT_MULTI_RAIL bit was set. > + * > + * A peer is marked NO_DISCOVERY if the LNET_PING_FEAT_DISCOVERY bit was > + * NOT set when the peer was pinged by discovery. > + */ > +#define LNET_PEER_MULTI_RAIL BIT(0) /* Multi-rail aware */ > +#define LNET_PEER_NO_DISCOVERY BIT(1) /* Peer disabled discovery */ > +/* > + * A peer is marked CONFIGURED if it was configured by DLC. > + * > + * In addition, a peer is marked DISCOVERED if it has fully passed > + * through Peer Discovery. > + * > + * When Peer Discovery is disabled, the discovery thread will mark > + * peers REDISCOVER to indicate that they should be re-examined if > + * discovery is (re)enabled on the node. > + * > + * A peer that was created as the result of inbound traffic will not > + * be marked at all. > + */ > +#define LNET_PEER_CONFIGURED BIT(2) /* Configured via DLC */ > +#define LNET_PEER_DISCOVERED BIT(3) /* Peer was discovered */ > +#define LNET_PEER_REDISCOVER BIT(4) /* Discovery was disabled */ > +/* > + * A peer is marked DISCOVERING when discovery is in progress. > + * The other flags below correspond to stages of discovery. > + */ > +#define LNET_PEER_DISCOVERING BIT(5) /* Discovering */ > +#define LNET_PEER_DATA_PRESENT BIT(6) /* Remote peer data present */ > +#define LNET_PEER_NIDS_UPTODATE BIT(7) /* Remote peer info uptodate */ > +#define LNET_PEER_PING_SENT BIT(8) /* Waiting for REPLY to Ping */ > +#define LNET_PEER_PUSH_SENT BIT(9) /* Waiting for ACK of Push */ > +#define LNET_PEER_PING_FAILED BIT(10) /* Ping send failure */ > +#define LNET_PEER_PUSH_FAILED BIT(11) /* Push send failure */ > +/* > + * A ping can be forced as a way to fix up state, or as a manual > + * intervention by an admin. > + * A push can be forced in circumstances that would normally not > + * allow for one to happen. > + */ > +#define LNET_PEER_FORCE_PING BIT(12) /* Forced Ping */ > +#define LNET_PEER_FORCE_PUSH BIT(13) /* Forced Push */ > > struct lnet_peer_net { > /* chain on lp_peer_nets */ > @@ -775,6 +826,11 @@ struct lnet_msg_container { > void **msc_finalizers; > }; > > +/* Peer Discovery states */ > +#define LNET_DC_STATE_SHUTDOWN 0 /* not started */ > +#define LNET_DC_STATE_RUNNING 1 /* started up OK */ > +#define LNET_DC_STATE_STOPPING 2 /* telling thread to stop */ > + > /* Router Checker states */ > enum lnet_rc_state { > LNET_RC_STATE_SHUTDOWN, /* not started */ > @@ -856,6 +912,17 @@ struct lnet { > struct lnet_ping_buffer *ln_ping_target; > atomic_t ln_ping_target_seqno; > > + /* discovery event queue handle */ > + struct lnet_handle_eq ln_dc_eqh; > + /* discovery requests */ > + struct list_head ln_dc_request; > + /* discovery working list */ > + struct list_head ln_dc_working; > + /* discovery thread wait queue */ > + wait_queue_head_t ln_dc_waitq; > + /* discovery startup/shutdown state */ > + int ln_dc_state; > + > /* router checker startup/shutdown state */ > enum lnet_rc_state ln_rc_state; > /* router checker's event queue */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index c48bcb8722a0..dccfd5bcc459 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -78,6 +78,13 @@ module_param_call(lnet_interfaces_max, intf_max_set, param_get_int, > MODULE_PARM_DESC(lnet_interfaces_max, > "Maximum number of interfaces in a node."); > > +unsigned int lnet_peer_discovery_disabled; > +static int discovery_set(const char *val, const struct kernel_param *kp); > +module_param_call(lnet_peer_discovery_disabled, discovery_set, param_get_int, > + &lnet_peer_discovery_disabled, 0644); > +MODULE_PARM_DESC(lnet_peer_discovery_disabled, > + "Set to 1 to disable peer discovery on this node."); > + > /* > * This sequence number keeps track of how many times DLC was used to > * update the local NIs. It is incremented when a NI is added or > @@ -90,6 +97,23 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); > static int lnet_ping(struct lnet_process_id id, signed long timeout, > struct lnet_process_id __user *ids, int n_ids); > > +static int > +discovery_set(const char *val, const struct kernel_param *kp) > +{ > + int rc; > + unsigned long value; > + > + rc = kstrtoul(val, 0, &value); > + if (rc) { > + CERROR("Invalid module parameter value for 'lnet_peer_discovery_disabled'\n"); > + return rc; > + } > + > + *(unsigned int *)kp->arg = !!value; > + > + return 0; > +} > + > static int > intf_max_set(const char *val, const struct kernel_param *kp) > { > @@ -1921,6 +1945,10 @@ LNetNIInit(lnet_pid_t requested_pid) > if (rc) > goto err_stop_ping; > > + rc = lnet_peer_discovery_start(); > + if (rc != 0) > + goto err_stop_router_checker; > + > lnet_fault_init(); > lnet_router_debugfs_init(); > > @@ -1928,6 +1956,8 @@ LNetNIInit(lnet_pid_t requested_pid) > > return 0; > > +err_stop_router_checker: > + lnet_router_checker_stop(); > err_stop_ping: > lnet_ping_target_fini(); > err_acceptor_stop: > @@ -1976,6 +2006,7 @@ LNetNIFini(void) > > lnet_fault_fini(); > lnet_router_debugfs_fini(); > + lnet_peer_discovery_stop(); > lnet_router_checker_stop(); > lnet_ping_target_fini(); > > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 4c1eef907dc7..4773180cc7b3 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -1208,6 +1208,27 @@ lnet_get_best_ni(struct lnet_net *local_net, struct lnet_ni *cur_ni, > return best_ni; > } > > +/* > + * Traffic to the LNET_RESERVED_PORTAL may not trigger peer discovery, > + * because such traffic is required to perform discovery. We therefore > + * exclude all GET and PUT on that portal. We also exclude all ACK and > + * REPLY traffic, but that is because the portal is not tracked in the > + * message structure for these message types. We could restrict this > + * further by also checking for LNET_PROTO_PING_MATCHBITS. > + */ > +static bool > +lnet_msg_discovery(struct lnet_msg *msg) > +{ > + if (msg->msg_type == LNET_MSG_PUT) { > + if (msg->msg_hdr.msg.put.ptl_index != LNET_RESERVED_PORTAL) > + return true; > + } else if (msg->msg_type == LNET_MSG_GET) { > + if (msg->msg_hdr.msg.get.ptl_index != LNET_RESERVED_PORTAL) > + return true; > + } > + return false; > +} > + > static int > lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > struct lnet_msg *msg, lnet_nid_t rtr_nid) > @@ -1220,7 +1241,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > struct lnet_peer *peer; > struct lnet_peer_net *peer_net; > struct lnet_net *local_net; > - __u32 seq; > int cpt, cpt2, rc; > bool routing; > bool routing2; > @@ -1255,13 +1275,6 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > routing2 = false; > local_found = false; > > - seq = lnet_get_dlc_seq_locked(); > - > - if (the_lnet.ln_state != LNET_STATE_RUNNING) { > - lnet_net_unlock(cpt); > - return -ESHUTDOWN; > - } > - > /* > * lnet_nid2peerni_locked() is the path that will find an > * existing peer_ni, or create one and mark it as having been > @@ -1272,7 +1285,22 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > lnet_net_unlock(cpt); > return PTR_ERR(lpni); > } > + /* > + * Now that we have a peer_ni, check if we want to discover > + * the peer. Traffic to the LNET_RESERVED_PORTAL should not > + * trigger discovery. > + */ > peer = lpni->lpni_peer_net->lpn_peer; > + if (lnet_msg_discovery(msg) && !lnet_peer_is_uptodate(peer)) { > + rc = lnet_discover_peer_locked(lpni, cpt); > + if (rc) { > + lnet_peer_ni_decref_locked(lpni); > + lnet_net_unlock(cpt); > + return rc; > + } > + /* The peer may have changed. */ > + peer = lpni->lpni_peer_net->lpn_peer; > + } > lnet_peer_ni_decref_locked(lpni); > > /* If peer is not healthy then can not send anything to it */ > @@ -1701,6 +1729,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > */ > cpt2 = lnet_cpt_of_nid_locked(best_lpni->lpni_nid, best_ni); > if (cpt != cpt2) { > + __u32 seq = lnet_get_dlc_seq_locked(); > lnet_net_unlock(cpt); > cpt = cpt2; > lnet_net_lock(cpt); > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index d7a0a2f3bdd9..038b58414ce0 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -201,6 +201,8 @@ lnet_peer_alloc(lnet_nid_t nid) > > INIT_LIST_HEAD(&lp->lp_peer_list); > INIT_LIST_HEAD(&lp->lp_peer_nets); > + INIT_LIST_HEAD(&lp->lp_dc_list); > + init_waitqueue_head(&lp->lp_dc_waitq); > spin_lock_init(&lp->lp_lock); > lp->lp_primary_nid = nid; > lp->lp_cpt = lnet_nid_cpt_hash(nid, LNET_CPT_NUMBER); > @@ -1457,6 +1459,10 @@ lnet_nid2peerni_ex(lnet_nid_t nid, int cpt) > return lpni; > } > > +/* > + * Get a peer_ni for the given nid, create it if necessary. Takes a > + * hold on the peer_ni. > + */ > struct lnet_peer_ni * > lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) > { > @@ -1510,9 +1516,326 @@ lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, int cpt) > mutex_unlock(&the_lnet.ln_api_mutex); > lnet_net_lock(cpt); > > + /* Lock has been dropped, check again for shutdown. */ > + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { > + if (!IS_ERR(lpni)) > + lnet_peer_ni_decref_locked(lpni); > + lpni = ERR_PTR(-ESHUTDOWN); > + } > + > return lpni; > } > > +/* > + * Peer Discovery > + */ > + > +/* > + * Is a peer uptodate from the point of view of discovery? > + * > + * If it is currently being processed, obviously not. > + * A forced Ping or Push is also handled by the discovery thread. > + * > + * Otherwise look at whether the peer needs rediscovering. > + */ > +bool > +lnet_peer_is_uptodate(struct lnet_peer *lp) > +{ > + bool rc; > + > + spin_lock(&lp->lp_lock); > + if (lp->lp_state & (LNET_PEER_DISCOVERING | > + LNET_PEER_FORCE_PING | > + LNET_PEER_FORCE_PUSH)) { > + rc = false; > + } else if (lp->lp_state & LNET_PEER_REDISCOVER) { > + if (lnet_peer_discovery_disabled) > + rc = true; > + else > + rc = false; > + } else if (lp->lp_state & LNET_PEER_DISCOVERED) { > + if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) > + rc = true; > + else > + rc = false; > + } else { > + rc = false; > + } > + spin_unlock(&lp->lp_lock); > + > + return rc; > +} > + > +/* > + * Queue a peer for the attention of the discovery thread. Call with > + * lnet_net_lock/EX held. Returns 0 if the peer was queued, and > + * -EALREADY if the peer was already queued. > + */ > +static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) > +{ > + int rc; > + > + spin_lock(&lp->lp_lock); > + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) > + lp->lp_state |= LNET_PEER_DISCOVERING; > + spin_unlock(&lp->lp_lock); > + if (list_empty(&lp->lp_dc_list)) { > + lnet_peer_addref_locked(lp); > + list_add_tail(&lp->lp_dc_list, &the_lnet.ln_dc_request); > + wake_up(&the_lnet.ln_dc_waitq); > + rc = 0; > + } else { > + rc = -EALREADY; > + } > + > + return rc; > +} > + > +/* > + * Discovery of a peer is complete. Wake all waiters on the peer. > + * Call with lnet_net_lock/EX held. > + */ > +static void lnet_peer_discovery_complete(struct lnet_peer *lp) > +{ > + list_del_init(&lp->lp_dc_list); > + wake_up_all(&lp->lp_dc_waitq); > + lnet_peer_decref_locked(lp); > +} > + > +/* > + * Peer discovery slow path. The ln_api_mutex is held on entry, and > + * dropped/retaken within this function. An lnet_peer_ni is passed in > + * because discovery could tear down an lnet_peer. > + */ > +int > +lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) > +{ > + DEFINE_WAIT(wait); > + struct lnet_peer *lp; > + int rc = 0; > + > +again: > + lnet_net_unlock(cpt); > + lnet_net_lock(LNET_LOCK_EX); > + > + /* We're willing to be interrupted. */ > + for (;;) { > + lp = lpni->lpni_peer_net->lpn_peer; > + prepare_to_wait(&lp->lp_dc_waitq, &wait, TASK_INTERRUPTIBLE); > + if (signal_pending(current)) > + break; > + if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) > + break; > + if (lnet_peer_is_uptodate(lp)) > + break; > + lnet_peer_queue_for_discovery(lp); > + lnet_peer_addref_locked(lp); > + lnet_net_unlock(LNET_LOCK_EX); > + schedule(); > + finish_wait(&lp->lp_dc_waitq, &wait); > + lnet_net_lock(LNET_LOCK_EX); > + lnet_peer_decref_locked(lp); > + /* Do not use lp beyond this point. */ > + } > + finish_wait(&lp->lp_dc_waitq, &wait); > + > + lnet_net_unlock(LNET_LOCK_EX); > + lnet_net_lock(cpt); > + > + if (signal_pending(current)) > + rc = -EINTR; > + else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) > + rc = -ESHUTDOWN; > + else if (!lnet_peer_is_uptodate(lp)) > + goto again; > + > + return rc; > +} > + > +/* > + * Event handler for the discovery EQ. > + * > + * Called with lnet_res_lock(cpt) held. The cpt is the > + * lnet_cpt_of_cookie() of the md handle cookie. > + */ > +static void lnet_discovery_event_handler(struct lnet_event *event) > +{ > + wake_up(&the_lnet.ln_dc_waitq); > +} > + > +/* > + * Wait for work to be queued or some other change that must be > + * attended to. Returns non-zero if the discovery thread should shut > + * down. > + */ > +static int lnet_peer_discovery_wait_for_work(void) > +{ > + int cpt; > + int rc = 0; > + > + DEFINE_WAIT(wait); > + > + cpt = lnet_net_lock_current(); > + for (;;) { > + prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, > + TASK_IDLE); > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + break; > + if (!list_empty(&the_lnet.ln_dc_request)) > + break; > + lnet_net_unlock(cpt); > + schedule(); > + finish_wait(&the_lnet.ln_dc_waitq, &wait); > + cpt = lnet_net_lock_current(); > + } > + finish_wait(&the_lnet.ln_dc_waitq, &wait); > + > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + rc = -ESHUTDOWN; > + > + lnet_net_unlock(cpt); > + > + CDEBUG(D_NET, "woken: %d\n", rc); > + > + return rc; > +} > + > +/* The discovery thread. */ > +static int lnet_peer_discovery(void *arg) > +{ > + struct lnet_peer *lp; > + > + CDEBUG(D_NET, "started\n"); > + > + for (;;) { > + if (lnet_peer_discovery_wait_for_work()) > + break; > + > + lnet_net_lock(LNET_LOCK_EX); > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + break; > + while (!list_empty(&the_lnet.ln_dc_request)) { > + lp = list_first_entry(&the_lnet.ln_dc_request, > + struct lnet_peer, lp_dc_list); > + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_working); > + lnet_net_unlock(LNET_LOCK_EX); > + > + /* Just tag and release for now. */ > + spin_lock(&lp->lp_lock); > + if (lnet_peer_discovery_disabled) { > + lp->lp_state |= LNET_PEER_REDISCOVER; > + lp->lp_state &= ~(LNET_PEER_DISCOVERED | > + LNET_PEER_NIDS_UPTODATE | > + LNET_PEER_DISCOVERING); > + } else { > + lp->lp_state |= (LNET_PEER_DISCOVERED | > + LNET_PEER_NIDS_UPTODATE); > + lp->lp_state &= ~(LNET_PEER_REDISCOVER | > + LNET_PEER_DISCOVERING); > + } > + spin_unlock(&lp->lp_lock); > + > + lnet_net_lock(LNET_LOCK_EX); > + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) > + lnet_peer_discovery_complete(lp); > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + break; > + } > + lnet_net_unlock(LNET_LOCK_EX); > + } > + > + CDEBUG(D_NET, "stopping\n"); > + /* > + * Clean up before telling lnet_peer_discovery_stop() that > + * we're done. Use wake_up() below to somewhat reduce the > + * size of the thundering herd if there are multiple threads > + * waiting on discovery of a single peer. > + */ > + LNetEQFree(the_lnet.ln_dc_eqh); > + LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); > + > + lnet_net_lock(LNET_LOCK_EX); > + list_for_each_entry(lp, &the_lnet.ln_dc_request, lp_dc_list) { > + spin_lock(&lp->lp_lock); > + lp->lp_state |= LNET_PEER_REDISCOVER; > + lp->lp_state &= ~(LNET_PEER_DISCOVERED | > + LNET_PEER_DISCOVERING | > + LNET_PEER_NIDS_UPTODATE); > + spin_unlock(&lp->lp_lock); > + lnet_peer_discovery_complete(lp); > + } > + list_for_each_entry(lp, &the_lnet.ln_dc_working, lp_dc_list) { > + spin_lock(&lp->lp_lock); > + lp->lp_state |= LNET_PEER_REDISCOVER; > + lp->lp_state &= ~(LNET_PEER_DISCOVERED | > + LNET_PEER_DISCOVERING | > + LNET_PEER_NIDS_UPTODATE); > + spin_unlock(&lp->lp_lock); > + lnet_peer_discovery_complete(lp); > + } > + lnet_net_unlock(LNET_LOCK_EX); > + > + the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; > + wake_up(&the_lnet.ln_dc_waitq); > + > + CDEBUG(D_NET, "stopped\n"); > + > + return 0; > +} > + > +/* ln_api_mutex is held on entry. */ > +int lnet_peer_discovery_start(void) > +{ > + struct task_struct *task; > + int rc; > + > + if (the_lnet.ln_dc_state != LNET_DC_STATE_SHUTDOWN) > + return -EALREADY; > + > + INIT_LIST_HEAD(&the_lnet.ln_dc_request); > + INIT_LIST_HEAD(&the_lnet.ln_dc_working); > + init_waitqueue_head(&the_lnet.ln_dc_waitq); > + > + rc = LNetEQAlloc(0, lnet_discovery_event_handler, &the_lnet.ln_dc_eqh); > + if (rc != 0) { > + CERROR("Can't allocate discovery EQ: %d\n", rc); > + return rc; > + } > + > + the_lnet.ln_dc_state = LNET_DC_STATE_RUNNING; > + task = kthread_run(lnet_peer_discovery, NULL, "lnet_discovery"); > + if (IS_ERR(task)) { > + rc = PTR_ERR(task); > + CERROR("Can't start peer discovery thread: %d\n", rc); > + > + LNetEQFree(the_lnet.ln_dc_eqh); > + LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); > + > + the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; > + } > + > + return rc; > +} > + > +/* ln_api_mutex is held on entry. */ > +void lnet_peer_discovery_stop(void) > +{ > + if (the_lnet.ln_dc_state == LNET_DC_STATE_SHUTDOWN) > + return; > + > + LASSERT(the_lnet.ln_dc_state == LNET_DC_STATE_RUNNING); > + the_lnet.ln_dc_state = LNET_DC_STATE_STOPPING; > + wake_up(&the_lnet.ln_dc_waitq); > + > + wait_event(the_lnet.ln_dc_waitq, > + the_lnet.ln_dc_state == LNET_DC_STATE_SHUTDOWN); > + > + LASSERT(list_empty(&the_lnet.ln_dc_request)); > + LASSERT(list_empty(&the_lnet.ln_dc_working)); > +} > + > +/* Debugging */ > + > void > lnet_debug_peer(lnet_nid_t nid) > { > @@ -1544,6 +1867,8 @@ lnet_debug_peer(lnet_nid_t nid) > lnet_net_unlock(cpt); > } > > +/* Gathering information for userspace. */ > + > int > lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > char aliveness[LNET_MAX_STR_LEN], > > > From jsimmons at infradead.org Sun Oct 14 22:58:34 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 14 Oct 2018 23:58:34 +0100 (BST) Subject: [lustre-devel] [PATCH 17/24] lustre: lnet: add the Push target In-Reply-To: <153895437820.16383.6069246179655761617.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437820.16383.6069246179655761617.stgit@noble> Message-ID: > From: Olaf Weber > > Peer Discovery will send a Push message (same format as an > LNet Ping) to Multi-Rail capable peers to give the peer the > list of local interfaces. > > Set up a target buffer for these pushes in the_lnet. The > size of this buffer defaults to LNET_MIN_INTERFACES, but it > is resized if required. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25788 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 8 + > .../staging/lustre/include/linux/lnet/lib-types.h | 25 +++ > drivers/staging/lustre/lnet/lnet/api-ni.c | 150 ++++++++++++++++++++ > drivers/staging/lustre/lnet/lnet/peer.c | 5 + > 4 files changed, 187 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 848d622911a4..5632e5aadf41 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -686,6 +686,14 @@ static inline int lnet_ping_buffer_numref(struct lnet_ping_buffer *pbuf) > return atomic_read(&pbuf->pb_refcnt); > } > > +static inline int lnet_push_target_resize_needed(void) > +{ > + return the_lnet.ln_push_target->pb_nnis < the_lnet.ln_push_target_nnis; > +} > + > +int lnet_push_target_resize(void); > +void lnet_peer_push_event(struct lnet_event *ev); > + > int lnet_parse_ip2nets(char **networksp, char *ip2nets); > int lnet_parse_routes(char *route_str, int *im_a_router); > int lnet_parse_networks(struct list_head *nilist, char *networks, > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 6394a3af50b7..e00c13355d43 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -521,6 +521,18 @@ struct lnet_peer { > /* peer state flags */ > unsigned int lp_state; > > + /* buffer for data pushed by peer */ > + struct lnet_ping_buffer *lp_data; > + > + /* number of NIDs for sizing push data */ > + int lp_data_nnis; > + > + /* NI config sequence number of peer */ > + __u32 lp_peer_seqno; > + > + /* Local NI config sequence number peer knows */ > + __u32 lp_node_seqno; > + > /* link on discovery-related lists */ > struct list_head lp_dc_list; > > @@ -912,6 +924,19 @@ struct lnet { > struct lnet_ping_buffer *ln_ping_target; > atomic_t ln_ping_target_seqno; > > + /* > + * Push Target > + * > + * ln_push_nnis contains the desired size of the push target. > + * The lnet_net_lock is used to handle update races. The old > + * buffer may linger a while after it has been unlinked, in > + * which case the event handler cleans up. > + */ > + struct lnet_handle_eq ln_push_target_eq; > + struct lnet_handle_md ln_push_target_md; > + struct lnet_ping_buffer *ln_push_target; > + int ln_push_target_nnis; > + > /* discovery event queue handle */ > struct lnet_handle_eq ln_dc_eqh; > /* discovery requests */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index dccfd5bcc459..e6bc54e9de71 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -1268,6 +1268,147 @@ lnet_ping_target_fini(void) > lnet_ping_target_destroy(); > } > > +/* Resize the push target. */ > +int lnet_push_target_resize(void) > +{ > + struct lnet_process_id id = { LNET_NID_ANY, LNET_PID_ANY }; > + struct lnet_md md = { NULL }; > + struct lnet_handle_me meh; > + struct lnet_handle_md mdh; > + struct lnet_handle_md old_mdh; > + struct lnet_ping_buffer *pbuf; > + struct lnet_ping_buffer *old_pbuf; > + int nnis = the_lnet.ln_push_target_nnis; > + int rc; > + > + if (nnis <= 0) { > + rc = -EINVAL; > + goto fail_return; > + } > +again: > + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); > + if (!pbuf) { > + rc = -ENOMEM; > + goto fail_return; > + } > + > + rc = LNetMEAttach(LNET_RESERVED_PORTAL, id, > + LNET_PROTO_PING_MATCHBITS, 0, > + LNET_UNLINK, LNET_INS_AFTER, > + &meh); > + if (rc) { > + CERROR("Can't create push target ME: %d\n", rc); > + goto fail_decref_pbuf; > + } > + > + /* initialize md content */ > + md.start = &pbuf->pb_info; > + md.length = LNET_PING_INFO_SIZE(nnis); > + md.threshold = LNET_MD_THRESH_INF; > + md.max_size = 0; > + md.options = LNET_MD_OP_PUT | LNET_MD_TRUNCATE | > + LNET_MD_MANAGE_REMOTE; > + md.user_ptr = pbuf; > + md.eq_handle = the_lnet.ln_push_target_eq; > + > + rc = LNetMDAttach(meh, md, LNET_RETAIN, &mdh); > + if (rc) { > + CERROR("Can't attach push MD: %d\n", rc); > + goto fail_unlink_meh; > + } > + lnet_ping_buffer_addref(pbuf); > + > + lnet_net_lock(LNET_LOCK_EX); > + old_pbuf = the_lnet.ln_push_target; > + old_mdh = the_lnet.ln_push_target_md; > + the_lnet.ln_push_target = pbuf; > + the_lnet.ln_push_target_md = mdh; > + lnet_net_unlock(LNET_LOCK_EX); > + > + if (old_pbuf) { > + LNetMDUnlink(old_mdh); > + lnet_ping_buffer_decref(old_pbuf); > + } > + > + if (nnis < the_lnet.ln_push_target_nnis) > + goto again; > + > + CDEBUG(D_NET, "nnis %d success\n", nnis); > + > + return 0; > + > +fail_unlink_meh: > + LNetMEUnlink(meh); > +fail_decref_pbuf: > + lnet_ping_buffer_decref(pbuf); > +fail_return: > + CDEBUG(D_NET, "nnis %d error %d\n", nnis, rc); > + return rc; > +} > + > +static void lnet_push_target_event_handler(struct lnet_event *ev) > +{ > + struct lnet_ping_buffer *pbuf = ev->md.user_ptr; > + > + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) > + lnet_swap_pinginfo(pbuf); > + > + if (ev->unlinked) > + lnet_ping_buffer_decref(pbuf); > +} > + > +/* Initialize the push target. */ > +static int lnet_push_target_init(void) > +{ > + int rc; > + > + if (the_lnet.ln_push_target) > + return -EALREADY; > + > + rc = LNetEQAlloc(0, lnet_push_target_event_handler, > + &the_lnet.ln_push_target_eq); > + if (rc) { > + CERROR("Can't allocated push target EQ: %d\n", rc); > + return rc; > + } > + > + /* Start at the required minimum, we'll enlarge if required. */ > + the_lnet.ln_push_target_nnis = LNET_INTERFACES_MIN; > + > + rc = lnet_push_target_resize(); > + > + if (rc) { > + LNetEQFree(the_lnet.ln_push_target_eq); > + LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq); > + } > + > + return rc; > +} > + > +/* Clean up the push target. */ > +static void lnet_push_target_fini(void) > +{ > + if (!the_lnet.ln_push_target) > + return; > + > + /* Unlink and invalidate to prevent new references. */ > + LNetMDUnlink(the_lnet.ln_push_target_md); > + LNetInvalidateMDHandle(&the_lnet.ln_push_target_md); > + > + /* Wait for the unlink to complete. */ > + while (lnet_ping_buffer_numref(the_lnet.ln_push_target) > 1) { > + CDEBUG(D_NET, "Still waiting for ping data MD to unlink\n"); > + schedule_timeout_uninterruptible(HZ); > + } > + > + lnet_ping_buffer_decref(the_lnet.ln_push_target); > + the_lnet.ln_push_target = NULL; > + the_lnet.ln_push_target_nnis = 0; > + > + LNetEQFree(the_lnet.ln_push_target_eq); > + LNetInvalidateEQHandle(&the_lnet.ln_push_target_eq); > +} > + > static int > lnet_ni_tq_credits(struct lnet_ni *ni) > { > @@ -1945,10 +2086,14 @@ LNetNIInit(lnet_pid_t requested_pid) > if (rc) > goto err_stop_ping; > > - rc = lnet_peer_discovery_start(); > + rc = lnet_push_target_init(); > if (rc != 0) > goto err_stop_router_checker; > > + rc = lnet_peer_discovery_start(); > + if (rc != 0) > + goto err_destroy_push_target; > + > lnet_fault_init(); > lnet_router_debugfs_init(); > > @@ -1956,6 +2101,8 @@ LNetNIInit(lnet_pid_t requested_pid) > > return 0; > > +err_destroy_push_target: > + lnet_push_target_fini(); > err_stop_router_checker: > lnet_router_checker_stop(); > err_stop_ping: > @@ -2007,6 +2154,7 @@ LNetNIFini(void) > lnet_fault_fini(); > lnet_router_debugfs_fini(); > lnet_peer_discovery_stop(); > + lnet_push_target_fini(); > lnet_router_checker_stop(); > lnet_ping_target_fini(); > > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 038b58414ce0..b78f99c354de 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -1681,6 +1681,8 @@ static int lnet_peer_discovery_wait_for_work(void) > TASK_IDLE); > if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > break; > + if (lnet_push_target_resize_needed()) > + break; > if (!list_empty(&the_lnet.ln_dc_request)) > break; > lnet_net_unlock(cpt); > @@ -1711,6 +1713,9 @@ static int lnet_peer_discovery(void *arg) > if (lnet_peer_discovery_wait_for_work()) > break; > > + if (lnet_push_target_resize_needed()) > + lnet_push_target_resize(); > + > lnet_net_lock(LNET_LOCK_EX); > if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > break; > > > From jsimmons at infradead.org Sun Oct 14 23:33:36 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:33:36 +0100 (BST) Subject: [lustre-devel] [PATCH 18/24] lustre: lnet: implement Peer Discovery In-Reply-To: <153895437824.16383.8664465506271547759.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437824.16383.8664465506271547759.stgit@noble> Message-ID: > From: Olaf Weber > > Implement Peer Discovery. > > A peer is queued for discovery by lnet_peer_queue_for_discovery(). > This set LNET_PEER_DISCOVERING, to indicate that discovery is in > progress. > > The discovery thread lnet_peer_discovery() checks the peer and > updates its state as appropriate. > > If LNET_PEER_DATA_PRESENT is set, then a valid Push message or > Ping reply has been received. The peer is updated in accordance > with the data, and LNET_PEER_NIDS_UPTODATE is set. > > If LNET_PEER_PING_FAILED is set, then an attempt to send a Ping > message failed, and peer state is updated accordingly. The discovery > thread can do some cleanup like unlinking an MD that cannot be done > from the message event handler. > > If LNET_PEER_PUSH_FAILED is set, then an attempt to send a Push > message failed, and peer state is updated accordingly. The discovery > thread can do some cleanup like unlinking an MD that cannot be done > from the message event handler. > > If LNET_PEER_PING_REQUIRED is set, we must Ping the peer in order to > correctly update our knowledge of it. This is set, for example, if > we receive a Push message for a peer, but cannot handle it because > the Push target was too small. In such a case we know that the > state of the peer is incorrect, but need to do extra work to obtain > the required information. > > If discovery is not enabled, then the discovery process stops here > and the peer is marked with LNET_PEER_UNDISCOVERED. This tells the > discovery process that it doesn't need to revisit the peer while > discovery remains disabled. > > If LNET_PEER_NIDS_UPTODATE is not set, then we have reason to think > the lnet_peer is not up to date, and will Ping it. > > The peer needs a Push if it is multi-rail and the ping buffer > sequence number for this node is newer than the sequence number it > has acknowledged receiving by sending an Ack of a Push. > > If none of the above is true, then discovery has completed its work > on the peer. > > Discovery signals that it is done with a peer by clearing the > LNET_PEER_DISCOVERING flag, and setting LNET_PEER_DISCOVERED or > LNET_PEER_UNDISCOVERED as appropriate. It then dequeues the peer > and clears the LNET_PEER_QUEUED flag. > > When the local node is discovered via the loopback network, the > peer structure that is created will have an lnet_peer_ni for the > local loopback interface. Subsequent traffic from this node to > itself will use the loopback net. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25789 > Reviewed-by: Olaf Weber > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 20 > .../staging/lustre/include/linux/lnet/lib-types.h | 39 + > drivers/staging/lustre/lnet/lnet/api-ni.c | 59 + > drivers/staging/lustre/lnet/lnet/lib-move.c | 18 > drivers/staging/lustre/lnet/lnet/peer.c | 1499 +++++++++++++++++++- > 5 files changed, 1543 insertions(+), 92 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 5632e5aadf41..f82a699371f2 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -76,6 +76,9 @@ extern struct lnet the_lnet; /* THE network */ > #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 > #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 > > +/* Discovery timeout - same as default peer_timeout */ > +#define DISCOVERY_TIMEOUT 180 > + > static inline int lnet_is_route_alive(struct lnet_route *route) > { > /* gateway is down */ > @@ -713,9 +716,10 @@ struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); > void lnet_peer_net_added(struct lnet_net *net); > lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); > -int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt); > +int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block); > int lnet_peer_discovery_start(void); > void lnet_peer_discovery_stop(void); > +void lnet_push_update_to_peers(int force); > void lnet_peer_tables_cleanup(struct lnet_net *net); > void lnet_peer_uninit(void); > int lnet_peer_tables_create(void); > @@ -805,4 +809,18 @@ lnet_peer_ni_is_primary(struct lnet_peer_ni *lpni) > > bool lnet_peer_is_uptodate(struct lnet_peer *lp); > > +static inline bool > +lnet_peer_needs_push(struct lnet_peer *lp) > +{ > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) > + return false; > + if (lp->lp_state & LNET_PEER_FORCE_PUSH) > + return true; > + if (lp->lp_state & LNET_PEER_NO_DISCOVERY) > + return false; > + if (lp->lp_node_seqno < atomic_read(&the_lnet.ln_ping_target_seqno)) > + return true; > + return false; > +} > + > #endif > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index e00c13355d43..07baa86e61ab 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -67,6 +67,13 @@ struct lnet_msg { > lnet_nid_t msg_from; > __u32 msg_type; > > + /* > + * hold parameters in case message is with held due > + * to discovery > + */ > + lnet_nid_t msg_src_nid_param; > + lnet_nid_t msg_rtr_nid_param; > + > /* committed for sending */ > unsigned int msg_tx_committed:1; > /* CPT # this message committed for sending */ > @@ -395,6 +402,8 @@ struct lnet_ping_buffer { > #define LNET_PING_BUFFER_LONI(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_nid) > #define LNET_PING_BUFFER_SEQNO(PBUF) ((PBUF)->pb_info.pi_ni[0].ns_status) > > +#define LNET_PING_INFO_TO_BUFFER(PINFO) \ > + container_of((PINFO), struct lnet_ping_buffer, pb_info) > > /* router checker data, per router */ > struct lnet_rc_data { > @@ -503,6 +512,9 @@ struct lnet_peer { > /* list of peer nets */ > struct list_head lp_peer_nets; > > + /* list of messages pending discovery*/ > + struct list_head lp_dc_pendq; > + > /* primary NID of the peer */ > lnet_nid_t lp_primary_nid; > > @@ -524,15 +536,36 @@ struct lnet_peer { > /* buffer for data pushed by peer */ > struct lnet_ping_buffer *lp_data; > > + /* MD handle for ping in progress */ > + struct lnet_handle_md lp_ping_mdh; > + > + /* MD handle for push in progress */ > + struct lnet_handle_md lp_push_mdh; > + > /* number of NIDs for sizing push data */ > int lp_data_nnis; > > /* NI config sequence number of peer */ > __u32 lp_peer_seqno; > > - /* Local NI config sequence number peer knows */ > + /* Local NI config sequence number acked by peer */ > __u32 lp_node_seqno; > > + /* Local NI config sequence number sent to peer */ > + __u32 lp_node_seqno_sent; > + > + /* Ping error encountered during discovery. */ > + int lp_ping_error; > + > + /* Push error encountered during discovery. */ > + int lp_push_error; > + > + /* Error encountered during discovery. */ > + int lp_dc_error; > + > + /* time it was put on the ln_dc_working queue */ > + time64_t lp_last_queued; > + > /* link on discovery-related lists */ > struct list_head lp_dc_list; > > @@ -691,6 +724,8 @@ struct lnet_remotenet { > #define LNET_CREDIT_OK 0 > /** lnet message is waiting for credit */ > #define LNET_CREDIT_WAIT 1 > +/** lnet message is waiting for discovery */ > +#define LNET_DC_WAIT 2 > > struct lnet_rtrbufpool { > struct list_head rbp_bufs; /* my free buffer pool */ > @@ -943,6 +978,8 @@ struct lnet { > struct list_head ln_dc_request; > /* discovery working list */ > struct list_head ln_dc_working; > + /* discovery expired list */ > + struct list_head ln_dc_expired; > /* discovery thread wait queue */ > wait_queue_head_t ln_dc_waitq; > /* discovery startup/shutdown state */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index e6bc54e9de71..955d1711eda4 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -41,7 +41,14 @@ > > #define D_LNI D_CONSOLE > > -struct lnet the_lnet; /* THE state of the network */ > +/* > + * initialize ln_api_mutex statically, since it needs to be used in > + * discovery_set callback. That module parameter callback can be called > + * before module init completes. The mutex needs to be ready for use then. > + */ > +struct lnet the_lnet = { > + .ln_api_mutex = __MUTEX_INITIALIZER(the_lnet.ln_api_mutex), > +}; /* THE state of the network */ > EXPORT_SYMBOL(the_lnet); > > static char *ip2nets = ""; > @@ -101,7 +108,9 @@ static int > discovery_set(const char *val, const struct kernel_param *kp) > { > int rc; > + unsigned int *discovery = (unsigned int *)kp->arg; > unsigned long value; > + struct lnet_ping_buffer *pbuf; > > rc = kstrtoul(val, 0, &value); > if (rc) { > @@ -109,7 +118,38 @@ discovery_set(const char *val, const struct kernel_param *kp) > return rc; > } > > - *(unsigned int *)kp->arg = !!value; > + value = !!value; > + > + /* > + * The purpose of locking the api_mutex here is to ensure that > + * the correct value ends up stored properly. > + */ > + mutex_lock(&the_lnet.ln_api_mutex); > + > + if (value == *discovery) { > + mutex_unlock(&the_lnet.ln_api_mutex); > + return 0; > + } > + > + *discovery = value; > + > + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { > + mutex_unlock(&the_lnet.ln_api_mutex); > + return 0; > + } > + > + /* tell peers that discovery setting has changed */ > + lnet_net_lock(LNET_LOCK_EX); > + pbuf = the_lnet.ln_ping_target; > + if (value) > + pbuf->pb_info.pi_features &= ~LNET_PING_FEAT_DISCOVERY; > + else > + pbuf->pb_info.pi_features |= LNET_PING_FEAT_DISCOVERY; > + lnet_net_unlock(LNET_LOCK_EX); > + > + lnet_push_update_to_peers(1); > + > + mutex_unlock(&the_lnet.ln_api_mutex); > > return 0; > } > @@ -171,7 +211,6 @@ lnet_init_locks(void) > init_waitqueue_head(&the_lnet.ln_eq_waitq); > init_waitqueue_head(&the_lnet.ln_rc_waitq); > mutex_init(&the_lnet.ln_lnd_mutex); > - mutex_init(&the_lnet.ln_api_mutex); > } > > static int > @@ -654,6 +693,10 @@ lnet_prepare(lnet_pid_t requested_pid) > INIT_LIST_HEAD(&the_lnet.ln_routers); > INIT_LIST_HEAD(&the_lnet.ln_drop_rules); > INIT_LIST_HEAD(&the_lnet.ln_delay_rules); > + INIT_LIST_HEAD(&the_lnet.ln_dc_request); > + INIT_LIST_HEAD(&the_lnet.ln_dc_working); > + INIT_LIST_HEAD(&the_lnet.ln_dc_expired); > + init_waitqueue_head(&the_lnet.ln_dc_waitq); > > rc = lnet_create_remote_nets_table(); > if (rc) > @@ -998,7 +1041,8 @@ lnet_ping_target_create(int nnis) > pbuf->pb_info.pi_nnis = nnis; > pbuf->pb_info.pi_pid = the_lnet.ln_pid; > pbuf->pb_info.pi_magic = LNET_PROTO_PING_MAGIC; > - pbuf->pb_info.pi_features = LNET_PING_FEAT_NI_STATUS; > + pbuf->pb_info.pi_features = > + LNET_PING_FEAT_NI_STATUS | LNET_PING_FEAT_MULTI_RAIL; > > return pbuf; > } > @@ -1231,6 +1275,8 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, > > if (!the_lnet.ln_routing) > pbuf->pb_info.pi_features |= LNET_PING_FEAT_RTE_DISABLED; > + if (!lnet_peer_discovery_disabled) > + pbuf->pb_info.pi_features |= LNET_PING_FEAT_DISCOVERY; > > /* Ensure only known feature bits have been set. */ > LASSERT(pbuf->pb_info.pi_features & LNET_PING_FEAT_BITS); > @@ -1252,6 +1298,8 @@ lnet_ping_target_update(struct lnet_ping_buffer *pbuf, > lnet_ping_md_unlink(old_pbuf, &old_ping_md); > lnet_ping_buffer_decref(old_pbuf); > } > + > + lnet_push_update_to_peers(0); > } > > static void > @@ -1353,6 +1401,7 @@ static void lnet_push_target_event_handler(struct lnet_event *ev) > if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) > lnet_swap_pinginfo(pbuf); > > + lnet_peer_push_event(ev); > if (ev->unlinked) > lnet_ping_buffer_decref(pbuf); > } > @@ -1910,8 +1959,6 @@ int lnet_lib_init(void) > > lnet_assert_wire_constants(); > > - memset(&the_lnet, 0, sizeof(the_lnet)); > - > /* refer to global cfs_cpt_tab for now */ > the_lnet.ln_cpt_table = cfs_cpt_tab; > the_lnet.ln_cpt_number = cfs_cpt_number(cfs_cpt_tab); > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 4773180cc7b3..2ff329bf91ba 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -444,6 +444,8 @@ lnet_prep_send(struct lnet_msg *msg, int type, struct lnet_process_id target, > > memset(&msg->msg_hdr, 0, sizeof(msg->msg_hdr)); > msg->msg_hdr.type = cpu_to_le32(type); > + /* dest_nid will be overwritten by lnet_select_pathway() */ > + msg->msg_hdr.dest_nid = cpu_to_le64(target.nid); > msg->msg_hdr.dest_pid = cpu_to_le32(target.pid); > /* src_nid will be set later */ > msg->msg_hdr.src_pid = cpu_to_le32(the_lnet.ln_pid); > @@ -1292,7 +1294,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > */ > peer = lpni->lpni_peer_net->lpn_peer; > if (lnet_msg_discovery(msg) && !lnet_peer_is_uptodate(peer)) { > - rc = lnet_discover_peer_locked(lpni, cpt); > + rc = lnet_discover_peer_locked(lpni, cpt, false); > if (rc) { > lnet_peer_ni_decref_locked(lpni); > lnet_net_unlock(cpt); > @@ -1300,6 +1302,18 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, > } > /* The peer may have changed. */ > peer = lpni->lpni_peer_net->lpn_peer; > + /* queue message and return */ > + msg->msg_src_nid_param = src_nid; > + msg->msg_rtr_nid_param = rtr_nid; > + msg->msg_sending = 0; > + list_add_tail(&msg->msg_list, &peer->lp_dc_pendq); > + lnet_peer_ni_decref_locked(lpni); > + lnet_net_unlock(cpt); > + > + CDEBUG(D_NET, "%s pending discovery\n", > + libcfs_nid2str(peer->lp_primary_nid)); > + > + return LNET_DC_WAIT; > } > lnet_peer_ni_decref_locked(lpni); > > @@ -1840,7 +1854,7 @@ lnet_send(lnet_nid_t src_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid) > if (rc == LNET_CREDIT_OK) > lnet_ni_send(msg->msg_txni, msg); > > - /* rc == LNET_CREDIT_OK or LNET_CREDIT_WAIT */ > + /* rc == LNET_CREDIT_OK or LNET_CREDIT_WAIT or LNET_DC_WAIT */ > return 0; > } > > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index b78f99c354de..1ef4a44e752e 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -38,6 +38,11 @@ > #include > #include > > +/* Value indicating that recovery needs to re-check a peer immediately. */ > +#define LNET_REDISCOVER_PEER (1) > + > +static int lnet_peer_queue_for_discovery(struct lnet_peer *lp); > + > static void > lnet_peer_remove_from_remote_list(struct lnet_peer_ni *lpni) > { > @@ -202,6 +207,7 @@ lnet_peer_alloc(lnet_nid_t nid) > INIT_LIST_HEAD(&lp->lp_peer_list); > INIT_LIST_HEAD(&lp->lp_peer_nets); > INIT_LIST_HEAD(&lp->lp_dc_list); > + INIT_LIST_HEAD(&lp->lp_dc_pendq); > init_waitqueue_head(&lp->lp_dc_waitq); > spin_lock_init(&lp->lp_lock); > lp->lp_primary_nid = nid; > @@ -220,6 +226,10 @@ lnet_destroy_peer_locked(struct lnet_peer *lp) > LASSERT(atomic_read(&lp->lp_refcount) == 0); > LASSERT(list_empty(&lp->lp_peer_nets)); > LASSERT(list_empty(&lp->lp_peer_list)); > + LASSERT(list_empty(&lp->lp_dc_list)); > + > + if (lp->lp_data) > + lnet_ping_buffer_decref(lp->lp_data); > > kfree(lp); > } > @@ -260,10 +270,19 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) > /* > * If there are no more peer nets, make the peer unfindable > * via the peer_tables. > + * > + * Otherwise, if the peer is DISCOVERED, tell discovery to > + * take another look at it. This is a no-op if discovery for > + * this peer did the detaching. > */ > if (list_empty(&lp->lp_peer_nets)) { > list_del_init(&lp->lp_peer_list); > ptable->pt_peers--; > + } else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) { > + /* Discovery isn't running, nothing to do here. */ > + } else if (lp->lp_state & LNET_PEER_DISCOVERED) { > + lnet_peer_queue_for_discovery(lp); > + wake_up(&the_lnet.ln_dc_waitq); > } > CDEBUG(D_NET, "peer %s NID %s\n", > libcfs_nid2str(lp->lp_primary_nid), > @@ -599,6 +618,25 @@ lnet_find_peer_ni_locked(lnet_nid_t nid) > return lpni; > } > > +struct lnet_peer * > +lnet_find_peer(lnet_nid_t nid) > +{ > + struct lnet_peer_ni *lpni; > + struct lnet_peer *lp = NULL; > + int cpt; > + > + cpt = lnet_net_lock_current(); > + lpni = lnet_find_peer_ni_locked(nid); > + if (lpni) { > + lp = lpni->lpni_peer_net->lpn_peer; > + lnet_peer_addref_locked(lp); > + lnet_peer_ni_decref_locked(lpni); > + } > + lnet_net_unlock(cpt); > + > + return lp; > +} > + > struct lnet_peer_ni * > lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, > struct lnet_peer **lp) > @@ -696,6 +734,37 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > return lpni; > } > > +/* > + * Start pushes to peers that need to be updated for a configuration > + * change on this node. > + */ > +void > +lnet_push_update_to_peers(int force) > +{ > + struct lnet_peer_table *ptable; > + struct lnet_peer *lp; > + int lncpt; > + int cpt; > + > + lnet_net_lock(LNET_LOCK_EX); > + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); > + for (cpt = 0; cpt < lncpt; cpt++) { > + ptable = the_lnet.ln_peer_tables[cpt]; > + list_for_each_entry(lp, &ptable->pt_peer_list, lp_peer_list) { > + if (force) { > + spin_lock(&lp->lp_lock); > + if (lp->lp_state & LNET_PEER_MULTI_RAIL) > + lp->lp_state |= LNET_PEER_FORCE_PUSH; > + spin_unlock(&lp->lp_lock); > + } > + if (lnet_peer_needs_push(lp)) > + lnet_peer_queue_for_discovery(lp); > + } > + } > + lnet_net_unlock(LNET_LOCK_EX); > + wake_up(&the_lnet.ln_dc_waitq); > +} > + > /* > * Test whether a ni is a preferred ni for this peer_ni, e.g, whether > * this is a preferred point-to-point path. Call with lnet_net_lock in > @@ -941,6 +1010,7 @@ lnet_peer_primary_nid_locked(lnet_nid_t nid) > lnet_nid_t > LNetPrimaryNID(lnet_nid_t nid) > { > + struct lnet_peer *lp; > struct lnet_peer_ni *lpni; > lnet_nid_t primary_nid = nid; > int rc = 0; > @@ -952,7 +1022,15 @@ LNetPrimaryNID(lnet_nid_t nid) > rc = PTR_ERR(lpni); > goto out_unlock; > } > - primary_nid = lpni->lpni_peer_net->lpn_peer->lp_primary_nid; > + lp = lpni->lpni_peer_net->lpn_peer; > + while (!lnet_peer_is_uptodate(lp)) { > + rc = lnet_discover_peer_locked(lpni, cpt, true); > + if (rc) > + goto out_decref; > + lp = lpni->lpni_peer_net->lpn_peer; > + } > + primary_nid = lp->lp_primary_nid; > +out_decref: > lnet_peer_ni_decref_locked(lpni); > out_unlock: > lnet_net_unlock(cpt); > @@ -1229,6 +1307,30 @@ lnet_peer_add_nid(struct lnet_peer *lp, lnet_nid_t nid, unsigned int flags) > return rc; > } > > +/* > + * Update the primary NID of a peer, if possible. > + * > + * Call with the lnet_api_mutex held. > + */ > +static int > +lnet_peer_set_primary_nid(struct lnet_peer *lp, lnet_nid_t nid, > + unsigned int flags) > +{ > + lnet_nid_t old = lp->lp_primary_nid; > + int rc = 0; > + > + if (lp->lp_primary_nid == nid) > + goto out; > + rc = lnet_peer_add_nid(lp, nid, flags); > + if (rc) > + goto out; > + lp->lp_primary_nid = nid; > +out: > + CDEBUG(D_NET, "peer %s NID %s: %d\n", > + libcfs_nid2str(old), libcfs_nid2str(nid), rc); > + return rc; > +} > + > /* > * lpni creation initiated due to traffic either sending or receiving. > */ > @@ -1548,11 +1650,15 @@ lnet_peer_is_uptodate(struct lnet_peer *lp) > LNET_PEER_FORCE_PING | > LNET_PEER_FORCE_PUSH)) { > rc = false; > + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { > + rc = true; > } else if (lp->lp_state & LNET_PEER_REDISCOVER) { > if (lnet_peer_discovery_disabled) > rc = true; > else > rc = false; > + } else if (lnet_peer_needs_push(lp)) { > + rc = false; > } else if (lp->lp_state & LNET_PEER_DISCOVERED) { > if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) > rc = true; > @@ -1588,6 +1694,9 @@ static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) > rc = -EALREADY; > } > > + CDEBUG(D_NET, "Queue peer %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), rc); > + > return rc; > } > > @@ -1597,9 +1706,252 @@ static int lnet_peer_queue_for_discovery(struct lnet_peer *lp) > */ > static void lnet_peer_discovery_complete(struct lnet_peer *lp) > { > + struct lnet_msg *msg = NULL; > + int rc = 0; > + struct list_head pending_msgs; > + > + INIT_LIST_HEAD(&pending_msgs); > + > + CDEBUG(D_NET, "Discovery complete. Dequeue peer %s\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + > list_del_init(&lp->lp_dc_list); > + list_splice_init(&lp->lp_dc_pendq, &pending_msgs); > wake_up_all(&lp->lp_dc_waitq); > + > + lnet_net_unlock(LNET_LOCK_EX); > + > + /* iterate through all pending messages and send them again */ > + list_for_each_entry(msg, &pending_msgs, msg_list) { > + if (lp->lp_dc_error) { > + lnet_finalize(msg, lp->lp_dc_error); > + continue; > + } > + > + CDEBUG(D_NET, "sending pending message %s to target %s\n", > + lnet_msgtyp2str(msg->msg_type), > + libcfs_id2str(msg->msg_target)); > + rc = lnet_send(msg->msg_src_nid_param, msg, > + msg->msg_rtr_nid_param); > + if (rc < 0) { > + CNETERR("Error sending %s to %s: %d\n", > + lnet_msgtyp2str(msg->msg_type), > + libcfs_id2str(msg->msg_target), rc); > + lnet_finalize(msg, rc); > + } > + } > + lnet_net_lock(LNET_LOCK_EX); > + lnet_peer_decref_locked(lp); > +} > + > +/* > + * Handle inbound push. > + * Like any event handler, called with lnet_res_lock/CPT held. > + */ > +void lnet_peer_push_event(struct lnet_event *ev) > +{ > + struct lnet_ping_buffer *pbuf = ev->md.user_ptr; > + struct lnet_peer *lp; > + > + /* lnet_find_peer() adds a refcount */ > + lp = lnet_find_peer(ev->source.nid); > + if (!lp) { > + CERROR("Push Put from unknown %s (source %s)\n", > + libcfs_nid2str(ev->initiator.nid), > + libcfs_nid2str(ev->source.nid)); > + return; > + } > + > + /* Ensure peer state remains consistent while we modify it. */ > + spin_lock(&lp->lp_lock); > + > + /* > + * If some kind of error happened the contents of the message > + * cannot be used. Clear the NIDS_UPTODATE and set the > + * FORCE_PING flag to trigger a ping. > + */ > + if (ev->status) { > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + lp->lp_state |= LNET_PEER_FORCE_PING; > + CDEBUG(D_NET, "Push Put error %d from %s (source %s)\n", > + ev->status, > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(ev->source.nid)); > + goto out; > + } > + > + /* > + * A push with invalid or corrupted info. Clear the UPTODATE > + * flag to trigger a ping. > + */ > + if (lnet_ping_info_validate(&pbuf->pb_info)) { > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + lp->lp_state |= LNET_PEER_FORCE_PING; > + CDEBUG(D_NET, "Corrupted Push from %s\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + goto out; > + } > + > + /* > + * Make sure we'll allocate the correct size ping buffer when > + * pinging the peer. > + */ > + if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis) > + lp->lp_data_nnis = pbuf->pb_info.pi_nnis; > + > + /* > + * A non-Multi-Rail peer is not supposed to be capable of > + * sending a push. > + */ > + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL)) { > + CERROR("Push from non-Multi-Rail peer %s dropped\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + goto out; > + } > + > + /* > + * Check the MULTIRAIL flag. Complain if the peer was DLC > + * configured without it. > + */ > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + if (lp->lp_state & LNET_PEER_CONFIGURED) { > + CERROR("Push says %s is Multi-Rail, DLC says not\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + } else { > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > + } > + } > + > + /* > + * The peer may have discovery disabled at its end. Set > + * NO_DISCOVERY as appropriate. > + */ > + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_DISCOVERY)) { > + CDEBUG(D_NET, "Peer %s has discovery disabled\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + lp->lp_state |= LNET_PEER_NO_DISCOVERY; > + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { > + CDEBUG(D_NET, "Peer %s has discovery enabled\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + lp->lp_state &= ~LNET_PEER_NO_DISCOVERY; > + } > + > + /* > + * Check for truncation of the Put message. Clear the > + * NIDS_UPTODATE flag and set FORCE_PING to trigger a ping, > + * and tell discovery to allocate a bigger buffer. > + */ > + if (pbuf->pb_nnis < pbuf->pb_info.pi_nnis) { > + if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis) > + the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis; > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + lp->lp_state |= LNET_PEER_FORCE_PING; > + CDEBUG(D_NET, "Truncated Push from %s (%d nids)\n", > + libcfs_nid2str(lp->lp_primary_nid), > + pbuf->pb_info.pi_nnis); > + goto out; > + } > + > + /* > + * Check whether the Put data is stale. Stale data can just be > + * dropped. > + */ > + if (pbuf->pb_info.pi_nnis > 1 && > + lp->lp_primary_nid == pbuf->pb_info.pi_ni[1].ns_nid && > + LNET_PING_BUFFER_SEQNO(pbuf) < lp->lp_peer_seqno) { > + CDEBUG(D_NET, "Stale Push from %s: got %u have %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf), > + lp->lp_peer_seqno); > + goto out; > + } > + > + /* > + * Check whether the Put data is new, in which case we clear > + * the UPTODATE flag and prepare to process it. > + * > + * If the Put data is current, and the peer is UPTODATE then > + * we assome everything is all right and drop the data as > + * stale. > + */ > + if (LNET_PING_BUFFER_SEQNO(pbuf) > lp->lp_peer_seqno) { > + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + } else if (lp->lp_state & LNET_PEER_NIDS_UPTODATE) { > + CDEBUG(D_NET, "Stale Push from %s: got %u have %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf), > + lp->lp_peer_seqno); > + goto out; > + } > + > + /* > + * If there is data present that hasn't been processed yet, > + * we'll replace it if the Put contained newer data and it > + * fits. We're racing with a Ping or earlier Push in this > + * case. > + */ > + if (lp->lp_state & LNET_PEER_DATA_PRESENT) { > + if (LNET_PING_BUFFER_SEQNO(pbuf) > > + LNET_PING_BUFFER_SEQNO(lp->lp_data) && > + pbuf->pb_info.pi_nnis <= lp->lp_data->pb_nnis) { > + memcpy(&lp->lp_data->pb_info, &pbuf->pb_info, > + LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis)); > + CDEBUG(D_NET, "Ping/Push race from %s: %u vs %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf), > + LNET_PING_BUFFER_SEQNO(lp->lp_data)); > + } > + goto out; > + } > + > + /* > + * Allocate a buffer to copy the data. On a failure we drop > + * the Push and set FORCE_PING to force the discovery > + * thread to fix the problem by pinging the peer. > + */ > + lp->lp_data = lnet_ping_buffer_alloc(lp->lp_data_nnis, GFP_ATOMIC); > + if (!lp->lp_data) { > + lp->lp_state |= LNET_PEER_FORCE_PING; > + CDEBUG(D_NET, "Cannot allocate Push buffer for %s %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf)); > + goto out; > + } > + > + /* Success */ > + memcpy(&lp->lp_data->pb_info, &pbuf->pb_info, > + LNET_PING_INFO_SIZE(pbuf->pb_info.pi_nnis)); > + lp->lp_state |= LNET_PEER_DATA_PRESENT; > + CDEBUG(D_NET, "Received Push %s %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf)); > + > +out: > + /* > + * Queue the peer for discovery, and wake the discovery thread > + * if the peer was already queued, because its status changed. > + */ > + spin_unlock(&lp->lp_lock); > + lnet_net_lock(LNET_LOCK_EX); > + if (lnet_peer_queue_for_discovery(lp)) > + wake_up(&the_lnet.ln_dc_waitq); > + /* Drop refcount from lookup */ > lnet_peer_decref_locked(lp); > + lnet_net_unlock(LNET_LOCK_EX); > +} > + > +/* > + * Clear the discovery error state, unless we're already discovering > + * this peer, in which case the error is current. > + */ > +static void lnet_peer_clear_discovery_error(struct lnet_peer *lp) > +{ > + spin_lock(&lp->lp_lock); > + if (!(lp->lp_state & LNET_PEER_DISCOVERING)) > + lp->lp_dc_error = 0; > + spin_unlock(&lp->lp_lock); > } > > /* > @@ -1608,7 +1960,7 @@ static void lnet_peer_discovery_complete(struct lnet_peer *lp) > * because discovery could tear down an lnet_peer. > */ > int > -lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) > +lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) > { > DEFINE_WAIT(wait); > struct lnet_peer *lp; > @@ -1617,25 +1969,40 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) > again: > lnet_net_unlock(cpt); > lnet_net_lock(LNET_LOCK_EX); > + lp = lpni->lpni_peer_net->lpn_peer; > + lnet_peer_clear_discovery_error(lp); > > - /* We're willing to be interrupted. */ > + /* > + * We're willing to be interrupted. The lpni can become a > + * zombie if we race with DLC, so we must check for that. > + */ > for (;;) { > - lp = lpni->lpni_peer_net->lpn_peer; > prepare_to_wait(&lp->lp_dc_waitq, &wait, TASK_INTERRUPTIBLE); > if (signal_pending(current)) > break; > if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) > break; > + if (lp->lp_dc_error) > + break; > if (lnet_peer_is_uptodate(lp)) > break; > lnet_peer_queue_for_discovery(lp); > lnet_peer_addref_locked(lp); > + /* > + * if caller requested a non-blocking operation then > + * return immediately. Once discovery is complete then the > + * peer ref will be decremented and any pending messages > + * that were stopped due to discovery will be transmitted. > + */ > + if (!block) > + break; > lnet_net_unlock(LNET_LOCK_EX); > schedule(); > finish_wait(&lp->lp_dc_waitq, &wait); > lnet_net_lock(LNET_LOCK_EX); > lnet_peer_decref_locked(lp); > - /* Do not use lp beyond this point. */ > + /* Peer may have changed */ > + lp = lpni->lpni_peer_net->lpn_peer; > } > finish_wait(&lp->lp_dc_waitq, &wait); > > @@ -1646,71 +2013,969 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt) > rc = -EINTR; > else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) > rc = -ESHUTDOWN; > + else if (lp->lp_dc_error) > + rc = lp->lp_dc_error; > + else if (!block) > + CDEBUG(D_NET, "non-blocking discovery\n"); > else if (!lnet_peer_is_uptodate(lp)) > goto again; > > + CDEBUG(D_NET, "peer %s NID %s: %d. %s\n", > + (lp ? libcfs_nid2str(lp->lp_primary_nid) : "(none)"), > + libcfs_nid2str(lpni->lpni_nid), rc, > + (!block) ? "pending discovery" : "discovery complete"); > + > return rc; > } > > -/* > - * Event handler for the discovery EQ. > - * > - * Called with lnet_res_lock(cpt) held. The cpt is the > - * lnet_cpt_of_cookie() of the md handle cookie. > - */ > -static void lnet_discovery_event_handler(struct lnet_event *event) > +/* Handle an incoming ack for a push. */ > +static void > +lnet_discovery_event_ack(struct lnet_peer *lp, struct lnet_event *ev) > { > - wake_up(&the_lnet.ln_dc_waitq); > + struct lnet_ping_buffer *pbuf; > + > + pbuf = LNET_PING_INFO_TO_BUFFER(ev->md.start); > + spin_lock(&lp->lp_lock); > + lp->lp_state &= ~LNET_PEER_PUSH_SENT; > + lp->lp_push_error = ev->status; > + if (ev->status) > + lp->lp_state |= LNET_PEER_PUSH_FAILED; > + else > + lp->lp_node_seqno = LNET_PING_BUFFER_SEQNO(pbuf); > + spin_unlock(&lp->lp_lock); > + > + CDEBUG(D_NET, "peer %s ev->status %d\n", > + libcfs_nid2str(lp->lp_primary_nid), ev->status); > } > > -/* > - * Wait for work to be queued or some other change that must be > - * attended to. Returns non-zero if the discovery thread should shut > - * down. > - */ > -static int lnet_peer_discovery_wait_for_work(void) > +/* Handle a Reply message. This is the reply to a Ping message. */ > +static void > +lnet_discovery_event_reply(struct lnet_peer *lp, struct lnet_event *ev) > { > - int cpt; > - int rc = 0; > + struct lnet_ping_buffer *pbuf; > + int rc; > > - DEFINE_WAIT(wait); > + spin_lock(&lp->lp_lock); > > - cpt = lnet_net_lock_current(); > - for (;;) { > - prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, > - TASK_IDLE); > - if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > - break; > - if (lnet_push_target_resize_needed()) > - break; > - if (!list_empty(&the_lnet.ln_dc_request)) > - break; > - lnet_net_unlock(cpt); > - schedule(); > - finish_wait(&the_lnet.ln_dc_waitq, &wait); > - cpt = lnet_net_lock_current(); > + /* > + * If some kind of error happened the contents of message > + * cannot be used. Set PING_FAILED to trigger a retry. > + */ > + if (ev->status) { > + lp->lp_state |= LNET_PEER_PING_FAILED; > + lp->lp_ping_error = ev->status; > + CDEBUG(D_NET, "Ping Reply error %d from %s (source %s)\n", > + ev->status, > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(ev->source.nid)); > + goto out; > } > - finish_wait(&the_lnet.ln_dc_waitq, &wait); > - > - if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > - rc = -ESHUTDOWN; > > - lnet_net_unlock(cpt); > + pbuf = LNET_PING_INFO_TO_BUFFER(ev->md.start); > + if (pbuf->pb_info.pi_magic == __swab32(LNET_PROTO_PING_MAGIC)) > + lnet_swap_pinginfo(pbuf); > > - CDEBUG(D_NET, "woken: %d\n", rc); > + /* > + * A reply with invalid or corrupted info. Set PING_FAILED to > + * trigger a retry. > + */ > + rc = lnet_ping_info_validate(&pbuf->pb_info); > + if (rc) { > + lp->lp_state |= LNET_PEER_PING_FAILED; > + lp->lp_ping_error = 0; > + CDEBUG(D_NET, "Corrupted Ping Reply from %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), rc); > + goto out; > + } > > - return rc; > -} > + /* > + * Update the MULTI_RAIL flag based on the reply. If the peer > + * was configured with DLC then the setting should match what > + * DLC put in. > + */ > + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) { > + if (lp->lp_state & LNET_PEER_MULTI_RAIL) { > + /* Everything's fine */ > + } else if (lp->lp_state & LNET_PEER_CONFIGURED) { > + CWARN("Reply says %s is Multi-Rail, DLC says not\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + } else { > + lp->lp_state |= LNET_PEER_MULTI_RAIL; > + lnet_peer_clr_non_mr_pref_nids(lp); > + } > + } else if (lp->lp_state & LNET_PEER_MULTI_RAIL) { > + if (lp->lp_state & LNET_PEER_CONFIGURED) { > + CWARN("DLC says %s is Multi-Rail, Reply says not\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + } else { > + CERROR("Multi-Rail state vanished from %s\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + lp->lp_state &= ~LNET_PEER_MULTI_RAIL; > + } > + } > > -/* The discovery thread. */ > -static int lnet_peer_discovery(void *arg) > -{ > - struct lnet_peer *lp; > + /* > + * Make sure we'll allocate the correct size ping buffer when > + * pinging the peer. > + */ > + if (lp->lp_data_nnis < pbuf->pb_info.pi_nnis) > + lp->lp_data_nnis = pbuf->pb_info.pi_nnis; > > - CDEBUG(D_NET, "started\n"); > + /* > + * The peer may have discovery disabled at its end. Set > + * NO_DISCOVERY as appropriate. > + */ > + if (!(pbuf->pb_info.pi_features & LNET_PING_FEAT_DISCOVERY)) { > + CDEBUG(D_NET, "Peer %s has discovery disabled\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + lp->lp_state |= LNET_PEER_NO_DISCOVERY; > + } else if (lp->lp_state & LNET_PEER_NO_DISCOVERY) { > + CDEBUG(D_NET, "Peer %s has discovery enabled\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + lp->lp_state &= ~LNET_PEER_NO_DISCOVERY; > + } > > - for (;;) { > - if (lnet_peer_discovery_wait_for_work()) > + /* > + * Check for truncation of the Reply. Clear PING_SENT and set > + * PING_FAILED to trigger a retry. > + */ > + if (pbuf->pb_nnis < pbuf->pb_info.pi_nnis) { > + if (the_lnet.ln_push_target_nnis < pbuf->pb_info.pi_nnis) > + the_lnet.ln_push_target_nnis = pbuf->pb_info.pi_nnis; > + lp->lp_state |= LNET_PEER_PING_FAILED; > + lp->lp_ping_error = 0; > + CDEBUG(D_NET, "Truncated Reply from %s (%d nids)\n", > + libcfs_nid2str(lp->lp_primary_nid), > + pbuf->pb_info.pi_nnis); > + goto out; > + } > + > + /* > + * Check the sequence numbers in the reply. These are only > + * available if the reply came from a Multi-Rail peer. > + */ > + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL && > + pbuf->pb_info.pi_nnis > 1 && > + lp->lp_primary_nid == pbuf->pb_info.pi_ni[1].ns_nid) { > + if (LNET_PING_BUFFER_SEQNO(pbuf) < lp->lp_peer_seqno) { > + CDEBUG(D_NET, "Stale Reply from %s: got %u have %u\n", > + libcfs_nid2str(lp->lp_primary_nid), > + LNET_PING_BUFFER_SEQNO(pbuf), > + lp->lp_peer_seqno); > + goto out; > + } > + > + if (LNET_PING_BUFFER_SEQNO(pbuf) > lp->lp_peer_seqno) > + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); > + } > + > + /* We're happy with the state of the data in the buffer. */ > + CDEBUG(D_NET, "peer %s data present %u\n", > + libcfs_nid2str(lp->lp_primary_nid), lp->lp_peer_seqno); > + if (lp->lp_state & LNET_PEER_DATA_PRESENT) > + lnet_ping_buffer_decref(lp->lp_data); > + else > + lp->lp_state |= LNET_PEER_DATA_PRESENT; > + lnet_ping_buffer_addref(pbuf); > + lp->lp_data = pbuf; > +out: > + lp->lp_state &= ~LNET_PEER_PING_SENT; > + spin_unlock(&lp->lp_lock); > +} > + > +/* > + * Send event handling. Only matters for error cases, where we clean > + * up state on the peer and peer_ni that would otherwise be updated in > + * the REPLY event handler for a successful Ping, and the ACK event > + * handler for a successful Push. > + */ > +static int > +lnet_discovery_event_send(struct lnet_peer *lp, struct lnet_event *ev) > +{ > + int rc = 0; > + > + if (!ev->status) > + goto out; > + > + spin_lock(&lp->lp_lock); > + if (ev->msg_type == LNET_MSG_GET) { > + lp->lp_state &= ~LNET_PEER_PING_SENT; > + lp->lp_state |= LNET_PEER_PING_FAILED; > + lp->lp_ping_error = ev->status; > + } else { /* ev->msg_type == LNET_MSG_PUT */ > + lp->lp_state &= ~LNET_PEER_PUSH_SENT; > + lp->lp_state |= LNET_PEER_PUSH_FAILED; > + lp->lp_push_error = ev->status; > + } > + spin_unlock(&lp->lp_lock); > + rc = LNET_REDISCOVER_PEER; > +out: > + CDEBUG(D_NET, "%s Send to %s: %d\n", > + (ev->msg_type == LNET_MSG_GET ? "Ping" : "Push"), > + libcfs_nid2str(ev->target.nid), rc); > + return rc; > +} > + > +/* > + * Unlink event handling. This event is only seen if a call to > + * LNetMDUnlink() caused the event to be unlinked. If this call was > + * made after the event was set up in LNetGet() or LNetPut() then we > + * assume the Ping or Push timed out. > + */ > +static void > +lnet_discovery_event_unlink(struct lnet_peer *lp, struct lnet_event *ev) > +{ > + spin_lock(&lp->lp_lock); > + /* We've passed through LNetGet() */ > + if (lp->lp_state & LNET_PEER_PING_SENT) { > + lp->lp_state &= ~LNET_PEER_PING_SENT; > + lp->lp_state |= LNET_PEER_PING_FAILED; > + lp->lp_ping_error = -ETIMEDOUT; > + CDEBUG(D_NET, "Ping Unlink for message to peer %s\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + } > + /* We've passed through LNetPut() */ > + if (lp->lp_state & LNET_PEER_PUSH_SENT) { > + lp->lp_state &= ~LNET_PEER_PUSH_SENT; > + lp->lp_state |= LNET_PEER_PUSH_FAILED; > + lp->lp_push_error = -ETIMEDOUT; > + CDEBUG(D_NET, "Push Unlink for message to peer %s\n", > + libcfs_nid2str(lp->lp_primary_nid)); > + } > + spin_unlock(&lp->lp_lock); > +} > + > +/* > + * Event handler for the discovery EQ. > + * > + * Called with lnet_res_lock(cpt) held. The cpt is the > + * lnet_cpt_of_cookie() of the md handle cookie. > + */ > +static void lnet_discovery_event_handler(struct lnet_event *event) > +{ > + struct lnet_peer *lp = event->md.user_ptr; > + struct lnet_ping_buffer *pbuf; > + int rc; > + > + /* discovery needs to take another look */ > + rc = LNET_REDISCOVER_PEER; > + > + CDEBUG(D_NET, "Received event: %d\n", event->type); > + > + switch (event->type) { > + case LNET_EVENT_ACK: > + lnet_discovery_event_ack(lp, event); > + break; > + case LNET_EVENT_REPLY: > + lnet_discovery_event_reply(lp, event); > + break; > + case LNET_EVENT_SEND: > + /* Only send failure triggers a retry. */ > + rc = lnet_discovery_event_send(lp, event); > + break; > + case LNET_EVENT_UNLINK: > + /* LNetMDUnlink() was called */ > + lnet_discovery_event_unlink(lp, event); > + break; > + default: > + /* Invalid events. */ > + LBUG(); > + } > + lnet_net_lock(LNET_LOCK_EX); > + if (event->unlinked) { > + pbuf = LNET_PING_INFO_TO_BUFFER(event->md.start); > + lnet_ping_buffer_decref(pbuf); > + lnet_peer_decref_locked(lp); > + } > + if (rc == LNET_REDISCOVER_PEER) { > + list_move_tail(&lp->lp_dc_list, &the_lnet.ln_dc_request); > + wake_up(&the_lnet.ln_dc_waitq); > + } > + lnet_net_unlock(LNET_LOCK_EX); > +} > + > +/* > + * Build a peer from incoming data. > + * > + * The NIDs in the incoming data are supposed to be structured as follows: > + * - loopback > + * - primary NID > + * - other NIDs in same net > + * - NIDs in second net > + * - NIDs in third net > + * - ... > + * This due to the way the list of NIDs in the data is created. > + * > + * Note that this function will mark the peer uptodate unless an > + * ENOMEM is encontered. All other errors are due to a conflict > + * between the DLC configuration and what discovery sees. We treat DLC > + * as binding, and therefore set the NIDS_UPTODATE flag to prevent the > + * peer from becoming stuck in discovery. > + */ > +static int lnet_peer_merge_data(struct lnet_peer *lp, > + struct lnet_ping_buffer *pbuf) > +{ > + struct lnet_peer_ni *lpni; > + lnet_nid_t *curnis = NULL; > + lnet_nid_t *addnis = NULL; > + lnet_nid_t *delnis = NULL; > + unsigned int flags; > + int ncurnis; > + int naddnis; > + int ndelnis; > + int nnis = 0; > + int i; > + int j; > + int rc; > + > + flags = LNET_PEER_DISCOVERED; > + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) > + flags |= LNET_PEER_MULTI_RAIL; > + > + nnis = max_t(int, lp->lp_nnis, pbuf->pb_info.pi_nnis); > + curnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); > + addnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); > + delnis = kmalloc_array(nnis, sizeof(lnet_nid_t), GFP_NOFS); > + if (!curnis || !addnis || !delnis) { > + rc = -ENOMEM; > + goto out; > + } > + ncurnis = 0; > + naddnis = 0; > + ndelnis = 0; > + > + /* Construct the list of NIDs present in peer. */ > + lpni = NULL; > + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) > + curnis[ncurnis++] = lpni->lpni_nid; > + > + /* > + * Check for NIDs in pbuf not present in curnis[]. > + * The loop starts at 1 to skip the loopback NID. > + */ > + for (i = 1; i < pbuf->pb_info.pi_nnis; i++) { > + for (j = 0; j < ncurnis; j++) > + if (pbuf->pb_info.pi_ni[i].ns_nid == curnis[j]) > + break; > + if (j == ncurnis) > + addnis[naddnis++] = pbuf->pb_info.pi_ni[i].ns_nid; > + } > + /* > + * Check for NIDs in curnis[] not present in pbuf. > + * The nested loop starts at 1 to skip the loopback NID. > + * > + * But never add the loopback NID to delnis[]: if it is > + * present in curnis[] then this peer is for this node. > + */ > + for (i = 0; i < ncurnis; i++) { > + if (LNET_NETTYP(LNET_NIDNET(curnis[i])) == LOLND) > + continue; > + for (j = 1; j < pbuf->pb_info.pi_nnis; j++) > + if (curnis[i] == pbuf->pb_info.pi_ni[j].ns_nid) > + break; > + if (j == pbuf->pb_info.pi_nnis) > + delnis[ndelnis++] = curnis[i]; > + } > + > + for (i = 0; i < naddnis; i++) { > + rc = lnet_peer_add_nid(lp, addnis[i], flags); > + if (rc) { > + CERROR("Error adding NID %s to peer %s: %d\n", > + libcfs_nid2str(addnis[i]), > + libcfs_nid2str(lp->lp_primary_nid), rc); > + if (rc == -ENOMEM) > + goto out; > + } > + } > + for (i = 0; i < ndelnis; i++) { > + rc = lnet_peer_del_nid(lp, delnis[i], flags); > + if (rc) { > + CERROR("Error deleting NID %s from peer %s: %d\n", > + libcfs_nid2str(delnis[i]), > + libcfs_nid2str(lp->lp_primary_nid), rc); > + if (rc == -ENOMEM) > + goto out; > + } > + } > + /* > + * Errors other than -ENOMEM are due to peers having been > + * configured with DLC. Ignore these because DLC overrides > + * Discovery. > + */ > + rc = 0; > +out: > + kfree(curnis); > + kfree(addnis); > + kfree(delnis); > + lnet_ping_buffer_decref(pbuf); > + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); > + > + if (rc) { > + spin_lock(&lp->lp_lock); > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + lp->lp_state |= LNET_PEER_FORCE_PING; > + spin_unlock(&lp->lp_lock); > + } > + return rc; > +} > + > +/* > + * The data in pbuf says lp is its primary peer, but the data was > + * received by a different peer. Try to update lp with the data. > + */ > +static int > +lnet_peer_set_primary_data(struct lnet_peer *lp, struct lnet_ping_buffer *pbuf) > +{ > + struct lnet_handle_md mdh; > + > + /* Queue lp for discovery, and force it on the request queue. */ > + lnet_net_lock(LNET_LOCK_EX); > + if (lnet_peer_queue_for_discovery(lp)) > + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_request); > + lnet_net_unlock(LNET_LOCK_EX); > + > + LNetInvalidateMDHandle(&mdh); > + > + /* > + * Decide whether we can move the peer to the DATA_PRESENT state. > + * > + * We replace stale data for a multi-rail peer, repair PING_FAILED > + * status, and preempt FORCE_PING. > + * > + * If after that we have DATA_PRESENT, we merge it into this peer. > + */ > + spin_lock(&lp->lp_lock); > + if (lp->lp_state & LNET_PEER_MULTI_RAIL) { > + if (lp->lp_peer_seqno < LNET_PING_BUFFER_SEQNO(pbuf)) { > + lp->lp_peer_seqno = LNET_PING_BUFFER_SEQNO(pbuf); > + } else if (lp->lp_state & LNET_PEER_DATA_PRESENT) { > + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; > + lnet_ping_buffer_decref(pbuf); > + pbuf = lp->lp_data; > + lp->lp_data = NULL; > + } > + } > + if (lp->lp_state & LNET_PEER_DATA_PRESENT) { > + lnet_ping_buffer_decref(lp->lp_data); > + lp->lp_data = NULL; > + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; > + } > + if (lp->lp_state & LNET_PEER_PING_FAILED) { > + mdh = lp->lp_ping_mdh; > + LNetInvalidateMDHandle(&lp->lp_ping_mdh); > + lp->lp_state &= ~LNET_PEER_PING_FAILED; > + lp->lp_ping_error = 0; > + } > + if (lp->lp_state & LNET_PEER_FORCE_PING) > + lp->lp_state &= ~LNET_PEER_FORCE_PING; > + lp->lp_state |= LNET_PEER_NIDS_UPTODATE; > + spin_unlock(&lp->lp_lock); > + > + if (!LNetMDHandleIsInvalid(mdh)) > + LNetMDUnlink(mdh); > + > + if (pbuf) > + return lnet_peer_merge_data(lp, pbuf); > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + return 0; > +} > + > +/* > + * Update a peer using the data received. > + */ > +static int lnet_peer_data_present(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + struct lnet_ping_buffer *pbuf; > + struct lnet_peer_ni *lpni; > + lnet_nid_t nid = LNET_NID_ANY; > + unsigned int flags; > + int rc = 0; > + > + pbuf = lp->lp_data; > + lp->lp_data = NULL; > + lp->lp_state &= ~LNET_PEER_DATA_PRESENT; > + lp->lp_state |= LNET_PEER_NIDS_UPTODATE; > + spin_unlock(&lp->lp_lock); > + > + /* > + * Modifications of peer structures are done while holding the > + * ln_api_mutex. A global lock is required because we may be > + * modifying multiple peer structures, and a mutex greatly > + * simplifies memory management. > + * > + * The actual changes to the data structures must also protect > + * against concurrent lookups, for which the lnet_net_lock in > + * LNET_LOCK_EX mode is used. > + */ > + mutex_lock(&the_lnet.ln_api_mutex); > + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) { > + rc = -ESHUTDOWN; > + goto out; > + } > + > + /* > + * If this peer is not on the peer list then it is being torn > + * down, and our reference count may be all that is keeping it > + * alive. Don't do any work on it. > + */ > + if (list_empty(&lp->lp_peer_list)) > + goto out; > + > + flags = LNET_PEER_DISCOVERED; > + if (pbuf->pb_info.pi_features & LNET_PING_FEAT_MULTI_RAIL) > + flags |= LNET_PEER_MULTI_RAIL; > + > + /* > + * Check whether the primary NID in the message matches the > + * primary NID of the peer. If it does, update the peer, if > + * it it does not, check whether there is already a peer with > + * that primary NID. If no such peer exists, try to update > + * the primary NID of the current peer (allowed if it was > + * created due to message traffic) and complete the update. > + * If the peer did exist, hand off the data to it. > + * > + * The peer for the loopback interface is a special case: this > + * is the peer for the local node, and we want to set its > + * primary NID to the correct value here. > + */ > + if (pbuf->pb_info.pi_nnis > 1) > + nid = pbuf->pb_info.pi_ni[1].ns_nid; > + if (LNET_NETTYP(LNET_NIDNET(lp->lp_primary_nid)) == LOLND) { > + rc = lnet_peer_set_primary_nid(lp, nid, flags); > + if (!rc) > + rc = lnet_peer_merge_data(lp, pbuf); > + } else if (lp->lp_primary_nid == nid) { > + rc = lnet_peer_merge_data(lp, pbuf); > + } else { > + lpni = lnet_find_peer_ni_locked(nid); > + if (!lpni) { > + rc = lnet_peer_set_primary_nid(lp, nid, flags); > + if (rc) { > + CERROR("Primary NID error %s versus %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), > + libcfs_nid2str(nid), rc); > + } else { > + rc = lnet_peer_merge_data(lp, pbuf); > + } > + } else { > + rc = lnet_peer_set_primary_data( > + lpni->lpni_peer_net->lpn_peer, pbuf); > + lnet_peer_ni_decref_locked(lpni); > + } > + } > +out: > + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); > + mutex_unlock(&the_lnet.ln_api_mutex); > + > + spin_lock(&lp->lp_lock); > + /* Tell discovery to re-check the peer immediately. */ > + if (!rc) > + rc = LNET_REDISCOVER_PEER; > + return rc; > +} > + > +/* > + * A ping failed. Clear the PING_FAILED state and set the > + * FORCE_PING state, to ensure a retry even if discovery is > + * disabled. This avoids being left with incorrect state. > + */ > +static int lnet_peer_ping_failed(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + struct lnet_handle_md mdh; > + int rc; > + > + mdh = lp->lp_ping_mdh; > + LNetInvalidateMDHandle(&lp->lp_ping_mdh); > + lp->lp_state &= ~LNET_PEER_PING_FAILED; > + lp->lp_state |= LNET_PEER_FORCE_PING; > + rc = lp->lp_ping_error; > + lp->lp_ping_error = 0; > + spin_unlock(&lp->lp_lock); > + > + if (!LNetMDHandleIsInvalid(mdh)) > + LNetMDUnlink(mdh); > + > + CDEBUG(D_NET, "peer %s:%d\n", > + libcfs_nid2str(lp->lp_primary_nid), rc); > + > + spin_lock(&lp->lp_lock); > + return rc ? rc : LNET_REDISCOVER_PEER; > +} > + > +/* > + * Select NID to send a Ping or Push to. > + */ > +static lnet_nid_t lnet_peer_select_nid(struct lnet_peer *lp) > +{ > + struct lnet_peer_ni *lpni; > + > + /* Look for a direct-connected NID for this peer. */ > + lpni = NULL; > + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { > + if (!lnet_is_peer_ni_healthy_locked(lpni)) > + continue; > + if (!lnet_get_net_locked(lpni->lpni_peer_net->lpn_net_id)) > + continue; > + break; > + } > + if (lpni) > + return lpni->lpni_nid; > + > + /* Look for a routed-connected NID for this peer. */ > + lpni = NULL; > + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { > + if (!lnet_is_peer_ni_healthy_locked(lpni)) > + continue; > + if (!lnet_find_rnet_locked(lpni->lpni_peer_net->lpn_net_id)) > + continue; > + break; > + } > + if (lpni) > + return lpni->lpni_nid; > + > + return LNET_NID_ANY; > +} > + > +/* Active side of ping. */ > +static int lnet_peer_send_ping(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + struct lnet_md md = { NULL }; > + struct lnet_process_id id; > + struct lnet_ping_buffer *pbuf; > + int nnis; > + int rc; > + int cpt; > + > + lp->lp_state |= LNET_PEER_PING_SENT; > + lp->lp_state &= ~LNET_PEER_FORCE_PING; > + spin_unlock(&lp->lp_lock); > + > + nnis = max_t(int, lp->lp_data_nnis, LNET_INTERFACES_MIN); > + pbuf = lnet_ping_buffer_alloc(nnis, GFP_NOFS); > + if (!pbuf) { > + rc = -ENOMEM; > + goto fail_error; > + } > + > + /* initialize md content */ > + md.start = &pbuf->pb_info; > + md.length = LNET_PING_INFO_SIZE(nnis); > + md.threshold = 2; /* GET/REPLY */ > + md.max_size = 0; > + md.options = LNET_MD_TRUNCATE; > + md.user_ptr = lp; > + md.eq_handle = the_lnet.ln_dc_eqh; > + > + rc = LNetMDBind(md, LNET_UNLINK, &lp->lp_ping_mdh); > + if (rc != 0) { > + lnet_ping_buffer_decref(pbuf); > + CERROR("Can't bind MD: %d\n", rc); > + goto fail_error; > + } > + cpt = lnet_net_lock_current(); > + /* Refcount for MD. */ > + lnet_peer_addref_locked(lp); > + id.pid = LNET_PID_LUSTRE; > + id.nid = lnet_peer_select_nid(lp); > + lnet_net_unlock(cpt); > + > + if (id.nid == LNET_NID_ANY) { > + rc = -EHOSTUNREACH; > + goto fail_unlink_md; > + } > + > + rc = LNetGet(LNET_NID_ANY, lp->lp_ping_mdh, id, > + LNET_RESERVED_PORTAL, > + LNET_PROTO_PING_MATCHBITS, 0); > + > + if (rc) > + goto fail_unlink_md; > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + > + spin_lock(&lp->lp_lock); > + return 0; > + > +fail_unlink_md: > + LNetMDUnlink(lp->lp_ping_mdh); > + LNetInvalidateMDHandle(&lp->lp_ping_mdh); > +fail_error: > + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); > + /* > + * The errors that get us here are considered hard errors and > + * cause Discovery to terminate. So we clear PING_SENT, but do > + * not set either PING_FAILED or FORCE_PING. In fact we need > + * to clear PING_FAILED, because the unlink event handler will > + * have set it if we called LNetMDUnlink() above. > + */ > + spin_lock(&lp->lp_lock); > + lp->lp_state &= ~(LNET_PEER_PING_SENT | LNET_PEER_PING_FAILED); > + return rc; > +} > + > +/* > + * This function exists because you cannot call LNetMDUnlink() from an > + * event handler. > + */ > +static int lnet_peer_push_failed(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + struct lnet_handle_md mdh; > + int rc; > + > + mdh = lp->lp_push_mdh; > + LNetInvalidateMDHandle(&lp->lp_push_mdh); > + lp->lp_state &= ~LNET_PEER_PUSH_FAILED; > + rc = lp->lp_push_error; > + lp->lp_push_error = 0; > + spin_unlock(&lp->lp_lock); > + > + if (!LNetMDHandleIsInvalid(mdh)) > + LNetMDUnlink(mdh); > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + spin_lock(&lp->lp_lock); > + return rc ? rc : LNET_REDISCOVER_PEER; > +} > + > +/* Active side of push. */ > +static int lnet_peer_send_push(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + struct lnet_ping_buffer *pbuf; > + struct lnet_process_id id; > + struct lnet_md md; > + int cpt; > + int rc; > + > + /* Don't push to a non-multi-rail peer. */ > + if (!(lp->lp_state & LNET_PEER_MULTI_RAIL)) { > + lp->lp_state &= ~LNET_PEER_FORCE_PUSH; > + return 0; > + } > + > + lp->lp_state |= LNET_PEER_PUSH_SENT; > + lp->lp_state &= ~LNET_PEER_FORCE_PUSH; > + spin_unlock(&lp->lp_lock); > + > + cpt = lnet_net_lock_current(); > + pbuf = the_lnet.ln_ping_target; > + lnet_ping_buffer_addref(pbuf); > + lnet_net_unlock(cpt); > + > + /* Push source MD */ > + md.start = &pbuf->pb_info; > + md.length = LNET_PING_INFO_SIZE(pbuf->pb_nnis); > + md.threshold = 2; /* Put/Ack */ > + md.max_size = 0; > + md.options = 0; > + md.eq_handle = the_lnet.ln_dc_eqh; > + md.user_ptr = lp; > + > + rc = LNetMDBind(md, LNET_UNLINK, &lp->lp_push_mdh); > + if (rc) { > + lnet_ping_buffer_decref(pbuf); > + CERROR("Can't bind push source MD: %d\n", rc); > + goto fail_error; > + } > + cpt = lnet_net_lock_current(); > + /* Refcount for MD. */ > + lnet_peer_addref_locked(lp); > + id.pid = LNET_PID_LUSTRE; > + id.nid = lnet_peer_select_nid(lp); > + lnet_net_unlock(cpt); > + > + if (id.nid == LNET_NID_ANY) { > + rc = -EHOSTUNREACH; > + goto fail_unlink; > + } > + > + rc = LNetPut(LNET_NID_ANY, lp->lp_push_mdh, > + LNET_ACK_REQ, id, LNET_RESERVED_PORTAL, > + LNET_PROTO_PING_MATCHBITS, 0, 0); > + > + if (rc) > + goto fail_unlink; > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + > + spin_lock(&lp->lp_lock); > + return 0; > + > +fail_unlink: > + LNetMDUnlink(lp->lp_push_mdh); > + LNetInvalidateMDHandle(&lp->lp_push_mdh); > +fail_error: > + CDEBUG(D_NET, "peer %s: %d\n", libcfs_nid2str(lp->lp_primary_nid), rc); > + /* > + * The errors that get us here are considered hard errors and > + * cause Discovery to terminate. So we clear PUSH_SENT, but do > + * not set PUSH_FAILED. In fact we need to clear PUSH_FAILED, > + * because the unlink event handler will have set it if we > + * called LNetMDUnlink() above. > + */ > + spin_lock(&lp->lp_lock); > + lp->lp_state &= ~(LNET_PEER_PUSH_SENT | LNET_PEER_PUSH_FAILED); > + return rc; > +} > + > +/* > + * An unrecoverable error was encountered during discovery. > + * Set error status in peer and abort discovery. > + */ > +static void lnet_peer_discovery_error(struct lnet_peer *lp, int error) > +{ > + CDEBUG(D_NET, "Discovery error %s: %d\n", > + libcfs_nid2str(lp->lp_primary_nid), error); > + > + spin_lock(&lp->lp_lock); > + lp->lp_dc_error = error; > + lp->lp_state &= ~LNET_PEER_DISCOVERING; > + lp->lp_state |= LNET_PEER_REDISCOVER; > + spin_unlock(&lp->lp_lock); > +} > + > +/* > + * Mark the peer as discovered. > + */ > +static int lnet_peer_discovered(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + lp->lp_state |= LNET_PEER_DISCOVERED; > + lp->lp_state &= ~(LNET_PEER_DISCOVERING | > + LNET_PEER_REDISCOVER); > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + > + return 0; > +} > + > +/* > + * Mark the peer as to be rediscovered. > + */ > +static int lnet_peer_rediscover(struct lnet_peer *lp) > +__must_hold(&lp->lp_lock) > +{ > + lp->lp_state |= LNET_PEER_REDISCOVER; > + lp->lp_state &= ~LNET_PEER_DISCOVERING; > + > + CDEBUG(D_NET, "peer %s\n", libcfs_nid2str(lp->lp_primary_nid)); > + > + return 0; > +} > + > +/* > + * Returns the first peer on the ln_dc_working queue if its timeout > + * has expired. Takes the current time as an argument so as to not > + * obsessively re-check the clock. The oldest discovery request will > + * be at the head of the queue. > + */ > +static struct lnet_peer *lnet_peer_dc_timed_out(time64_t now) > +{ > + struct lnet_peer *lp; > + > + if (list_empty(&the_lnet.ln_dc_working)) > + return NULL; > + lp = list_first_entry(&the_lnet.ln_dc_working, > + struct lnet_peer, lp_dc_list); > + if (now < lp->lp_last_queued + DISCOVERY_TIMEOUT) > + return NULL; > + return lp; > +} > + > +/* > + * Discovering this peer is taking too long. Cancel any Ping or Push > + * that discovery is waiting on by unlinking the relevant MDs. The > + * lnet_discovery_event_handler() will proceed from here and complete > + * the cleanup. > + */ > +static void lnet_peer_discovery_timeout(struct lnet_peer *lp) > +{ > + struct lnet_handle_md ping_mdh; > + struct lnet_handle_md push_mdh; > + > + LNetInvalidateMDHandle(&ping_mdh); > + LNetInvalidateMDHandle(&push_mdh); > + > + spin_lock(&lp->lp_lock); > + if (lp->lp_state & LNET_PEER_PING_SENT) { > + ping_mdh = lp->lp_ping_mdh; > + LNetInvalidateMDHandle(&lp->lp_ping_mdh); > + } > + if (lp->lp_state & LNET_PEER_PUSH_SENT) { > + push_mdh = lp->lp_push_mdh; > + LNetInvalidateMDHandle(&lp->lp_push_mdh); > + } > + spin_unlock(&lp->lp_lock); > + > + if (!LNetMDHandleIsInvalid(ping_mdh)) > + LNetMDUnlink(ping_mdh); > + if (!LNetMDHandleIsInvalid(push_mdh)) > + LNetMDUnlink(push_mdh); > +} > + > +/* > + * Wait for work to be queued or some other change that must be > + * attended to. Returns non-zero if the discovery thread should shut > + * down. > + */ > +static int lnet_peer_discovery_wait_for_work(void) > +{ > + int cpt; > + int rc = 0; > + > + DEFINE_WAIT(wait); > + > + cpt = lnet_net_lock_current(); > + for (;;) { > + prepare_to_wait(&the_lnet.ln_dc_waitq, &wait, > + TASK_IDLE); > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + break; > + if (lnet_push_target_resize_needed()) > + break; > + if (!list_empty(&the_lnet.ln_dc_request)) > + break; > + if (lnet_peer_dc_timed_out(ktime_get_real_seconds())) > + break; > + lnet_net_unlock(cpt); > + > + /* > + * wakeup max every second to check if there are peers that > + * have been stuck on the working queue for greater than > + * the peer timeout. > + */ > + schedule_timeout(HZ); > + finish_wait(&the_lnet.ln_dc_waitq, &wait); > + cpt = lnet_net_lock_current(); > + } > + finish_wait(&the_lnet.ln_dc_waitq, &wait); > + > + if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > + rc = -ESHUTDOWN; > + > + lnet_net_unlock(cpt); > + > + CDEBUG(D_NET, "woken: %d\n", rc); > + > + return rc; > +} > + > +/* The discovery thread. */ > +static int lnet_peer_discovery(void *arg) > +{ > + struct lnet_peer *lp; > + time64_t now; > + int rc; > + > + CDEBUG(D_NET, "started\n"); > + > + for (;;) { > + if (lnet_peer_discovery_wait_for_work()) > break; > > if (lnet_push_target_resize_needed()) > @@ -1719,33 +2984,97 @@ static int lnet_peer_discovery(void *arg) > lnet_net_lock(LNET_LOCK_EX); > if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > break; > + > + /* > + * Process all incoming discovery work requests. When > + * discovery must wait on a peer to change state, it > + * is added to the tail of the ln_dc_working queue. A > + * timestamp keeps track of when the peer was added, > + * so we can time out discovery requests that take too > + * long. > + */ > while (!list_empty(&the_lnet.ln_dc_request)) { > lp = list_first_entry(&the_lnet.ln_dc_request, > struct lnet_peer, lp_dc_list); > list_move(&lp->lp_dc_list, &the_lnet.ln_dc_working); > + /* > + * set the time the peer was put on the dc_working > + * queue. It shouldn't remain on the queue > + * forever, in case the GET message (for ping) > + * doesn't get a REPLY or the PUT message (for > + * push) doesn't get an ACK. > + * > + * TODO: LNet Health will deal with this scenario > + * in a generic way. > + */ > + lp->lp_last_queued = ktime_get_real_seconds(); > lnet_net_unlock(LNET_LOCK_EX); > > - /* Just tag and release for now. */ > + /* > + * Select an action depending on the state of > + * the peer and whether discovery is disabled. > + * The check whether discovery is disabled is > + * done after the code that handles processing > + * for arrived data, cleanup for failures, and > + * forcing a Ping or Push. > + */ > spin_lock(&lp->lp_lock); > - if (lnet_peer_discovery_disabled) { > - lp->lp_state |= LNET_PEER_REDISCOVER; > - lp->lp_state &= ~(LNET_PEER_DISCOVERED | > - LNET_PEER_NIDS_UPTODATE | > - LNET_PEER_DISCOVERING); > - } else { > - lp->lp_state |= (LNET_PEER_DISCOVERED | > - LNET_PEER_NIDS_UPTODATE); > - lp->lp_state &= ~(LNET_PEER_REDISCOVER | > - LNET_PEER_DISCOVERING); > - } > + CDEBUG(D_NET, "peer %s state %#x\n", > + libcfs_nid2str(lp->lp_primary_nid), > + lp->lp_state); > + if (lp->lp_state & LNET_PEER_DATA_PRESENT) > + rc = lnet_peer_data_present(lp); > + else if (lp->lp_state & LNET_PEER_PING_FAILED) > + rc = lnet_peer_ping_failed(lp); > + else if (lp->lp_state & LNET_PEER_PUSH_FAILED) > + rc = lnet_peer_push_failed(lp); > + else if (lp->lp_state & LNET_PEER_FORCE_PING) > + rc = lnet_peer_send_ping(lp); > + else if (lp->lp_state & LNET_PEER_FORCE_PUSH) > + rc = lnet_peer_send_push(lp); > + else if (lnet_peer_discovery_disabled) > + rc = lnet_peer_rediscover(lp); > + else if (!(lp->lp_state & LNET_PEER_NIDS_UPTODATE)) > + rc = lnet_peer_send_ping(lp); > + else if (lnet_peer_needs_push(lp)) > + rc = lnet_peer_send_push(lp); > + else > + rc = lnet_peer_discovered(lp); > + CDEBUG(D_NET, "peer %s state %#x rc %d\n", > + libcfs_nid2str(lp->lp_primary_nid), > + lp->lp_state, rc); > spin_unlock(&lp->lp_lock); > > lnet_net_lock(LNET_LOCK_EX); > + if (rc == LNET_REDISCOVER_PEER) { > + list_move(&lp->lp_dc_list, > + &the_lnet.ln_dc_request); > + } else if (rc) { > + lnet_peer_discovery_error(lp, rc); > + } > if (!(lp->lp_state & LNET_PEER_DISCOVERING)) > lnet_peer_discovery_complete(lp); > if (the_lnet.ln_dc_state == LNET_DC_STATE_STOPPING) > break; > } > + > + /* > + * Now that the ln_dc_request queue has been emptied > + * check the ln_dc_working queue for peers that are > + * taking too long. Move all that are found to the > + * ln_dc_expired queue and time out any pending > + * Ping or Push. We have to drop the lnet_net_lock > + * in the loop because lnet_peer_discovery_timeout() > + * calls LNetMDUnlink(). > + */ > + now = ktime_get_real_seconds(); > + while ((lp = lnet_peer_dc_timed_out(now)) != NULL) { > + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_expired); > + lnet_net_unlock(LNET_LOCK_EX); > + lnet_peer_discovery_timeout(lp); > + lnet_net_lock(LNET_LOCK_EX); > + } > + > lnet_net_unlock(LNET_LOCK_EX); > } > > @@ -1759,23 +3088,28 @@ static int lnet_peer_discovery(void *arg) > LNetEQFree(the_lnet.ln_dc_eqh); > LNetInvalidateEQHandle(&the_lnet.ln_dc_eqh); > > + /* Queue cleanup 1: stop all pending pings and pushes. */ > lnet_net_lock(LNET_LOCK_EX); > - list_for_each_entry(lp, &the_lnet.ln_dc_request, lp_dc_list) { > - spin_lock(&lp->lp_lock); > - lp->lp_state |= LNET_PEER_REDISCOVER; > - lp->lp_state &= ~(LNET_PEER_DISCOVERED | > - LNET_PEER_DISCOVERING | > - LNET_PEER_NIDS_UPTODATE); > - spin_unlock(&lp->lp_lock); > - lnet_peer_discovery_complete(lp); > + while (!list_empty(&the_lnet.ln_dc_working)) { > + lp = list_first_entry(&the_lnet.ln_dc_working, > + struct lnet_peer, lp_dc_list); > + list_move(&lp->lp_dc_list, &the_lnet.ln_dc_expired); > + lnet_net_unlock(LNET_LOCK_EX); > + lnet_peer_discovery_timeout(lp); > + lnet_net_lock(LNET_LOCK_EX); > } > - list_for_each_entry(lp, &the_lnet.ln_dc_working, lp_dc_list) { > - spin_lock(&lp->lp_lock); > - lp->lp_state |= LNET_PEER_REDISCOVER; > - lp->lp_state &= ~(LNET_PEER_DISCOVERED | > - LNET_PEER_DISCOVERING | > - LNET_PEER_NIDS_UPTODATE); > - spin_unlock(&lp->lp_lock); > + lnet_net_unlock(LNET_LOCK_EX); > + > + /* Queue cleanup 2: wait for the expired queue to clear. */ > + while (!list_empty(&the_lnet.ln_dc_expired)) > + schedule_timeout_uninterruptible(HZ); > + > + /* Queue cleanup 3: clear the request queue. */ > + lnet_net_lock(LNET_LOCK_EX); > + while (!list_empty(&the_lnet.ln_dc_request)) { > + lp = list_first_entry(&the_lnet.ln_dc_request, > + struct lnet_peer, lp_dc_list); > + lnet_peer_discovery_error(lp, -ESHUTDOWN); > lnet_peer_discovery_complete(lp); > } > lnet_net_unlock(LNET_LOCK_EX); > @@ -1797,10 +3131,6 @@ int lnet_peer_discovery_start(void) > if (the_lnet.ln_dc_state != LNET_DC_STATE_SHUTDOWN) > return -EALREADY; > > - INIT_LIST_HEAD(&the_lnet.ln_dc_request); > - INIT_LIST_HEAD(&the_lnet.ln_dc_working); > - init_waitqueue_head(&the_lnet.ln_dc_waitq); > - > rc = LNetEQAlloc(0, lnet_discovery_event_handler, &the_lnet.ln_dc_eqh); > if (rc != 0) { > CERROR("Can't allocate discovery EQ: %d\n", rc); > @@ -1819,6 +3149,8 @@ int lnet_peer_discovery_start(void) > the_lnet.ln_dc_state = LNET_DC_STATE_SHUTDOWN; > } > > + CDEBUG(D_NET, "discovery start: %d\n", rc); > + > return rc; > } > > @@ -1837,6 +3169,9 @@ void lnet_peer_discovery_stop(void) > > LASSERT(list_empty(&the_lnet.ln_dc_request)); > LASSERT(list_empty(&the_lnet.ln_dc_working)); > + LASSERT(list_empty(&the_lnet.ln_dc_expired)); > + > + CDEBUG(D_NET, "discovery stopped\n"); > } > > /* Debugging */ > > > From jsimmons at infradead.org Sun Oct 14 23:38:52 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:38:52 +0100 (BST) Subject: [lustre-devel] [PATCH 19/24] lustre: lnet: add "lnetctl peer list" In-Reply-To: <153895437828.16383.14376327105039832285.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437828.16383.14376327105039832285.stgit@noble> Message-ID: > From: Olaf Weber > > Add IOC_LIBCFS_GET_PEER_LIST to obtain a list of the primary > NIDs of all peers known to the system. The list is written > into a userspace buffer by the kernel. The typical usage is > to make a first call to determine the required buffer size, > then a second call to obtain the list. > > Extend the "lnetctl peer" set of commands with a "list" > subcommand that uses this interface. > > Modify the IOC_LIBCFS_GET_PEER_NI ioctl (which is new in the > Multi-Rail code) to use a NID to indicate the peer to look > up, and then pass out the data for all NIDs of that peer. > > Re-implement "lnetctl peer show" to obtain the list of NIDs > using IOC_LIBCFS_GET_PEER_LIST followed by one or more > IOC_LIBCFS_GET_PEER_NI calls to get information for each > peer. > > Make sure to copy the structure from kernel space to > user space even if the ioctl handler returns an error. > This is needed because if the buffer passed in by the > user space is not big enough to copy the data, we want > to pass the requested size to user space in the structure > passed in. The return code in this case is -E2BIG. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25790 > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 9 - > .../staging/lustre/include/linux/lnet/lib-types.h | 3 > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 3 > drivers/staging/lustre/lnet/lnet/api-ni.c | 30 ++- > drivers/staging/lustre/lnet/lnet/peer.c | 222 +++++++++++++------- > 5 files changed, 169 insertions(+), 98 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index f82a699371f2..58e3a9c4e39f 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -462,6 +462,8 @@ int lnet_get_rtr_pool_cfg(int idx, struct lnet_ioctl_pool_cfg *pool_cfg); > struct lnet_ni *lnet_get_next_ni_locked(struct lnet_net *mynet, > struct lnet_ni *prev); > struct lnet_ni *lnet_get_ni_idx_locked(int idx); > +int lnet_get_peer_list(__u32 *countp, __u32 *sizep, > + struct lnet_process_id __user *ids); > > void lnet_router_debugfs_init(void); > void lnet_router_debugfs_fini(void); > @@ -730,10 +732,9 @@ bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); > int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); > int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); > int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); > -int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > - bool *mr, > - struct lnet_peer_ni_credit_info __user *peer_ni_info, > - struct lnet_ioctl_element_stats __user *peer_ni_stats); > +int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nid, > + __u32 *nnis, bool *mr, __u32 *sizep, > + void __user *bulk); > int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > char alivness[LNET_MAX_STR_LEN], > __u32 *cpt_iter, __u32 *refcount, > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 07baa86e61ab..8543a67420d7 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -651,7 +651,6 @@ struct lnet_peer_net { > * pt_hash[...] > * pt_peer_list > * pt_peers > - * pt_peer_nnids > * protected by pt_zombie_lock: > * pt_zombie_list > * pt_zombies > @@ -667,8 +666,6 @@ struct lnet_peer_table { > struct list_head pt_peer_list; > /* # peers */ > int pt_peers; > - /* # NIDS on listed peers */ > - int pt_peer_nnids; > /* # zombies to go to deathrow (and not there yet) */ > int pt_zombies; > /* zombie peers_ni */ > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > index 2a9beed23985..2607620e8ef8 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > @@ -144,6 +144,7 @@ struct libcfs_debug_ioctl_data { > #define IOC_LIBCFS_GET_LOCAL_NI _IOWR(IOC_LIBCFS_TYPE, 97, IOCTL_CONFIG_SIZE) > #define IOC_LIBCFS_SET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE) > #define IOC_LIBCFS_GET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 99, IOCTL_CONFIG_SIZE) > -#define IOC_LIBCFS_MAX_NR 99 > +#define IOC_LIBCFS_GET_PEER_LIST _IOWR(IOC_LIBCFS_TYPE, 100, IOCTL_CONFIG_SIZE) > +#define IOC_LIBCFS_MAX_NR 100 > > #endif /* __LIBCFS_IOCTL_H__ */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 955d1711eda4..f624abe7db80 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -3117,21 +3117,31 @@ LNetCtl(unsigned int cmd, void *arg) > > case IOC_LIBCFS_GET_PEER_NI: { > struct lnet_ioctl_peer_cfg *cfg = arg; > - struct lnet_peer_ni_credit_info __user *lpni_cri; > - struct lnet_ioctl_element_stats __user *lpni_stats; > - size_t usr_size = sizeof(*lpni_cri) + sizeof(*lpni_stats); > > - if ((cfg->prcfg_hdr.ioc_len != sizeof(*cfg)) || > - (cfg->prcfg_size != usr_size)) > + if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) > return -EINVAL; > > - lpni_cri = cfg->prcfg_bulk; > - lpni_stats = cfg->prcfg_bulk + sizeof(*lpni_cri); > + mutex_lock(&the_lnet.ln_api_mutex); > + rc = lnet_get_peer_info(&cfg->prcfg_prim_nid, > + &cfg->prcfg_cfg_nid, > + &cfg->prcfg_count, > + &cfg->prcfg_mr, > + &cfg->prcfg_size, > + (void __user *)cfg->prcfg_bulk); > + mutex_unlock(&the_lnet.ln_api_mutex); > + return rc; > + } > + > + case IOC_LIBCFS_GET_PEER_LIST: { > + struct lnet_ioctl_peer_cfg *cfg = arg; > + > + if (cfg->prcfg_hdr.ioc_len < sizeof(*cfg)) > + return -EINVAL; > > mutex_lock(&the_lnet.ln_api_mutex); > - rc = lnet_get_peer_info(cfg->prcfg_count, &cfg->prcfg_prim_nid, > - &cfg->prcfg_cfg_nid, &cfg->prcfg_mr, > - lpni_cri, lpni_stats); > + rc = lnet_get_peer_list(&cfg->prcfg_count, &cfg->prcfg_size, > + (struct lnet_process_id __user *) > + cfg->prcfg_bulk); > mutex_unlock(&the_lnet.ln_api_mutex); > return rc; > } > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 1ef4a44e752e..8dff3b767577 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -263,9 +263,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) > > /* Update peer NID count. */ > lp = lpn->lpn_peer; > - ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; > lp->lp_nnis--; > - ptable->pt_peer_nnids--; > > /* > * If there are no more peer nets, make the peer unfindable > @@ -277,6 +275,7 @@ lnet_peer_detach_peer_ni_locked(struct lnet_peer_ni *lpni) > */ > if (list_empty(&lp->lp_peer_nets)) { > list_del_init(&lp->lp_peer_list); > + ptable = the_lnet.ln_peer_tables[lp->lp_cpt]; > ptable->pt_peers--; > } else if (the_lnet.ln_dc_state != LNET_DC_STATE_RUNNING) { > /* Discovery isn't running, nothing to do here. */ > @@ -637,44 +636,6 @@ lnet_find_peer(lnet_nid_t nid) > return lp; > } > > -struct lnet_peer_ni * > -lnet_get_peer_ni_idx_locked(int idx, struct lnet_peer_net **lpn, > - struct lnet_peer **lp) > -{ > - struct lnet_peer_table *ptable; > - struct lnet_peer_ni *lpni; > - int lncpt; > - int cpt; > - > - lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); > - > - for (cpt = 0; cpt < lncpt; cpt++) { > - ptable = the_lnet.ln_peer_tables[cpt]; > - if (ptable->pt_peer_nnids > idx) > - break; > - idx -= ptable->pt_peer_nnids; > - } > - if (cpt >= lncpt) > - return NULL; > - > - list_for_each_entry((*lp), &ptable->pt_peer_list, lp_peer_list) { > - if ((*lp)->lp_nnis <= idx) { > - idx -= (*lp)->lp_nnis; > - continue; > - } > - list_for_each_entry((*lpn), &((*lp)->lp_peer_nets), > - lpn_peer_nets) { > - list_for_each_entry(lpni, &((*lpn)->lpn_peer_nis), > - lpni_peer_nis) { > - if (idx-- == 0) > - return lpni; > - } > - } > - } > - > - return NULL; > -} > - > struct lnet_peer_ni * > lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > struct lnet_peer_net *peer_net, > @@ -734,6 +695,69 @@ lnet_get_next_peer_ni_locked(struct lnet_peer *peer, > return lpni; > } > > +/* Call with the ln_api_mutex held */ > +int > +lnet_get_peer_list(__u32 *countp, __u32 *sizep, > + struct lnet_process_id __user *ids) > +{ > + struct lnet_process_id id; > + struct lnet_peer_table *ptable; > + struct lnet_peer *lp; > + __u32 count = 0; > + __u32 size = 0; > + int lncpt; > + int cpt; > + __u32 i; > + int rc; > + > + rc = -ESHUTDOWN; > + if (the_lnet.ln_state == LNET_STATE_SHUTDOWN) > + goto done; > + > + lncpt = cfs_percpt_number(the_lnet.ln_peer_tables); > + > + /* > + * Count the number of peers, and return E2BIG if the buffer > + * is too small. We'll also return the desired size. > + */ > + rc = -E2BIG; > + for (cpt = 0; cpt < lncpt; cpt++) { > + ptable = the_lnet.ln_peer_tables[cpt]; > + count += ptable->pt_peers; > + } > + size = count * sizeof(*ids); > + if (size > *sizep) > + goto done; > + > + /* > + * Walk the peer lists and copy out the primary nids. > + * This is safe because the peer lists are only modified > + * while the ln_api_mutex is held. So we don't need to > + * hold the lnet_net_lock as well, and can therefore > + * directly call copy_to_user(). > + */ > + rc = -EFAULT; > + memset(&id, 0, sizeof(id)); > + id.pid = LNET_PID_LUSTRE; > + i = 0; > + for (cpt = 0; cpt < lncpt; cpt++) { > + ptable = the_lnet.ln_peer_tables[cpt]; > + list_for_each_entry(lp, &ptable->pt_peer_list, lp_peer_list) { > + if (i >= count) > + goto done; > + id.nid = lp->lp_primary_nid; > + if (copy_to_user(&ids[i], &id, sizeof(id))) > + goto done; > + i++; > + } > + } > + rc = 0; > +done: > + *countp = count; > + *sizep = size; > + return rc; > +} > + > /* > * Start pushes to peers that need to be updated for a configuration > * change on this node. > @@ -1128,7 +1152,6 @@ lnet_peer_attach_peer_ni(struct lnet_peer *lp, > spin_unlock(&lp->lp_lock); > > lp->lp_nnis++; > - the_lnet.ln_peer_tables[lp->lp_cpt]->pt_peer_nnids++; > lnet_net_unlock(LNET_LOCK_EX); > > CDEBUG(D_NET, "peer %s NID %s flags %#x\n", > @@ -3273,55 +3296,94 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > } > > /* ln_api_mutex is held, which keeps the peer list stable */ > -int lnet_get_peer_info(__u32 idx, lnet_nid_t *primary_nid, lnet_nid_t *nid, > - bool *mr, > - struct lnet_peer_ni_credit_info __user *peer_ni_info, > - struct lnet_ioctl_element_stats __user *peer_ni_stats) > +int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > + __u32 *nnis, bool *mr, __u32 *sizep, > + void __user *bulk) > { > - struct lnet_ioctl_element_stats ni_stats; > - struct lnet_peer_ni_credit_info ni_info; > - struct lnet_peer_ni *lpni = NULL; > - struct lnet_peer_net *lpn = NULL; > - struct lnet_peer *lp = NULL; > + struct lnet_ioctl_element_stats *lpni_stats; > + struct lnet_peer_ni_credit_info *lpni_info; > + struct lnet_peer_ni *lpni; > + struct lnet_peer *lp; > + lnet_nid_t nid; > + __u32 size; > int rc; > > - lpni = lnet_get_peer_ni_idx_locked(idx, &lpn, &lp); > + lp = lnet_find_peer(*primary_nid); > > - if (!lpni) > - return -ENOENT; > + if (!lp) { > + rc = -ENOENT; > + goto out; > + } > + > + size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats); > + size *= lp->lp_nnis; > + if (size > *sizep) { > + *sizep = size; > + rc = -E2BIG; > + goto out_lp_decref; > + } > > *primary_nid = lp->lp_primary_nid; > *mr = lnet_peer_is_multi_rail(lp); > - *nid = lpni->lpni_nid; > - snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, "NA"); > - if (lnet_isrouter(lpni) || > - lnet_peer_aliveness_enabled(lpni)) > - snprintf(ni_info.cr_aliveness, LNET_MAX_STR_LEN, > - lpni->lpni_alive ? "up" : "down"); > - > - ni_info.cr_refcount = atomic_read(&lpni->lpni_refcount); > - ni_info.cr_ni_peer_tx_credits = lpni->lpni_net ? > - lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0; > - ni_info.cr_peer_tx_credits = lpni->lpni_txcredits; > - ni_info.cr_peer_rtr_credits = lpni->lpni_rtrcredits; > - ni_info.cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits; > - ni_info.cr_peer_min_tx_credits = lpni->lpni_mintxcredits; > - ni_info.cr_peer_tx_qnob = lpni->lpni_txqnob; > - > - ni_stats.iel_send_count = atomic_read(&lpni->lpni_stats.send_count); > - ni_stats.iel_recv_count = atomic_read(&lpni->lpni_stats.recv_count); > - ni_stats.iel_drop_count = atomic_read(&lpni->lpni_stats.drop_count); > - > - /* If copy_to_user fails */ > - rc = -EFAULT; > - if (copy_to_user(peer_ni_info, &ni_info, sizeof(ni_info))) > - goto copy_failed; > + *nidp = lp->lp_primary_nid; > + *nnis = lp->lp_nnis; > + *sizep = size; > > - if (copy_to_user(peer_ni_stats, &ni_stats, sizeof(ni_stats))) > - goto copy_failed; > + /* Allocate helper buffers. */ > + rc = -ENOMEM; > + lpni_info = kzalloc(sizeof(*lpni_info), GFP_KERNEL); > + if (!lpni_info) > + goto out_lp_decref; > + lpni_stats = kzalloc(sizeof(*lpni_stats), GFP_KERNEL); > + if (!lpni_stats) > + goto out_free_info; > > + lpni = NULL; > + rc = -EFAULT; > + while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { > + nid = lpni->lpni_nid; > + if (copy_to_user(bulk, &nid, sizeof(nid))) > + goto out_free_stats; > + bulk += sizeof(nid); > + > + memset(lpni_info, 0, sizeof(*lpni_info)); > + snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN, "NA"); > + if (lnet_isrouter(lpni) || > + lnet_peer_aliveness_enabled(lpni)) > + snprintf(lpni_info->cr_aliveness, LNET_MAX_STR_LEN, > + lpni->lpni_alive ? "up" : "down"); > + > + lpni_info->cr_refcount = atomic_read(&lpni->lpni_refcount); > + lpni_info->cr_ni_peer_tx_credits = lpni->lpni_net ? > + lpni->lpni_net->net_tunables.lct_peer_tx_credits : 0; > + lpni_info->cr_peer_tx_credits = lpni->lpni_txcredits; > + lpni_info->cr_peer_rtr_credits = lpni->lpni_rtrcredits; > + lpni_info->cr_peer_min_rtr_credits = lpni->lpni_minrtrcredits; > + lpni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits; > + lpni_info->cr_peer_tx_qnob = lpni->lpni_txqnob; > + if (copy_to_user(bulk, lpni_info, sizeof(*lpni_info))) > + goto out_free_stats; > + bulk += sizeof(*lpni_info); > + > + memset(lpni_stats, 0, sizeof(*lpni_stats)); > + lpni_stats->iel_send_count = > + atomic_read(&lpni->lpni_stats.send_count); > + lpni_stats->iel_recv_count = > + atomic_read(&lpni->lpni_stats.recv_count); > + lpni_stats->iel_drop_count = > + atomic_read(&lpni->lpni_stats.drop_count); > + if (copy_to_user(bulk, lpni_stats, sizeof(*lpni_stats))) > + goto out_free_stats; > + bulk += sizeof(*lpni_stats); > + } > rc = 0; > > -copy_failed: > +out_free_stats: > + kfree(lpni_stats); > +out_free_info: > + kfree(lpni_info); > +out_lp_decref: > + lnet_peer_decref_locked(lp); > +out: > return rc; > } > > > From jsimmons at infradead.org Sun Oct 14 23:43:03 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:43:03 +0100 (BST) Subject: [lustre-devel] [PATCH 20/24] lustre: lnet: add "lnetctl ping" command In-Reply-To: <153895437832.16383.822062330627071137.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437832.16383.822062330627071137.stgit@noble> Message-ID: > From: Olaf Weber > > Adds function jt_ping() in lnetctl.c and > lustre_lnet_ping_nid() in liblnetconfig.c file. > The output of "lnetctl ping" is similar to > "lnetctl peer show". > > Function jt_ping() in lnetctl.c calls lustre_lnet_ping_nid() > to implement "lnetctl ping". Adds a function infra_ping_nid() > to be later reused for the ping similar lnetctl commands. > Uses a new ioctl call, IOC_LIBCFS_PING_PEER for "lnetctl ping". > With "lnetctl ping", multiple nids can be pinged. Uses a new > struct(lnet_ioctl_ping_data in lib-dlc.h) to pass the data > from kernel to user space for ping. Also changes lnet_ping() > function and its input parameters in drivers/staging/lustre/lnet/lnet/api-ni.c Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Sonia Sharma > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25791 > Reviewed-by: Amir Shehata > Tested-by: Amir Shehata > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 5 +- > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 2 - > .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 2 - > .../lustre/lnet/klnds/socklnd/socklnd_modparams.c | 2 - > drivers/staging/lustre/lnet/lnet/api-ni.c | 55 +++++++++++++++----- > drivers/staging/lustre/lnet/lnet/peer.c | 2 - > 6 files changed, 47 insertions(+), 21 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 58e3a9c4e39f..adb4d0551ef5 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -76,8 +76,8 @@ extern struct lnet the_lnet; /* THE network */ > #define LNET_ACCEPTOR_MIN_RESERVED_PORT 512 > #define LNET_ACCEPTOR_MAX_RESERVED_PORT 1023 > > -/* Discovery timeout - same as default peer_timeout */ > -#define DISCOVERY_TIMEOUT 180 > +/* default timeout */ > +#define DEFAULT_PEER_TIMEOUT 180 > > static inline int lnet_is_route_alive(struct lnet_route *route) > { > @@ -716,6 +716,7 @@ struct lnet_peer_ni *lnet_nid2peerni_locked(lnet_nid_t nid, lnet_nid_t pref, > int cpt); > struct lnet_peer_ni *lnet_nid2peerni_ex(lnet_nid_t nid, int cpt); > struct lnet_peer_ni *lnet_find_peer_ni_locked(lnet_nid_t nid); > +struct lnet_peer *lnet_find_peer(lnet_nid_t nid); > void lnet_peer_net_added(struct lnet_net *net); > lnet_nid_t lnet_peer_primary_nid_locked(lnet_nid_t nid); > int lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block); > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > index 2607620e8ef8..3d89202bd396 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > @@ -102,7 +102,7 @@ struct libcfs_debug_ioctl_data { > #define IOC_LIBCFS_CONFIGURE _IOWR('e', 59, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_TESTPROTOCOMPAT _IOWR('e', 60, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_PING _IOWR('e', 61, IOCTL_LIBCFS_TYPE) > -/* IOC_LIBCFS_DEBUG_PEER _IOWR('e', 62, IOCTL_LIBCFS_TYPE) */ > +#define IOC_LIBCFS_PING_PEER _IOWR('e', 62, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_LNETST _IOWR('e', 63, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_LNET_FAULT _IOWR('e', 64, IOCTL_LIBCFS_TYPE) > /* lnd ioctls */ > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c > index 0f2ad9110dc9..13b19f3eabf0 100644 > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c > @@ -83,7 +83,7 @@ static int peer_buffer_credits; > module_param(peer_buffer_credits, int, 0444); > MODULE_PARM_DESC(peer_buffer_credits, "# per-peer router buffer credits"); > > -static int peer_timeout = 180; > +static int peer_timeout = DEFAULT_PEER_TIMEOUT; > module_param(peer_timeout, int, 0444); > MODULE_PARM_DESC(peer_timeout, "Seconds without aliveness news to declare peer dead (<=0 to disable)"); > > diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c > index 5663a4ca94d4..da5910049fc1 100644 > --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c > +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_modparams.c > @@ -35,7 +35,7 @@ static int peer_buffer_credits; > module_param(peer_buffer_credits, int, 0444); > MODULE_PARM_DESC(peer_buffer_credits, "# per-peer router buffer credits"); > > -static int peer_timeout = 180; > +static int peer_timeout = DEFAULT_PEER_TIMEOUT; > module_param(peer_timeout, int, 0444); > MODULE_PARM_DESC(peer_timeout, "Seconds without aliveness news to declare peer dead (<=0 to disable)"); > > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index f624abe7db80..37f47bd1511f 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -3181,24 +3181,50 @@ LNetCtl(unsigned int cmd, void *arg) > id.nid = data->ioc_nid; > id.pid = data->ioc_u32[0]; > > - /* Don't block longer than 2 minutes */ > - if (data->ioc_u32[1] > 120 * MSEC_PER_SEC) > - return -EINVAL; > - > - /* If timestamp is negative then disable timeout */ > - if ((s32)data->ioc_u32[1] < 0) > - timeout = MAX_SCHEDULE_TIMEOUT; > + /* If timeout is negative then set default of 3 minutes */ > + if (((s32)data->ioc_u32[1] <= 0) || > + data->ioc_u32[1] > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC)) > + timeout = DEFAULT_PEER_TIMEOUT * HZ; > else > timeout = msecs_to_jiffies(data->ioc_u32[1]); > > rc = lnet_ping(id, timeout, data->ioc_pbuf1, > data->ioc_plen1 / sizeof(struct lnet_process_id)); > + > if (rc < 0) > return rc; > + > data->ioc_count = rc; > return 0; > } > > + case IOC_LIBCFS_PING_PEER: { > + struct lnet_ioctl_ping_data *ping = arg; > + struct lnet_peer *lp; > + signed long timeout; > + > + /* If timeout is negative then set default of 3 minutes */ > + if (((s32)ping->op_param) <= 0 || > + ping->op_param > (DEFAULT_PEER_TIMEOUT * MSEC_PER_SEC)) > + timeout = DEFAULT_PEER_TIMEOUT * HZ; > + else > + timeout = msecs_to_jiffies(ping->op_param); > + > + rc = lnet_ping(ping->ping_id, timeout, > + ping->ping_buf, > + ping->ping_count); > + if (rc < 0) > + return rc; > + > + lp = lnet_find_peer(ping->ping_id.nid); > + if (lp) { > + ping->ping_id.nid = lp->lp_primary_nid; > + ping->mr_info = lnet_peer_is_multi_rail(lp); > + } > + ping->ping_count = rc; > + return 0; > + } > + > default: > ni = lnet_net2ni_addref(data->ioc_net); > if (!ni) > @@ -3301,7 +3327,7 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > /* initialize md content */ > md.start = &pbuf->pb_info; > md.length = LNET_PING_INFO_SIZE(n_ids); > - md.threshold = 2; /*GET/REPLY*/ > + md.threshold = 2; /* GET/REPLY */ > md.max_size = 0; > md.options = LNET_MD_TRUNCATE; > md.user_ptr = NULL; > @@ -3319,7 +3345,6 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > > if (rc) { > /* Don't CERROR; this could be deliberate! */ > - > rc2 = LNetMDUnlink(mdh); > LASSERT(!rc2); > > @@ -3363,7 +3388,6 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > replied = 1; > rc = event.mlength; > } > - > } while (rc2 <= 0 || !event.unlinked); > > if (!replied) { > @@ -3377,10 +3401,9 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > nob = rc; > LASSERT(nob >= 0 && nob <= LNET_PING_INFO_SIZE(n_ids)); > > - rc = -EPROTO; /* if I can't parse... */ > + rc = -EPROTO; /* if I can't parse... */ > > if (nob < 8) { > - /* can't check magic/version */ > CERROR("%s: ping info too short %d\n", > libcfs_id2str(id), nob); > goto fail_free_eq; > @@ -3401,7 +3424,8 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > } > > if (nob < LNET_PING_INFO_SIZE(0)) { > - CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id), > + CERROR("%s: Short reply %d(%d min)\n", > + libcfs_id2str(id), > nob, (int)LNET_PING_INFO_SIZE(0)); > goto fail_free_eq; > } > @@ -3410,12 +3434,13 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > n_ids = pbuf->pb_info.pi_nnis; > > if (nob < LNET_PING_INFO_SIZE(n_ids)) { > - CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id), > + CERROR("%s: Short reply %d(%d expected)\n", > + libcfs_id2str(id), > nob, (int)LNET_PING_INFO_SIZE(n_ids)); > goto fail_free_eq; > } > > - rc = -EFAULT; /* If I SEGV... */ > + rc = -EFAULT; /* if I segv in copy_to_user()... */ > > memset(&tmpid, 0, sizeof(tmpid)); > for (i = 0; i < n_ids; i++) { > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 8dff3b767577..95f72ae39a89 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -2905,7 +2905,7 @@ static struct lnet_peer *lnet_peer_dc_timed_out(time64_t now) > return NULL; > lp = list_first_entry(&the_lnet.ln_dc_working, > struct lnet_peer, lp_dc_list); > - if (now < lp->lp_last_queued + DISCOVERY_TIMEOUT) > + if (now < lp->lp_last_queued + DEFAULT_PEER_TIMEOUT) > return NULL; > return lp; > } > > > From jsimmons at infradead.org Sun Oct 14 23:45:59 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:45:59 +0100 (BST) Subject: [lustre-devel] [PATCH 21/24] lustre: lnet: add "lnetctl discover" In-Reply-To: <153895437836.16383.17797958097457714365.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437836.16383.17797958097457714365.stgit@noble> Message-ID: > From: Sonia Sharma > > Add a "discover" subcommand to lnetctl > > jt_discover() in lnetctl.c calls lustre_lnet_discover_nid() > to implement "lnetctl discover". The output is similar to > "lnetctl ping" command. > This patch also does some clean up in linlnetconfig.c > For parameters under global settings, the common code > for them is pulled in functions ioctl_set_value() and > ioctl_show_global_values(). Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Sonia Sharma > Signed-off-by: Amir Shehata > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25793 > Signed-off-by: NeilBrown > --- > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 2 > drivers/staging/lustre/lnet/lnet/api-ni.c | 100 ++++++++++++++++++++ > 2 files changed, 101 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > index 3d89202bd396..60bc9713923e 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > @@ -113,7 +113,7 @@ struct libcfs_debug_ioctl_data { > #define IOC_LIBCFS_DEL_PEER _IOWR('e', 74, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_ADD_PEER _IOWR('e', 75, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_GET_PEER _IOWR('e', 76, IOCTL_LIBCFS_TYPE) > -/* ioctl 77 is free for use */ > +#define IOC_LIBCFS_DISCOVER _IOWR('e', 77, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_ADD_INTERFACE _IOWR('e', 78, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_DEL_INTERFACE _IOWR('e', 79, IOCTL_LIBCFS_TYPE) > #define IOC_LIBCFS_GET_INTERFACE _IOWR('e', 80, IOCTL_LIBCFS_TYPE) > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 37f47bd1511f..0511c6acb9b1 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -104,6 +104,9 @@ static atomic_t lnet_dlc_seq_no = ATOMIC_INIT(0); > static int lnet_ping(struct lnet_process_id id, signed long timeout, > struct lnet_process_id __user *ids, int n_ids); > > +static int lnet_discover(struct lnet_process_id id, __u32 force, > + struct lnet_process_id __user *ids, int n_ids); > + > static int > discovery_set(const char *val, const struct kernel_param *kp) > { > @@ -3225,6 +3228,25 @@ LNetCtl(unsigned int cmd, void *arg) > return 0; > } > > + case IOC_LIBCFS_DISCOVER: { > + struct lnet_ioctl_ping_data *discover = arg; > + struct lnet_peer *lp; > + > + rc = lnet_discover(discover->ping_id, discover->op_param, > + discover->ping_buf, > + discover->ping_count); > + if (rc < 0) > + return rc; > + lp = lnet_find_peer(discover->ping_id.nid); > + if (lp) { > + discover->ping_id.nid = lp->lp_primary_nid; > + discover->mr_info = lnet_peer_is_multi_rail(lp); > + } > + > + discover->ping_count = rc; > + return 0; > + } > + > default: > ni = lnet_net2ni_addref(data->ioc_net); > if (!ni) > @@ -3461,3 +3483,81 @@ static int lnet_ping(struct lnet_process_id id, signed long timeout, > lnet_ping_buffer_decref(pbuf); > return rc; > } > + > +static int > +lnet_discover(struct lnet_process_id id, __u32 force, > + struct lnet_process_id __user *ids, > + int n_ids) > +{ > + struct lnet_peer_ni *lpni; > + struct lnet_peer_ni *p; > + struct lnet_peer *lp; > + struct lnet_process_id *buf; > + int cpt; > + int i; > + int rc; > + int max_intf = lnet_interfaces_max; > + > + if (n_ids <= 0 || > + id.nid == LNET_NID_ANY || > + n_ids > max_intf) > + return -EINVAL; > + > + if (id.pid == LNET_PID_ANY) > + id.pid = LNET_PID_LUSTRE; > + > + buf = kcalloc(n_ids, sizeof(*buf), GFP_KERNEL); > + if (!buf) > + return -ENOMEM; > + > + cpt = lnet_net_lock_current(); > + lpni = lnet_nid2peerni_locked(id.nid, LNET_NID_ANY, cpt); > + if (IS_ERR(lpni)) { > + rc = PTR_ERR(lpni); > + goto out; > + } > + > + /* > + * Clearing the NIDS_UPTODATE flag ensures the peer will > + * be discovered, provided discovery has not been disabled. > + */ > + lp = lpni->lpni_peer_net->lpn_peer; > + spin_lock(&lp->lp_lock); > + lp->lp_state &= ~LNET_PEER_NIDS_UPTODATE; > + /* If the force flag is set, force a PING and PUSH as well. */ > + if (force) > + lp->lp_state |= LNET_PEER_FORCE_PING | LNET_PEER_FORCE_PUSH; > + spin_unlock(&lp->lp_lock); > + rc = lnet_discover_peer_locked(lpni, cpt, true); > + if (rc) > + goto out_decref; > + > + /* Peer may have changed. */ > + lp = lpni->lpni_peer_net->lpn_peer; > + if (lp->lp_nnis < n_ids) > + n_ids = lp->lp_nnis; > + > + i = 0; > + p = NULL; > + while ((p = lnet_get_next_peer_ni_locked(lp, NULL, p)) != NULL) { > + buf[i].pid = id.pid; > + buf[i].nid = p->lpni_nid; > + if (++i >= n_ids) > + break; > + } > + > + lnet_net_unlock(cpt); > + > + rc = -EFAULT; > + if (copy_to_user(ids, buf, n_ids * sizeof(*buf))) > + goto out_relock; > + rc = n_ids; > +out_relock: > + lnet_net_lock(cpt); > +out_decref: > + lnet_peer_ni_decref_locked(lpni); > +out: > + lnet_net_unlock(cpt); > + kfree(buf); > + return rc; > +} > > > From jsimmons at infradead.org Sun Oct 14 23:50:44 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:50:44 +0100 (BST) Subject: [lustre-devel] [PATCH 22/24] lustre: lnet: add enhanced statistics In-Reply-To: <153895437840.16383.11395842984054958152.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437840.16383.11395842984054958152.stgit@noble> Message-ID: > From: Amir Shehata > > Added statistics to track the different types of > LNet messages which are sent/received/dropped Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Amir Shehata > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/25795 > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 12 ++ > .../staging/lustre/include/linux/lnet/lib-types.h | 20 +++ > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 3 - > drivers/staging/lustre/lnet/lnet/api-ni.c | 45 +++++++- > drivers/staging/lustre/lnet/lnet/lib-move.c | 116 +++++++++++++++++++- > drivers/staging/lustre/lnet/lnet/lib-msg.c | 16 ++- > drivers/staging/lustre/lnet/lnet/net_fault.c | 3 - > drivers/staging/lustre/lnet/lnet/peer.c | 26 +++- > 8 files changed, 217 insertions(+), 24 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index adb4d0551ef5..91980f60a50d 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -575,7 +575,7 @@ void lnet_set_reply_msg_len(struct lnet_ni *ni, struct lnet_msg *msg, > void lnet_finalize(struct lnet_msg *msg, int rc); > > void lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, > - unsigned int nob); > + unsigned int nob, __u32 msg_type); > void lnet_drop_delayed_msg_list(struct list_head *head, char *reason); > void lnet_recv_delayed_msg_list(struct list_head *head); > > @@ -825,4 +825,14 @@ lnet_peer_needs_push(struct lnet_peer *lp) > return false; > } > > +void lnet_incr_stats(struct lnet_element_stats *stats, > + enum lnet_msg_type msg_type, > + enum lnet_stats_type stats_type); > + > +__u32 lnet_sum_stats(struct lnet_element_stats *stats, > + enum lnet_stats_type stats_type); > + > +void lnet_usr_translate_stats(struct lnet_ioctl_element_msg_stats *msg_stats, > + struct lnet_element_stats *stats); > + > #endif > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h > index 8543a67420d7..19f7b11a1e44 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h > @@ -279,10 +279,24 @@ enum lnet_ni_state { > LNET_NI_STATE_DELETING > }; > > +enum lnet_stats_type { > + LNET_STATS_TYPE_SEND = 0, > + LNET_STATS_TYPE_RECV, > + LNET_STATS_TYPE_DROP > +}; > + > +struct lnet_comm_count { > + atomic_t co_get_count; > + atomic_t co_put_count; > + atomic_t co_reply_count; > + atomic_t co_ack_count; > + atomic_t co_hello_count; > +}; > + > struct lnet_element_stats { > - atomic_t send_count; > - atomic_t recv_count; > - atomic_t drop_count; > + struct lnet_comm_count el_send_stats; > + struct lnet_comm_count el_recv_stats; > + struct lnet_comm_count el_drop_stats; > }; > > struct lnet_net { > diff --git a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > index 60bc9713923e..4590f65c333f 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > +++ b/drivers/staging/lustre/include/uapi/linux/lnet/libcfs_ioctl.h > @@ -145,6 +145,7 @@ struct libcfs_debug_ioctl_data { > #define IOC_LIBCFS_SET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 98, IOCTL_CONFIG_SIZE) > #define IOC_LIBCFS_GET_NUMA_RANGE _IOWR(IOC_LIBCFS_TYPE, 99, IOCTL_CONFIG_SIZE) > #define IOC_LIBCFS_GET_PEER_LIST _IOWR(IOC_LIBCFS_TYPE, 100, IOCTL_CONFIG_SIZE) > -#define IOC_LIBCFS_MAX_NR 100 > +#define IOC_LIBCFS_GET_LOCAL_NI_MSG_STATS _IOWR(IOC_LIBCFS_TYPE, 101, IOCTL_CONFIG_SIZE) > +#define IOC_LIBCFS_MAX_NR 101 > > #endif /* __LIBCFS_IOCTL_H__ */ > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 0511c6acb9b1..0852118bf803 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -2263,8 +2263,12 @@ lnet_fill_ni_info(struct lnet_ni *ni, struct lnet_ioctl_config_ni *cfg_ni, > memcpy(&tun->lt_cmn, &ni->ni_net->net_tunables, sizeof(tun->lt_cmn)); > > if (stats) { > - stats->iel_send_count = atomic_read(&ni->ni_stats.send_count); > - stats->iel_recv_count = atomic_read(&ni->ni_stats.recv_count); > + stats->iel_send_count = lnet_sum_stats(&ni->ni_stats, > + LNET_STATS_TYPE_SEND); > + stats->iel_recv_count = lnet_sum_stats(&ni->ni_stats, > + LNET_STATS_TYPE_RECV); > + stats->iel_drop_count = lnet_sum_stats(&ni->ni_stats, > + LNET_STATS_TYPE_DROP); > } > > /* > @@ -2491,6 +2495,29 @@ lnet_get_ni_config(struct lnet_ioctl_config_ni *cfg_ni, > return rc; > } > > +int lnet_get_ni_stats(struct lnet_ioctl_element_msg_stats *msg_stats) > +{ > + struct lnet_ni *ni; > + int cpt; > + int rc = -ENOENT; > + > + if (!msg_stats) > + return -EINVAL; > + > + cpt = lnet_net_lock_current(); > + > + ni = lnet_get_ni_idx_locked(msg_stats->im_idx); > + > + if (ni) { > + lnet_usr_translate_stats(msg_stats, &ni->ni_stats); > + rc = 0; > + } > + > + lnet_net_unlock(cpt); > + > + return rc; > +} > + > static int lnet_add_net_common(struct lnet_net *net, > struct lnet_ioctl_config_lnd_tunables *tun) > { > @@ -2956,6 +2983,7 @@ LNetCtl(unsigned int cmd, void *arg) > __u32 tun_size; > > cfg_ni = arg; > + > /* get the tunables if they are available */ > if (cfg_ni->lic_cfg_hdr.ioc_len < > sizeof(*cfg_ni) + sizeof(*stats) + sizeof(*tun)) > @@ -2975,6 +3003,19 @@ LNetCtl(unsigned int cmd, void *arg) > return rc; > } > > + case IOC_LIBCFS_GET_LOCAL_NI_MSG_STATS: { > + struct lnet_ioctl_element_msg_stats *msg_stats = arg; > + > + if (msg_stats->im_hdr.ioc_len != sizeof(*msg_stats)) > + return -EINVAL; > + > + mutex_lock(&the_lnet.ln_api_mutex); > + rc = lnet_get_ni_stats(msg_stats); > + mutex_unlock(&the_lnet.ln_api_mutex); > + > + return rc; > + } > + > case IOC_LIBCFS_GET_NET: { > size_t total = sizeof(*config) + > sizeof(struct lnet_ioctl_net_config); > diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c > index 2ff329bf91ba..5694d85c713c 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-move.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c > @@ -45,6 +45,104 @@ static int local_nid_dist_zero = 1; > module_param(local_nid_dist_zero, int, 0444); > MODULE_PARM_DESC(local_nid_dist_zero, "Reserved"); > > +static inline struct lnet_comm_count * > +get_stats_counts(struct lnet_element_stats *stats, > + enum lnet_stats_type stats_type) > +{ > + switch (stats_type) { > + case LNET_STATS_TYPE_SEND: > + return &stats->el_send_stats; > + case LNET_STATS_TYPE_RECV: > + return &stats->el_recv_stats; > + case LNET_STATS_TYPE_DROP: > + return &stats->el_drop_stats; > + default: > + CERROR("Unknown stats type\n"); > + } > + > + return NULL; > +} > + > +void lnet_incr_stats(struct lnet_element_stats *stats, > + enum lnet_msg_type msg_type, > + enum lnet_stats_type stats_type) > +{ > + struct lnet_comm_count *counts = get_stats_counts(stats, stats_type); > + > + if (!counts) > + return; > + > + switch (msg_type) { > + case LNET_MSG_ACK: > + atomic_inc(&counts->co_ack_count); > + break; > + case LNET_MSG_PUT: > + atomic_inc(&counts->co_put_count); > + break; > + case LNET_MSG_GET: > + atomic_inc(&counts->co_get_count); > + break; > + case LNET_MSG_REPLY: > + atomic_inc(&counts->co_reply_count); > + break; > + case LNET_MSG_HELLO: > + atomic_inc(&counts->co_hello_count); > + break; > + default: > + CERROR("There is a BUG in the code. Unknown message type\n"); > + break; > + } > +} > + > +__u32 lnet_sum_stats(struct lnet_element_stats *stats, > + enum lnet_stats_type stats_type) > +{ > + struct lnet_comm_count *counts = get_stats_counts(stats, stats_type); > + > + if (!counts) > + return 0; > + > + return (atomic_read(&counts->co_ack_count) + > + atomic_read(&counts->co_put_count) + > + atomic_read(&counts->co_get_count) + > + atomic_read(&counts->co_reply_count) + > + atomic_read(&counts->co_hello_count)); > +} > + > +static inline void assign_stats(struct lnet_ioctl_comm_count *msg_stats, > + struct lnet_comm_count *counts) > +{ > + msg_stats->ico_get_count = atomic_read(&counts->co_get_count); > + msg_stats->ico_put_count = atomic_read(&counts->co_put_count); > + msg_stats->ico_reply_count = atomic_read(&counts->co_reply_count); > + msg_stats->ico_ack_count = atomic_read(&counts->co_ack_count); > + msg_stats->ico_hello_count = atomic_read(&counts->co_hello_count); > +} > + > +void lnet_usr_translate_stats(struct lnet_ioctl_element_msg_stats *msg_stats, > + struct lnet_element_stats *stats) > +{ > + struct lnet_comm_count *counts; > + > + LASSERT(msg_stats); > + LASSERT(stats); > + > + counts = get_stats_counts(stats, LNET_STATS_TYPE_SEND); > + if (!counts) > + return; > + assign_stats(&msg_stats->im_send_stats, counts); > + > + counts = get_stats_counts(stats, LNET_STATS_TYPE_RECV); > + if (!counts) > + return; > + assign_stats(&msg_stats->im_recv_stats, counts); > + > + counts = get_stats_counts(stats, LNET_STATS_TYPE_DROP); > + if (!counts) > + return; > + assign_stats(&msg_stats->im_drop_stats, counts); > +} > + > int > lnet_fail_nid(lnet_nid_t nid, unsigned int threshold) > { > @@ -632,9 +730,13 @@ lnet_post_send_locked(struct lnet_msg *msg, int do_send) > the_lnet.ln_counters[cpt]->drop_length += msg->msg_len; > lnet_net_unlock(cpt); > if (msg->msg_txpeer) > - atomic_inc(&msg->msg_txpeer->lpni_stats.drop_count); > + lnet_incr_stats(&msg->msg_txpeer->lpni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_DROP); > if (msg->msg_txni) > - atomic_inc(&msg->msg_txni->ni_stats.drop_count); > + lnet_incr_stats(&msg->msg_txni->ni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_DROP); > > CNETERR("Dropping message for %s: peer not alive\n", > libcfs_id2str(msg->msg_target)); > @@ -1859,9 +1961,11 @@ lnet_send(lnet_nid_t src_nid, struct lnet_msg *msg, lnet_nid_t rtr_nid) > } > > void > -lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, unsigned int nob) > +lnet_drop_message(struct lnet_ni *ni, int cpt, void *private, unsigned int nob, > + __u32 msg_type) > { > lnet_net_lock(cpt); > + lnet_incr_stats(&ni->ni_stats, msg_type, LNET_STATS_TYPE_DROP); > the_lnet.ln_counters[cpt]->drop_count++; > the_lnet.ln_counters[cpt]->drop_length += nob; > lnet_net_unlock(cpt); > @@ -2510,7 +2614,7 @@ lnet_parse(struct lnet_ni *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid, > lnet_finalize(msg, rc); > > drop: > - lnet_drop_message(ni, cpt, private, payload_length); > + lnet_drop_message(ni, cpt, private, payload_length, type); > return 0; > } > EXPORT_SYMBOL(lnet_parse); > @@ -2546,7 +2650,8 @@ lnet_drop_delayed_msg_list(struct list_head *head, char *reason) > * until that's done > */ > lnet_drop_message(msg->msg_rxni, msg->msg_rx_cpt, > - msg->msg_private, msg->msg_len); > + msg->msg_private, msg->msg_len, > + msg->msg_type); > /* > * NB: message will not generate event because w/o attached MD, > * but we still should give error code so lnet_msg_decommit() > @@ -2786,6 +2891,7 @@ lnet_create_reply_msg(struct lnet_ni *ni, struct lnet_msg *getmsg) > cpt = lnet_cpt_of_nid(peer_id.nid, ni); > > lnet_net_lock(cpt); > + lnet_incr_stats(&ni->ni_stats, LNET_MSG_GET, LNET_STATS_TYPE_DROP); > the_lnet.ln_counters[cpt]->drop_count++; > the_lnet.ln_counters[cpt]->drop_length += getmd->md_length; > lnet_net_unlock(cpt); > diff --git a/drivers/staging/lustre/lnet/lnet/lib-msg.c b/drivers/staging/lustre/lnet/lnet/lib-msg.c > index db13d01d366f..7f58cfe25bc2 100644 > --- a/drivers/staging/lustre/lnet/lnet/lib-msg.c > +++ b/drivers/staging/lustre/lnet/lnet/lib-msg.c > @@ -219,9 +219,13 @@ lnet_msg_decommit_tx(struct lnet_msg *msg, int status) > > incr_stats: > if (msg->msg_txpeer) > - atomic_inc(&msg->msg_txpeer->lpni_stats.send_count); > + lnet_incr_stats(&msg->msg_txpeer->lpni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_SEND); > if (msg->msg_txni) > - atomic_inc(&msg->msg_txni->ni_stats.send_count); > + lnet_incr_stats(&msg->msg_txni->ni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_SEND); > out: > lnet_return_tx_credits_locked(msg); > msg->msg_tx_committed = 0; > @@ -280,9 +284,13 @@ lnet_msg_decommit_rx(struct lnet_msg *msg, int status) > > incr_stats: > if (msg->msg_rxpeer) > - atomic_inc(&msg->msg_rxpeer->lpni_stats.recv_count); > + lnet_incr_stats(&msg->msg_rxpeer->lpni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_RECV); > if (msg->msg_rxni) > - atomic_inc(&msg->msg_rxni->ni_stats.recv_count); > + lnet_incr_stats(&msg->msg_rxni->ni_stats, > + msg->msg_type, > + LNET_STATS_TYPE_RECV); > if (ev->type == LNET_EVENT_PUT || ev->type == LNET_EVENT_REPLY) > counters->recv_length += msg->msg_wanted; > > diff --git a/drivers/staging/lustre/lnet/lnet/net_fault.c b/drivers/staging/lustre/lnet/lnet/net_fault.c > index 3841bac1aa0a..e2c746855da9 100644 > --- a/drivers/staging/lustre/lnet/lnet/net_fault.c > +++ b/drivers/staging/lustre/lnet/lnet/net_fault.c > @@ -632,7 +632,8 @@ delayed_msg_process(struct list_head *msg_list, bool drop) > } > } > > - lnet_drop_message(ni, cpt, msg->msg_private, msg->msg_len); > + lnet_drop_message(ni, cpt, msg->msg_private, msg->msg_len, > + msg->msg_type); > lnet_finalize(msg, rc); > } > } > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 95f72ae39a89..03c1c34517e4 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -3301,6 +3301,7 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > void __user *bulk) > { > struct lnet_ioctl_element_stats *lpni_stats; > + struct lnet_ioctl_element_msg_stats *lpni_msg_stats; > struct lnet_peer_ni_credit_info *lpni_info; > struct lnet_peer_ni *lpni; > struct lnet_peer *lp; > @@ -3315,7 +3316,8 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > goto out; > } > > - size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats); > + size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats) > + + sizeof(*lpni_msg_stats); > size *= lp->lp_nnis; > if (size > *sizep) { > *sizep = size; > @@ -3337,13 +3339,17 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > lpni_stats = kzalloc(sizeof(*lpni_stats), GFP_KERNEL); > if (!lpni_stats) > goto out_free_info; > + lpni_msg_stats = kzalloc(sizeof(*lpni_msg_stats), GFP_KERNEL); > + if (!lpni_msg_stats) > + goto out_free_stats; > + > > lpni = NULL; > rc = -EFAULT; > while ((lpni = lnet_get_next_peer_ni_locked(lp, NULL, lpni)) != NULL) { > nid = lpni->lpni_nid; > if (copy_to_user(bulk, &nid, sizeof(nid))) > - goto out_free_stats; > + goto out_free_msg_stats; > bulk += sizeof(nid); > > memset(lpni_info, 0, sizeof(*lpni_info)); > @@ -3362,22 +3368,28 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > lpni_info->cr_peer_min_tx_credits = lpni->lpni_mintxcredits; > lpni_info->cr_peer_tx_qnob = lpni->lpni_txqnob; > if (copy_to_user(bulk, lpni_info, sizeof(*lpni_info))) > - goto out_free_stats; > + goto out_free_msg_stats; > bulk += sizeof(*lpni_info); > > memset(lpni_stats, 0, sizeof(*lpni_stats)); > lpni_stats->iel_send_count = > - atomic_read(&lpni->lpni_stats.send_count); > + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_SEND); > lpni_stats->iel_recv_count = > - atomic_read(&lpni->lpni_stats.recv_count); > + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_RECV); > lpni_stats->iel_drop_count = > - atomic_read(&lpni->lpni_stats.drop_count); > + lnet_sum_stats(&lpni->lpni_stats, LNET_STATS_TYPE_DROP); > if (copy_to_user(bulk, lpni_stats, sizeof(*lpni_stats))) > - goto out_free_stats; > + goto out_free_msg_stats; > bulk += sizeof(*lpni_stats); > + lnet_usr_translate_stats(lpni_msg_stats, &lpni->lpni_stats); > + if (copy_to_user(bulk, lpni_msg_stats, sizeof(*lpni_msg_stats))) > + goto out_free_msg_stats; > + bulk += sizeof(*lpni_msg_stats); > } > rc = 0; > > +out_free_msg_stats: > + kfree(lpni_msg_stats); > out_free_stats: > kfree(lpni_stats); > out_free_info: > > > From jsimmons at infradead.org Sun Oct 14 23:52:34 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:52:34 +0100 (BST) Subject: [lustre-devel] [PATCH 23/24] lustre: lnet: show peer state In-Reply-To: <153895437844.16383.527689917065770648.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437844.16383.527689917065770648.stgit@noble> Message-ID: > From: Amir Shehata > > It is important to show the peer state when debugging. > This patch exports the peer state from the kernel to > user space, and is shown when the detail level requested > in the peer show command is >= 3 Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > Signed-off-by: Amir Shehata > Signed-off-by: Olaf Weber > Reviewed-on: https://review.whamcloud.com/26130 > Reviewed-by: Olaf Weber > Reviewed-by: Dmitry Eremin > Signed-off-by: NeilBrown > --- > .../staging/lustre/include/linux/lnet/lib-lnet.h | 4 +--- > drivers/staging/lustre/lnet/lnet/api-ni.c | 6 +----- > drivers/staging/lustre/lnet/lnet/peer.c | 21 ++++++++++---------- > 3 files changed, 12 insertions(+), 19 deletions(-) > > diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > index 91980f60a50d..fcfd844e0162 100644 > --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > @@ -733,9 +733,7 @@ bool lnet_peer_is_pref_nid_locked(struct lnet_peer_ni *lpni, lnet_nid_t nid); > int lnet_peer_ni_set_non_mr_pref_nid(struct lnet_peer_ni *lpni, lnet_nid_t nid); > int lnet_add_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid, bool mr); > int lnet_del_peer_ni(lnet_nid_t key_nid, lnet_nid_t nid); > -int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nid, > - __u32 *nnis, bool *mr, __u32 *sizep, > - void __user *bulk); > +int lnet_get_peer_info(struct lnet_ioctl_peer_cfg *cfg, void __user *bulk); > int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > char alivness[LNET_MAX_STR_LEN], > __u32 *cpt_iter, __u32 *refcount, > diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c > index 0852118bf803..e2c86b8279e5 100644 > --- a/drivers/staging/lustre/lnet/lnet/api-ni.c > +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c > @@ -3166,11 +3166,7 @@ LNetCtl(unsigned int cmd, void *arg) > return -EINVAL; > > mutex_lock(&the_lnet.ln_api_mutex); > - rc = lnet_get_peer_info(&cfg->prcfg_prim_nid, > - &cfg->prcfg_cfg_nid, > - &cfg->prcfg_count, > - &cfg->prcfg_mr, > - &cfg->prcfg_size, > + rc = lnet_get_peer_info(cfg, > (void __user *)cfg->prcfg_bulk); > mutex_unlock(&the_lnet.ln_api_mutex); > return rc; > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 03c1c34517e4..5f61fca09f44 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -3296,9 +3296,7 @@ lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, > } > > /* ln_api_mutex is held, which keeps the peer list stable */ > -int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > - __u32 *nnis, bool *mr, __u32 *sizep, > - void __user *bulk) > +int lnet_get_peer_info(struct lnet_ioctl_peer_cfg *cfg, void __user *bulk) > { > struct lnet_ioctl_element_stats *lpni_stats; > struct lnet_ioctl_element_msg_stats *lpni_msg_stats; > @@ -3309,7 +3307,7 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > __u32 size; > int rc; > > - lp = lnet_find_peer(*primary_nid); > + lp = lnet_find_peer(cfg->prcfg_prim_nid); > > if (!lp) { > rc = -ENOENT; > @@ -3319,17 +3317,18 @@ int lnet_get_peer_info(lnet_nid_t *primary_nid, lnet_nid_t *nidp, > size = sizeof(nid) + sizeof(*lpni_info) + sizeof(*lpni_stats) > + sizeof(*lpni_msg_stats); > size *= lp->lp_nnis; > - if (size > *sizep) { > - *sizep = size; > + if (size > cfg->prcfg_size) { > + cfg->prcfg_size = size; > rc = -E2BIG; > goto out_lp_decref; > } > > - *primary_nid = lp->lp_primary_nid; > - *mr = lnet_peer_is_multi_rail(lp); > - *nidp = lp->lp_primary_nid; > - *nnis = lp->lp_nnis; > - *sizep = size; > + cfg->prcfg_prim_nid = lp->lp_primary_nid; > + cfg->prcfg_mr = lnet_peer_is_multi_rail(lp); > + cfg->prcfg_cfg_nid = lp->lp_primary_nid; > + cfg->prcfg_count = lp->lp_nnis; > + cfg->prcfg_size = size; > + cfg->prcfg_state = lp->lp_state; > > /* Allocate helper buffers. */ > rc = -ENOMEM; > > > From jsimmons at infradead.org Sun Oct 14 23:53:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:53:51 +0100 (BST) Subject: [lustre-devel] [PATCH 24/24] lustre: lnet: balance references in lnet_discover_peer_locked() In-Reply-To: <153895437848.16383.5882317080014923551.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437848.16383.5882317080014923551.stgit@noble> Message-ID: > From: John L. Hammond > > In lnet_discover_peer_locked() avoid a leaked reference to the peer in > the non-blocking discovery case. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9913 > Signed-off-by: John L. Hammond > Reviewed-on: https://review.whamcloud.com/28695 > Reviewed-by: Olaf Weber > Reviewed-by: Quentin Bouget > Reviewed-by: Oleg Drokin > Signed-off-by: NeilBrown > --- > drivers/staging/lustre/lnet/lnet/peer.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 5f61fca09f44..db36b5cf31e1 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -2010,7 +2010,6 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) > if (lnet_peer_is_uptodate(lp)) > break; > lnet_peer_queue_for_discovery(lp); > - lnet_peer_addref_locked(lp); > /* > * if caller requested a non-blocking operation then > * return immediately. Once discovery is complete then the > @@ -2019,6 +2018,8 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) > */ > if (!block) > break; > + > + lnet_peer_addref_locked(lp); > lnet_net_unlock(LNET_LOCK_EX); > schedule(); > finish_wait(&lp->lp_dc_waitq, &wait); > > > From jsimmons at infradead.org Sun Oct 14 23:54:06 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:54:06 +0100 (BST) Subject: [lustre-devel] [PATCH 24/24] lustre: lnet: balance references in lnet_discover_peer_locked() In-Reply-To: <153895437848.16383.5882317080014923551.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437848.16383.5882317080014923551.stgit@noble> Message-ID: > From: John L. Hammond > > In lnet_discover_peer_locked() avoid a leaked reference to the peer in > the non-blocking discovery case. Reviewed-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-9913 > Signed-off-by: John L. Hammond > Reviewed-on: https://review.whamcloud.com/28695 > Reviewed-by: Olaf Weber > Reviewed-by: Quentin Bouget > Reviewed-by: Oleg Drokin > Signed-off-by: NeilBrown > --- > drivers/staging/lustre/lnet/lnet/peer.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c > index 5f61fca09f44..db36b5cf31e1 100644 > --- a/drivers/staging/lustre/lnet/lnet/peer.c > +++ b/drivers/staging/lustre/lnet/lnet/peer.c > @@ -2010,7 +2010,6 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) > if (lnet_peer_is_uptodate(lp)) > break; > lnet_peer_queue_for_discovery(lp); > - lnet_peer_addref_locked(lp); > /* > * if caller requested a non-blocking operation then > * return immediately. Once discovery is complete then the > @@ -2019,6 +2018,8 @@ lnet_discover_peer_locked(struct lnet_peer_ni *lpni, int cpt, bool block) > */ > if (!block) > break; > + > + lnet_peer_addref_locked(lp); > lnet_net_unlock(LNET_LOCK_EX); > schedule(); > finish_wait(&lp->lp_dc_waitq, &wait); > > > From jsimmons at infradead.org Sun Oct 14 23:54:55 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 15 Oct 2018 00:54:55 +0100 (BST) Subject: [lustre-devel] [PATCH 00/24] Port Dynamic Discovery to drivers/staging In-Reply-To: <153895417139.16383.3791701638653772865.stgit@noble> References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: > This is a port of the "Dynamic Discovery" series > (756abb9cf00b936b3..1c45d9051764e0637ba90b3) > to my mainline-linux-with-lustre tree. > It is all fairly straight forward, but I don't think I have the > hardware to testing properly. And review never hurts. > > This is all in my lustre-testing branch. Only one patch was incorrect but the verison in lustre-testing is fine. Testing has shown no problems. > Thanks, > NeilBrown > > --- > > Amir Shehata (2): > lustre: lnet: add enhanced statistics > lustre: lnet: show peer state > > John L. Hammond (1): > lustre: lnet: balance references in lnet_discover_peer_locked() > > Olaf Weber (20): > lustre: lnet: add lnet_interfaces_max tunable > lustre: lnet: configure lnet_interfaces_max tunable from dlc > lustre: lnet: add struct lnet_ping_buffer > lustre: lnet: automatic sizing of router pinger buffers > lustre: lnet: add Multi-Rail and Discovery ping feature bits > lustre: lnet: add sanity checks on ping-related constants > lustre: lnet: cleanup of lnet_peer_ni_addref/decref_locked() > lustre: lnet: rename lnet_add/del_peer_ni_to/from_peer() > lustre: lnet: refactor lnet_del_peer_ni() > lustre: lnet: refactor lnet_add_peer_ni() > lustre: lnet: introduce LNET_PEER_MULTI_RAIL flag bit > lustre: lnet: preferred NIs for non-Multi-Rail peers > lustre: lnet: add LNET_PEER_CONFIGURED flag > lustre: lnet: reference counts on lnet_peer/lnet_peer_net > lustre: lnet: add msg_type to lnet_event > lustre: lnet: add discovery thread > lustre: lnet: add the Push target > lustre: lnet: implement Peer Discovery > lustre: lnet: add "lnetctl peer list" > lustre: lnet: add "lnetctl ping" command > > Sonia Sharma (1): > lustre: lnet: add "lnetctl discover" > > > .../staging/lustre/include/linux/lnet/lib-lnet.h | 156 + > .../staging/lustre/include/linux/lnet/lib-types.h | 258 ++ > .../lustre/include/uapi/linux/lnet/libcfs_ioctl.h | 8 > .../lustre/include/uapi/linux/lnet/lnet-dlc.h | 10 > .../lustre/include/uapi/linux/lnet/lnet-types.h | 42 > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 2 > .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 2 > .../staging/lustre/lnet/klnds/socklnd/socklnd.c | 22 > .../staging/lustre/lnet/klnds/socklnd/socklnd.h | 4 > .../staging/lustre/lnet/klnds/socklnd/socklnd_cb.c | 2 > .../lustre/lnet/klnds/socklnd/socklnd_modparams.c | 2 > .../lustre/lnet/klnds/socklnd/socklnd_proto.c | 4 > drivers/staging/lustre/lnet/lnet/api-ni.c | 907 +++++- > drivers/staging/lustre/lnet/lnet/config.c | 10 > drivers/staging/lustre/lnet/lnet/lib-move.c | 242 +- > drivers/staging/lustre/lnet/lnet/lib-msg.c | 17 > drivers/staging/lustre/lnet/lnet/net_fault.c | 3 > drivers/staging/lustre/lnet/lnet/peer.c | 3002 +++++++++++++++++--- > drivers/staging/lustre/lnet/lnet/router.c | 174 + > 19 files changed, 4056 insertions(+), 811 deletions(-) > > -- > Signature > > From neilb at suse.com Wed Oct 17 05:16:51 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 17 Oct 2018 16:16:51 +1100 Subject: [lustre-devel] [PATCH 14/24] lustre: lnet: reference counts on lnet_peer/lnet_peer_net In-Reply-To: References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437808.16383.1725584261522697360.stgit@noble> Message-ID: <87o9btduf0.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: >> From: Olaf Weber >> >> Peer discovery will be keeping track of lnet_peer structures, >> so there will be references to an lnet_peer independent of >> the references implied by lnet_peer_ni structures. Manage >> this by adding explicit reference counts to lnet_peer_net and >> lnet_peer. >> >> Each lnet_peer_net has a hold on the lnet_peer it links to >> with its lpn_peer pointer. This hold is only removed when that >> pointer is assigned a new value or the lnet_peer_net is freed. >> Just removing an lnet_peer_net from the lp_peer_nets list does >> not release this hold, it just prevents new lookups of the >> lnet_peer_net via the lnet_peer. >> >> Each lnet_peer_ni has a hold on the lnet_peer_net it links to >> with its lpni_peer_net pointer. This hold is only removed when >> that pointer is assigned a new value or the lnet_peer_ni is >> freed. Just removing an lnet_peer_ni from the lpn_peer_nis >> list does not release this hold, it just prevents new lookups >> of the lnet_peer_ni via the lnet_peer_net. >> >> This ensures that given a lnet_peer_ni *lpni, we can rely on >> lpni->lpni_peer_net->lpn_peer pointing to a valid lnet_peer. >> >> Keep a count of the total number of lnet_peer_ni attached to >> an lnet_peer in lp_nnis. >> >> Split the global ln_peers list into per-lnet_peer_table lists. >> The CPT of the peer table in which the lnet_peer is linked is >> stored in lp_cpt. >> >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 >> Signed-off-by: Olaf Weber >> Reviewed-on: https://review.whamcloud.com/25784 >> Reviewed-by: Olaf Weber >> Reviewed-by: Amir Shehata >> Tested-by: Amir Shehata >> Signed-off-by: NeilBrown >> --- >> .../staging/lustre/include/linux/lnet/lib-lnet.h | 49 +++-- >> .../staging/lustre/include/linux/lnet/lib-types.h | 50 ++++- >> drivers/staging/lustre/lnet/lnet/api-ni.c | 1 >> drivers/staging/lustre/lnet/lnet/lib-move.c | 8 - >> drivers/staging/lustre/lnet/lnet/peer.c | 210 ++++++++++++++------ >> 5 files changed, 227 insertions(+), 91 deletions(-) >> >> diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> index 563417510722..aad25eb0011b 100644 >> --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h >> @@ -310,6 +310,36 @@ lnet_handle2me(struct lnet_handle_me *handle) >> return lh_entry(lh, struct lnet_me, me_lh); >> } >> >> +static inline void >> +lnet_peer_net_addref_locked(struct lnet_peer_net *lpn) >> +{ >> + atomic_inc(&lpn->lpn_refcount); >> +} >> + >> +void lnet_destroy_peer_net_locked(struct lnet_peer_net *lpn); >> + >> +static inline void >> +lnet_peer_net_decref_locked(struct lnet_peer_net *lpn) >> +{ >> + if (atomic_dec_and_test(&lpn->lpn_refcount)) >> + lnet_destroy_peer_net_locked(lpn); >> +} >> + >> +static inline void >> +lnet_peer_addref_locked(struct lnet_peer *lp) >> +{ >> + atomic_inc(&lp->lp_refcount); >> +} >> + >> +void lnet_destroy_peer_locked(struct lnet_peer *lp); >> + >> +static inline void >> +lnet_peer_decref_locked(struct lnet_peer *lp) >> +{ >> + if (atomic_dec_and_test(&lp->lp_refcount)) >> + lnet_destroy_peer_locked(lp); >> +} >> + >> static inline void >> lnet_peer_ni_addref_locked(struct lnet_peer_ni *lp) >> { >> @@ -695,21 +725,6 @@ int lnet_get_peer_ni_info(__u32 peer_index, __u64 *nid, >> __u32 *peer_rtr_credits, __u32 *peer_min_rtr_credtis, >> __u32 *peer_tx_qnob); >> >> -static inline __u32 >> -lnet_get_num_peer_nis(struct lnet_peer *peer) >> -{ >> - struct lnet_peer_net *lpn; >> - struct lnet_peer_ni *lpni; >> - __u32 count = 0; >> - >> - list_for_each_entry(lpn, &peer->lp_peer_nets, lpn_on_peer_list) >> - list_for_each_entry(lpni, &lpn->lpn_peer_nis, >> - lpni_on_peer_net_list) >> - count++; >> - >> - return count; >> -} >> - >> static inline bool >> lnet_is_peer_ni_healthy_locked(struct lnet_peer_ni *lpni) >> { >> @@ -728,7 +743,7 @@ lnet_is_peer_net_healthy_locked(struct lnet_peer_net *peer_net) >> struct lnet_peer_ni *lpni; >> >> list_for_each_entry(lpni, &peer_net->lpn_peer_nis, >> - lpni_on_peer_net_list) { >> + lpni_peer_nis) { >> if (lnet_is_peer_ni_healthy_locked(lpni)) >> return true; >> } >> @@ -741,7 +756,7 @@ lnet_is_peer_healthy_locked(struct lnet_peer *peer) >> { >> struct lnet_peer_net *peer_net; >> >> - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { >> + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { >> if (lnet_is_peer_net_healthy_locked(peer_net)) >> return true; >> } >> diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h >> index d1721fd01d93..260619e19bde 100644 >> --- a/drivers/staging/lustre/include/linux/lnet/lib-types.h >> +++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h >> @@ -411,7 +411,8 @@ struct lnet_rc_data { >> }; >> >> struct lnet_peer_ni { >> - struct list_head lpni_on_peer_net_list; >> + /* chain on lpn_peer_nis */ >> + struct list_head lpni_peer_nis; >> /* chain on remote peer list */ >> struct list_head lpni_on_remote_peer_ni_list; >> /* chain on peer hash */ >> @@ -496,8 +497,8 @@ struct lnet_peer_ni { >> #define LNET_PEER_NI_NON_MR_PREF BIT(0) >> >> struct lnet_peer { >> - /* chain on global peer list */ >> - struct list_head lp_on_lnet_peer_list; >> + /* chain on pt_peer_list */ >> + struct list_head lp_peer_list; >> >> /* list of peer nets */ >> struct list_head lp_peer_nets; >> @@ -505,6 +506,15 @@ struct lnet_peer { >> /* primary NID of the peer */ >> lnet_nid_t lp_primary_nid; >> >> + /* CPT of peer_table */ >> + int lp_cpt; >> + >> + /* number of NIDs on this peer */ >> + int lp_nnis; >> + >> + /* reference count */ >> + atomic_t lp_refcount; >> + >> /* lock protecting peer state flags */ >> spinlock_t lp_lock; >> >> @@ -516,8 +526,8 @@ struct lnet_peer { >> #define LNET_PEER_CONFIGURED BIT(1) >> >> struct lnet_peer_net { >> - /* chain on peer block */ >> - struct list_head lpn_on_peer_list; >> + /* chain on lp_peer_nets */ >> + struct list_head lpn_peer_nets; >> >> /* list of peer_nis on this network */ >> struct list_head lpn_peer_nis; >> @@ -527,21 +537,45 @@ struct lnet_peer_net { >> >> /* Net ID */ >> __u32 lpn_net_id; >> + >> + /* reference count */ >> + atomic_t lpn_refcount; >> }; >> >> /* peer hash size */ >> #define LNET_PEER_HASH_BITS 9 >> #define LNET_PEER_HASH_SIZE (1 << LNET_PEER_HASH_BITS) >> >> -/* peer hash table */ >> +/* >> + * peer hash table - one per CPT >> + * >> + * protected by lnet_net_lock/EX for update >> + * pt_version >> + * pt_number >> + * pt_hash[...] >> + * pt_peer_list >> + * pt_peers >> + * pt_peer_nnids >> + * protected by pt_zombie_lock: >> + * pt_zombie_list >> + * pt_zombies >> + * >> + * pt_zombie lock nests inside lnet_net_lock >> + */ >> struct lnet_peer_table { >> /* /proc validity stamp */ >> int pt_version; >> /* # peers extant */ >> atomic_t pt_number; >> + /* peers */ >> + struct list_head pt_peer_list; >> + /* # peers */ >> + int pt_peers; >> + /* # NIDS on listed peers */ >> + int pt_peer_nnids; >> /* # zombies to go to deathrow (and not there yet) */ >> int pt_zombies; >> - /* zombie peers */ >> + /* zombie peers_ni */ >> struct list_head pt_zombie_list; >> /* protect list and count */ >> spinlock_t pt_zombie_lock; >> @@ -785,8 +819,6 @@ struct lnet { >> struct lnet_msg_container **ln_msg_containers; >> struct lnet_counters **ln_counters; >> struct lnet_peer_table **ln_peer_tables; >> - /* list of configured or discovered peers */ >> - struct list_head ln_peers; >> /* list of peer nis not on a local network */ >> struct list_head ln_remote_peer_ni_list; >> /* failure simulation */ >> diff --git a/drivers/staging/lustre/lnet/lnet/api-ni.c b/drivers/staging/lustre/lnet/lnet/api-ni.c >> index d64ae2939abc..c48bcb8722a0 100644 >> --- a/drivers/staging/lustre/lnet/lnet/api-ni.c >> +++ b/drivers/staging/lustre/lnet/lnet/api-ni.c >> @@ -625,7 +625,6 @@ lnet_prepare(lnet_pid_t requested_pid) >> the_lnet.ln_pid = requested_pid; >> >> INIT_LIST_HEAD(&the_lnet.ln_test_peers); >> - INIT_LIST_HEAD(&the_lnet.ln_peers); >> INIT_LIST_HEAD(&the_lnet.ln_remote_peer_ni_list); >> INIT_LIST_HEAD(&the_lnet.ln_nets); >> INIT_LIST_HEAD(&the_lnet.ln_routers); >> diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c >> index 99d8b22356bb..4c1eef907dc7 100644 >> --- a/drivers/staging/lustre/lnet/lnet/lib-move.c >> +++ b/drivers/staging/lustre/lnet/lnet/lib-move.c >> @@ -1388,7 +1388,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, >> peer_net = lnet_peer_get_net_locked( >> peer, LNET_NIDNET(best_lpni->lpni_nid)); >> list_for_each_entry(lpni, &peer_net->lpn_peer_nis, >> - lpni_on_peer_net_list) { >> + lpni_peer_nis) { >> if (lpni->lpni_pref_nnids == 0) >> continue; >> LASSERT(lpni->lpni_pref_nnids == 1); >> @@ -1411,7 +1411,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, >> } >> lpni = list_entry(peer_net->lpn_peer_nis.next, >> struct lnet_peer_ni, >> - lpni_on_peer_net_list); >> + lpni_peer_nis); >> } >> /* Set preferred NI if necessary. */ >> if (lpni->lpni_pref_nnids == 0) >> @@ -1443,7 +1443,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, >> * then the best route is chosen. If all routes are equal then >> * they are used in round robin. >> */ >> - list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_on_peer_list) { >> + list_for_each_entry(peer_net, &peer->lp_peer_nets, lpn_peer_nets) { >> if (!lnet_is_peer_net_healthy_locked(peer_net)) >> continue; >> >> @@ -1453,7 +1453,7 @@ lnet_select_pathway(lnet_nid_t src_nid, lnet_nid_t dst_nid, >> >> lpni = list_entry(peer_net->lpn_peer_nis.next, >> struct lnet_peer_ni, >> - lpni_on_peer_net_list); >> + lpni_peer_nis); >> >> net_gw = lnet_find_route_locked(NULL, >> lpni->lpni_nid, >> diff --git a/drivers/staging/lustre/lnet/lnet/peer.c b/drivers/staging/lustre/lnet/lnet/peer.c >> index 09c1b5516f6b..d7a0a2f3bdd9 100644 >> --- a/drivers/staging/lustre/lnet/lnet/peer.c >> +++ b/drivers/staging/lustre/lnet/lnet/peer.c > > INIT_LIST_HEAD(&ptable->pt_peer_list); seems to be missing from > lnet_peer_tables_create(). This is in the patch merged into > lustre-testing. Other than that it looks okay. No, it is there. It is just the the lnet_peer_tables_create() has moved, so it isn't in the same place in the patch. ..snip.. >> @@ -319,6 +358,8 @@ lnet_peer_tables_create(void) >> spin_lock_init(&ptable->pt_zombie_lock); >> INIT_LIST_HEAD(&ptable->pt_zombie_list); >> >> + INIT_LIST_HEAD(&ptable->pt_peer_list); >> + >> for (j = 0; j < LNET_PEER_HASH_SIZE; j++) >> INIT_LIST_HEAD(&hash[j]); >> ptable->pt_hash = hash; /* sign of initialization */ here it is. Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 05:20:51 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 17 Oct 2018 16:20:51 +1100 Subject: [lustre-devel] [PATCH 00/24] Port Dynamic Discovery to drivers/staging In-Reply-To: References: <153895417139.16383.3791701638653772865.stgit@noble> Message-ID: <87lg6xdu8c.fsf@notabene.neil.brown.name> On Mon, Oct 15 2018, James Simmons wrote: >> This is a port of the "Dynamic Discovery" series >> (756abb9cf00b936b3..1c45d9051764e0637ba90b3) >> to my mainline-linux-with-lustre tree. >> It is all fairly straight forward, but I don't think I have the >> hardware to testing properly. And review never hurts. >> >> This is all in my lustre-testing branch. > > Only one patch was incorrect but the verison in lustre-testing is fine. > Testing has shown no problems. Excellent - thanks for the review! NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 05:54:40 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 17 Oct 2018 16:54:40 +1100 Subject: [lustre-devel] [PATCH 01/10] lustre: lnd: set device capabilities In-Reply-To: <1539543332-28679-2-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-2-git-send-email-jsimmons@infradead.org> Message-ID: <87efcpdsnz.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Amir Shehata > > MLX-4, MLX-5 and OPA support different capabilities. Query the > device and cache the capabilities of the device for future use. > > At the time of the patches creation MLX5 could support fast > registration and gaps while MLX4 and OPA only support FMR > > Signed-off-by: Amir Shehata > WC-bug-id: https://jira.whamcloud.com/browse/LU-10129 > Reviewed-on: https://review.whamcloud.com/30309 > Reviewed-by: Alexey Lyashkov > Reviewed-by: Dmitry Eremin > Reviewed-by: James Simmons > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 41 ++++++++++++---------- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 5 +++ > 2 files changed, 28 insertions(+), 18 deletions(-) > > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > index bf969b3..b10658b 100644 > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > @@ -1399,6 +1399,7 @@ static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_poo > else > CERROR("FMRs are not supported\n"); > } > + fpo->fpo_is_fmr = true; > > return rc; > } > @@ -1408,6 +1409,8 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po > struct kib_fast_reg_descriptor *frd; > int i, rc; > > + fpo->fpo_is_fmr = false; > + > INIT_LIST_HEAD(&fpo->fast_reg.fpo_pool_list); > fpo->fast_reg.fpo_pool_size = 0; > for (i = 0; i < fps->fps_pool_size; i++) { > @@ -1469,23 +1472,7 @@ static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, > fpo->fpo_hdev = kiblnd_current_hdev(dev); > dev_attr = &fpo->fpo_hdev->ibh_ibdev->attrs; > > - /* Check for FMR or FastReg support */ > - fpo->fpo_is_fmr = 0; > - if (fpo->fpo_hdev->ibh_ibdev->alloc_fmr && > - fpo->fpo_hdev->ibh_ibdev->dealloc_fmr && > - fpo->fpo_hdev->ibh_ibdev->map_phys_fmr && > - fpo->fpo_hdev->ibh_ibdev->unmap_fmr) { > - LCONSOLE_INFO("Using FMR for registration\n"); > - fpo->fpo_is_fmr = 1; > - } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { > - LCONSOLE_INFO("Using FastReg for registration\n"); > - } else { > - rc = -ENOSYS; > - LCONSOLE_ERROR_MSG(rc, "IB device does not support FMRs nor FastRegs, can't register memory\n"); > - goto out_fpo; > - } > - > - if (fpo->fpo_is_fmr) > + if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) > rc = kiblnd_alloc_fmr_pool(fps, fpo); > else > rc = kiblnd_alloc_freg_pool(fps, fpo); > @@ -2261,6 +2248,9 @@ static int kiblnd_net_init_pools(struct kib_net *net, struct lnet_ni *ni, > > static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) > { > + struct ib_device_attr *dev_attr = &hdev->ibh_ibdev->attrs; > + int rc = 0; > + > /* > * It's safe to assume a HCA can handle a page size > * matching that of the native system > @@ -2269,7 +2259,22 @@ static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) > hdev->ibh_page_size = 1 << PAGE_SHIFT; > hdev->ibh_page_mask = ~((__u64)hdev->ibh_page_size - 1); > > - hdev->ibh_mr_size = hdev->ibh_ibdev->attrs.max_mr_size; > + if (hdev->ibh_ibdev->alloc_fmr && > + hdev->ibh_ibdev->dealloc_fmr && > + hdev->ibh_ibdev->map_phys_fmr && > + hdev->ibh_ibdev->unmap_fmr) { > + LCONSOLE_INFO("Using FMR for registration\n"); > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FMR_ENABLED; > + } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { > + LCONSOLE_INFO("Using FastReg for registration\n"); > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_ENABLED; > + } else { > + CERROR("IB device does not support FMRs nor FastRegs, can't register memory: %d\n", > + rc); > + return -ENXIO; > + } > + > + hdev->ibh_mr_size = dev_attr->max_mr_size; > if (hdev->ibh_mr_size == ~0ULL) { > hdev->ibh_mr_shift = 64; > return 0; > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > index a4438d2..9f0a47d 100644 > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > @@ -73,6 +73,10 @@ > #define IBLND_N_SCHED 2 > #define IBLND_N_SCHED_HIGH 4 > > +#define IBLND_DEV_CAPS_FASTREG_ENABLED 0x1 > +#define IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT 0x2 > +#define IBLND_DEV_CAPS_FMR_ENABLED 0x4 > + BIT(0), BIT(1), .... ??? > struct kib_tunables { > int *kib_dev_failover; /* HCA failover */ > unsigned int *kib_service; /* IB service number */ > @@ -162,6 +166,7 @@ struct kib_dev { > unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ > struct list_head ibd_nets; > struct kib_hca_dev *ibd_hdev; > + u32 ibd_dev_caps; "unsigned int" would be better I think, but it isn't very important. Thanks, NeilBrown > }; > > struct kib_hca_dev { > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 06:11:33 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 17 Oct 2018 17:11:33 +1100 Subject: [lustre-devel] [PATCH 03/10] lustre: lnd: rework map_on_demand behavior In-Reply-To: <1539543332-28679-4-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-4-git-send-email-jsimmons@infradead.org> Message-ID: <87bm7tdrvu.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > @@ -1320,9 +1324,8 @@ static void kiblnd_destroy_fmr_pool(struct kib_fmr_pool *fpo) > { > LASSERT(!fpo->fpo_map_count); > > - if (fpo->fpo_is_fmr) { > - if (fpo->fmr.fpo_fmr_pool) > - ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); > + if (fpo->fpo_is_fmr && fpo->fmr.fpo_fmr_pool) { > + ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); > } else { > struct kib_fast_reg_descriptor *frd; > int i = 0; This change looks strange. With the new code: if fpo_fmr_pool is NULL, then the fpo_pool_list is destroyed, even though fpo_is_fmr. Are we sure that is correct?? I don't really understand this code so it might be correct, but the change looks wrong. Can someone please confirm that it really is right - and maybe explain why? Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 22:43:01 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 09:43:01 +1100 Subject: [lustre-devel] [PATCH 03/28] lustre: ptlrpc: missing barrier before wake_up In-Reply-To: <1539543498-29105-4-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-4-git-send-email-jsimmons@infradead.org> Message-ID: <87y3awchze.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Lai Siyao > > ptlrpc_client_wake_req() misses a memory barrier, which may cause > strange errors. > > Signed-off-by: Lai Siyao > WC-bug-id: https://jira.whamcloud.com/browse/LU-8935 > Reviewed-on: https://review.whamcloud.com/26583 > Reviewed-by: Andreas Dilger > Reviewed-by: Wang Shilong > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/include/lustre_net.h | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h > index ce7e98c..468a03e 100644 > --- a/drivers/staging/lustre/lustre/include/lustre_net.h > +++ b/drivers/staging/lustre/lustre/include/lustre_net.h > @@ -2211,6 +2211,8 @@ static inline int ptlrpc_status_ntoh(int n) > static inline void > ptlrpc_client_wake_req(struct ptlrpc_request *req) > { > + /* ensure ptlrpc_register_bulk see rq_resend as set. */ > + smp_mb(); > if (!req->rq_set) > wake_up(&req->rq_reply_waitq); > else It is good that this memory barrier has a comment, but the comment isn't very helpful. There is no matching memory barrier in ptlrpc_register_bulk(), so it isn't clear what sequencing is important. And ptl_send_rpc() tests ->rq_resend *before* ptlrpc_register_bulk() is called (which also tests it). Presumably these should see that same value? So why does the comment refer to ptlrpc_register_bulk() instead of ptl_send_rpc() ?? It all seems rather confusing, so it is very hard to be sure that the code is now correct. Is someone able to explain? Thanks, NeilBrown > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 23:13:54 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 10:13:54 +1100 Subject: [lustre-devel] [PATCH 04/28] lustre: ptlrpc: Do not assert when bd_nob_transferred != 0 In-Reply-To: <1539543498-29105-5-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-5-git-send-email-jsimmons@infradead.org> Message-ID: <87va60cgjx.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Doug Oucharek > > There is a case in the routine ptlrpc_register_bulk() where we were > asserting if bd_nob_transferred != 0 when not resending. There is > evidence that network errors can create a situation where > this does happen. So we should not be asserting! > > This patch changes that assert to an error return code of -EIO. > > Signed-off-by: Doug Oucharek > WC-bug-id: https://jira.whamcloud.com/browse/LU-9828 > Reviewed-on: https://review.whamcloud.com/28491 > Reviewed-by: Dmitry Eremin > Reviewed-by: Sonia Sharma > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 8 ++++++-- > 1 file changed, 6 insertions(+), 2 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > index 27eb1c0..7e7db24 100644 > --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > @@ -139,8 +139,12 @@ static int ptlrpc_register_bulk(struct ptlrpc_request *req) > /* cleanup the state of the bulk for it will be reused */ > if (req->rq_resend || req->rq_send_state == LUSTRE_IMP_REPLAY) > desc->bd_nob_transferred = 0; > - else > - LASSERT(desc->bd_nob_transferred == 0); > + else if (desc->bd_nob_transferred != 0) > + /* If the network failed after an RPC was sent, this condition > + * could happen. Rather than assert (was here before), return > + * an EIO error. > + */ > + return -EIO; This looks weird, and the justification is rather lame. I wonder if this is an attempt to fix the same problem that the smp_mb() in the previous patch was attempting to fix (and I'm not yet convinced that either is the correct fix). NeilBrown > > desc->bd_failure = 0; > > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 23:20:37 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 10:20:37 +1100 Subject: [lustre-devel] [PATCH 06/28] lustre: ldlm: ELC shouldn't wait on lock flush In-Reply-To: <1539543498-29105-7-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-7-git-send-email-jsimmons@infradead.org> Message-ID: <87sh14cg8q.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Andriy Skulysh > > The commit 08fd034670b5 ("staging: lustre: ldlm: revert the changes > for lock canceling policy") removed the fix for LU-4300 when lru_resize > is disabled. > > Introduce ldlm_cancel_aged_no_wait_policy to be used by ELC. > > Signed-off-by: Andriy Skulysh > WC-bug-id: https://jira.whamcloud.com/browse/LU-8578 > Seagate-bug-id: MRP-3662 > Reviewed-on: https://review.whamcloud.com/22286 > Reviewed-by: Vitaly Fertman > Reviewed-by: Patrick Farrell > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 1 - > drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 51 +++++++++++++++------- > 2 files changed, 35 insertions(+), 17 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > index 1d7c727..709c527 100644 > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > @@ -96,7 +96,6 @@ enum { > LDLM_LRU_FLAG_NO_WAIT = BIT(4), /* Cancel locks w/o blocking (neither > * sending nor waiting for any rpcs) > */ > - LDLM_LRU_FLAG_LRUR_NO_WAIT = BIT(5), /* LRUR + NO_WAIT */ > }; > > int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr, > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > index 80260b07..3eb5036 100644 > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > @@ -579,8 +579,8 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req, > req_capsule_filled_sizes(pill, RCL_CLIENT); > avail = ldlm_capsule_handles_avail(pill, RCL_CLIENT, canceloff); > > - flags = ns_connect_lru_resize(ns) ? > - LDLM_LRU_FLAG_LRUR_NO_WAIT : LDLM_LRU_FLAG_AGED; > + flags = LDLM_LRU_FLAG_NO_WAIT | ns_connect_lru_resize(ns) ? > + LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED; > to_free = !ns_connect_lru_resize(ns) && > opc == LDLM_ENQUEUE ? 1 : 0; Bug. The commit in SFS-lustre (7ca60f33893) is correct, but you dropped the parentheses which introduces a bug. While the SFS code is correct, it is formatted badly. It should be lru_flags = LDLM_LRU_FLAG_NO_WAIT | (ns_connect_lru_resize(ns) ? LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED); or similar. NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 17 23:34:25 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 10:34:25 +1100 Subject: [lustre-devel] [PATCH 11/28] lustre: llite: use security context if it's enabled in the kernel In-Reply-To: <1539543498-29105-12-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-12-git-send-email-jsimmons@infradead.org> Message-ID: <87pnw8cflq.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Alex Zhuravlev > > if it's disabled, then Lustre stop to work properly (can not create > files, etc) > > Signed-off-by: Alex Zhuravlev > WC-bug-id: https://jira.whamcloud.com/browse/LU-9578 > Reviewed-on: https://review.whamcloud.com/27364 > Reviewed-by: Andreas Dilger > Reviewed-by: Chris Horn > Reviewed-by: James Simmons > Reviewed-by: Sebastien Buisson > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/llite/llite_lib.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c > index 22b545e..153aa12 100644 > --- a/drivers/staging/lustre/lustre/llite/llite_lib.c > +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c > @@ -243,8 +243,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) > if (sbi->ll_flags & LL_SBI_ALWAYS_PING) > data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; > > +#ifdef CONFIG_SECURITY > data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; > - > +#endif Policy is to avoid #ifdef in .c files where possible. If we put something like #ifdef CONFIG_SECURITY #define OBD_CONNECT2_FILE_SECURITY (OBD_CONNECT2_FILE_SECCTX) #else #define OBD_CONNECT2_FILE_SECURITY (0) #endif in a .h file, then use OBD_CONNECT2_FILE_SECURITY both here and in obd_connect_has_secctx(), then the latter could would be optimized away by the compiler. Wouldn't be a big win I guess as it is only used once in a trivial context. NeilBrown > data->ocd_brw_size = MD_MAX_BRW_SIZE; > > err = obd_connect(NULL, &sbi->ll_md_exp, sbi->ll_md_obd, > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 01:48:33 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 12:48:33 +1100 Subject: [lustre-devel] [PATCH 15/28] lustre: llite: fix for stat under kthread and X86_X32 In-Reply-To: <1539543498-29105-16-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-16-git-send-email-jsimmons@infradead.org> Message-ID: <87ftx4c9e6.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Frank Zago > > Under the following conditions, ll_getattr will flatten the inode > number when it shouldn't: > > - the X86_X32 architecture is defined CONFIG_X86_X32, and not even > used, > - ll_getattr is called from a kernel thread (though vfs_getattr for > instance.) > > This has the result that inode numbers are different whether the same > file is stat'ed from a kernel thread, or from a syscall. For instance, > 4198401 vs. 144115205272502273. > > ll_getattr calls ll_need_32bit_api to determine whether the task is 32 > bits. When the combination is kthread+X86_X32, that function returns > that the task is 32 bits, which is incorrect, as the kernel is 64 > bits. > > The solution is to check whether the call is from a kernel thread > (which is 64 bits) and act consequently. > > Signed-off-by: Frank Zago > WC-bug-id: https://jira.whamcloud.com/browse/LU-9468 > Reviewed-on: https://review.whamcloud.com/26992 > Reviewed-by: Andreas Dilger > Reviewed-by: Dmitry Eremin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/llite/dir.c | 6 +++--- > drivers/staging/lustre/lustre/llite/lcommon_cl.c | 2 +- > .../staging/lustre/lustre/llite/llite_internal.h | 22 +++++++++++++++++----- > 3 files changed, 21 insertions(+), 9 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c > index 231b351..19c5e9c 100644 > --- a/drivers/staging/lustre/lustre/llite/dir.c > +++ b/drivers/staging/lustre/lustre/llite/dir.c > @@ -202,7 +202,7 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data, > { > struct ll_sb_info *sbi = ll_i2sbi(inode); > __u64 pos = *ppos; > - int is_api32 = ll_need_32bit_api(sbi); > + bool is_api32 = ll_need_32bit_api(sbi); > int is_hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; > struct page *page; > bool done = false; > @@ -296,7 +296,7 @@ static int ll_readdir(struct file *filp, struct dir_context *ctx) > struct ll_sb_info *sbi = ll_i2sbi(inode); > __u64 pos = lfd ? lfd->lfd_pos : 0; > int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; > - int api32 = ll_need_32bit_api(sbi); > + bool api32 = ll_need_32bit_api(sbi); > struct md_op_data *op_data; > int rc; > > @@ -1674,7 +1674,7 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin) > struct inode *inode = file->f_mapping->host; > struct ll_file_data *fd = LUSTRE_FPRIVATE(file); > struct ll_sb_info *sbi = ll_i2sbi(inode); > - int api32 = ll_need_32bit_api(sbi); > + bool api32 = ll_need_32bit_api(sbi); > loff_t ret = -EINVAL; > > switch (origin) { > diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c > index 30f17ea..20a3c74 100644 > --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c > +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c > @@ -267,7 +267,7 @@ void cl_inode_fini(struct inode *inode) > /** > * build inode number from passed @fid > */ > -__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32) > +u64 cl_fid_build_ino(const struct lu_fid *fid, bool api32) > { > if (BITS_PER_LONG == 32 || api32) > return fid_flatten32(fid); > diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h > index dcb2fed..796a8ae 100644 > --- a/drivers/staging/lustre/lustre/llite/llite_internal.h > +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h > @@ -651,13 +651,25 @@ static inline struct inode *ll_info2i(struct ll_inode_info *lli) > __u32 ll_i2suppgid(struct inode *i); > void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2); > > -static inline int ll_need_32bit_api(struct ll_sb_info *sbi) > +static inline bool ll_need_32bit_api(struct ll_sb_info *sbi) > { > #if BITS_PER_LONG == 32 > - return 1; > + return true; > #elif defined(CONFIG_COMPAT) > - return unlikely(in_compat_syscall() || > - (sbi->ll_flags & LL_SBI_32BIT_API)); > + if (unlikely(sbi->ll_flags & LL_SBI_32BIT_API)) > + return true; > + > +#ifdef CONFIG_X86_X32 > + /* in_compat_syscall() returns true when called from a kthread > + * and CONFIG_X86_X32 is enabled, which is wrong. So check > + * whether the caller comes from a syscall (ie. not a kthread) > + * before calling in_compat_syscall(). > + */ > + if (current->flags & PF_KTHREAD) > + return false; > +#endif This is wrong. We should fix in_compat_syscall(), not work around it here. (and then there is that fact that the patch changes 'int' to 'bool' without explaining that in the change description). I've sent a query to some relevant people (Cc:ed to James) to ask about fixing in_compat_syscall(). NeilBrown > + > + return unlikely(in_compat_syscall()); > #else > return unlikely(sbi->ll_flags & LL_SBI_32BIT_API); > #endif > @@ -1353,7 +1365,7 @@ int cl_setattr_ost(struct cl_object *obj, const struct iattr *attr, > int cl_file_inode_init(struct inode *inode, struct lustre_md *md); > void cl_inode_fini(struct inode *inode); > > -__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32); > +u64 cl_fid_build_ino(const struct lu_fid *fid, bool api32); > __u32 cl_fid_build_gen(const struct lu_fid *fid); > > #endif /* LLITE_INTERNAL_H */ > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 02:00:50 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 13:00:50 +1100 Subject: [lustre-devel] [PATCH 16/28] lustre: statahead: missing barrier before wake_up In-Reply-To: <1539543498-29105-17-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-17-git-send-email-jsimmons@infradead.org> Message-ID: <87d0s8c8tp.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Lai Siyao > > A barrier is missing before wake_up() in ll_statahead_interpret(), > which may cause 'ls' hang. Under the right conditions a basic 'ls' > can fail. The debug logs show: > > statahead.c:683:ll_statahead_interpret()) sa_entry software rc -13 > statahead.c:1666:ll_statahead()) revalidate statahead software: -11. > > Obviously statahead failure didn't notify 'ls' process in time. > The mi_cbdata can be stale so add a barrier before calling > wake_up(). > > Signed-off-by: Lai Siyao > Signed-off-by: Bob Glossman > WC-bug-id: https://jira.whamcloud.com/browse/LU-9210 > Reviewed-on: https://review.whamcloud.com/27330 > Reviewed-by: Nathaniel Clark > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/llite/statahead.c | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c > index 1ad308c..0174a4c 100644 > --- a/drivers/staging/lustre/lustre/llite/statahead.c > +++ b/drivers/staging/lustre/lustre/llite/statahead.c > @@ -680,8 +680,14 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, > > spin_lock(&lli->lli_sa_lock); > if (rc) { > - if (__sa_make_ready(sai, entry, rc)) > + if (__sa_make_ready(sai, entry, rc)) { > + /* LU-9210 : Under the right conditions even 'ls' > + * can cause the statahead to fail. Using a memory > + * barrier resolves this issue. > + */ > + smp_mb(); > wake_up(&sai->sai_waitq); > + } > } else { > int first = 0; > entry->se_minfo = minfo; > -- > 1.8.3.1 Again, this is a fairly lame comment to justify the smp_mb(). It appears to me that the issue is most likely the value of entry->se_state. __sa_make_ready() sets this and revalidate_statahead_dentry tests it after waiting on sai_waitq. So I think it would be best if we changed __sa_make_ready() to smp_store_release(&entry->se_state, ret < 0 ? SA_ENTRY_INVA : SA_ENTRY_SUCC) and in ll_statahead_interpret() have if (smp_load_acquire(&entry->se_state) == SA_ENTRY_SUCC && entry->se_inode) { This would make it obvious which variable was important, and would show the paired synchronization points. NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 02:12:39 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 13:12:39 +1100 Subject: [lustre-devel] [PATCH 20/28] lustre: obdclass: deprecate OBD_GET_VERSION ioctl In-Reply-To: <1539543498-29105-21-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-21-git-send-email-jsimmons@infradead.org> Message-ID: <87a7ncc8a0.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > > + if (!warned) { > + warned = true; > + CWARN("%s: ioctl(OBD_GET_VERSION) is deprecated, use llapi_get_version_string() and/or relink\n", > + current->comm); > + } Is there a good reason not to use WARN_ON_ONCE() here? Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 02:15:23 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 13:15:23 +1100 Subject: [lustre-devel] [PATCH 21/28] lustre: llite: enhance vvp_dev data structure naming In-Reply-To: <1539543498-29105-22-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-22-git-send-email-jsimmons@infradead.org> Message-ID: <877eigc85g.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > The new code that added struct seq_private to the vvp_dev.c code > has very generic naming which doesn't fit the lustre / kernel style. > See http://wiki.lustre.org/Lustre_Coding_Style_Guidelines for the > naming conventions. Rename the struct seq_private and it fields. The guidelines say: unique member names for global structures, using a prefix to identify the parent structure type, helps readability. As this structure is local to vvp_dev.c, I don't think of it as a "global structure" and so I don't think the rule applies. But I don't really care. NeilBrown > > Signed-off-by: James Simmons > WC-bug-id: https://jira.whamcloud.com/browse/LU-8066 > Reviewed-on: https://review.whamcloud.com/33009 > Reviewed-by: Andreas Dilger > Reviewed-by: John L. Hammond > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/llite/vvp_dev.c | 54 ++++++++++++++------------- > 1 file changed, 28 insertions(+), 26 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c > index 31dc3c0..8cc981b 100644 > --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c > +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c > @@ -391,11 +391,11 @@ struct vvp_pgcache_id { > struct lu_object_header *vpi_obj; > }; > > -struct seq_private { > - struct ll_sb_info *sbi; > - struct lu_env *env; > - u16 refcheck; > - struct cl_object *clob; > +struct vvp_seq_private { > + struct ll_sb_info *vsp_sbi; > + struct lu_env *vsp_env; > + u16 vsp_refcheck; > + struct cl_object *vsp_clob; > }; > > static void vvp_pgcache_id_unpack(loff_t pos, struct vvp_pgcache_id *id) > @@ -542,52 +542,54 @@ static void vvp_pgcache_page_show(const struct lu_env *env, > > static int vvp_pgcache_show(struct seq_file *f, void *v) > { > - struct seq_private *priv = f->private; > + struct vvp_seq_private *priv = f->private; > struct page *vmpage = v; > struct cl_page *page; > > seq_printf(f, "%8lx@" DFID ": ", vmpage->index, > - PFID(lu_object_fid(&priv->clob->co_lu))); > + PFID(lu_object_fid(&priv->vsp_clob->co_lu))); > lock_page(vmpage); > - page = cl_vmpage_page(vmpage, priv->clob); > + page = cl_vmpage_page(vmpage, priv->vsp_clob); > unlock_page(vmpage); > put_page(vmpage); > > if (page) { > - vvp_pgcache_page_show(priv->env, f, page); > - cl_page_put(priv->env, page); > + vvp_pgcache_page_show(priv->vsp_env, f, page); > + cl_page_put(priv->vsp_env, page); > } else { > seq_puts(f, "missing\n"); > } > - lu_object_ref_del(&priv->clob->co_lu, "dump", current); > - cl_object_put(priv->env, priv->clob); > + lu_object_ref_del(&priv->vsp_clob->co_lu, "dump", current); > + cl_object_put(priv->vsp_env, priv->vsp_clob); > > return 0; > } > > static void *vvp_pgcache_start(struct seq_file *f, loff_t *pos) > { > - struct seq_private *priv = f->private; > + struct vvp_seq_private *priv = f->private; > struct page *ret; > > - if (priv->sbi->ll_site->ls_obj_hash->hs_cur_bits > > + if (priv->vsp_sbi->ll_site->ls_obj_hash->hs_cur_bits > > 64 - PGC_OBJ_SHIFT) > ret = ERR_PTR(-EFBIG); > else > - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, > - &priv->clob, pos); > + ret = vvp_pgcache_find(priv->vsp_env, > + &priv->vsp_sbi->ll_cl->cd_lu_dev, > + &priv->vsp_clob, pos); > > return ret; > } > > static void *vvp_pgcache_next(struct seq_file *f, void *v, loff_t *pos) > { > - struct seq_private *priv = f->private; > + struct vvp_seq_private *priv = f->private; > struct page *ret; > > *pos += 1; > - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, > - &priv->clob, pos); > + ret = vvp_pgcache_find(priv->vsp_env, > + &priv->vsp_sbi->ll_cl->cd_lu_dev, > + &priv->vsp_clob, pos); > return ret; > } > > @@ -605,16 +607,16 @@ static void vvp_pgcache_stop(struct seq_file *f, void *v) > > static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) > { > - struct seq_private *priv; > + struct vvp_seq_private *priv; > > priv = __seq_open_private(filp, &vvp_pgcache_ops, sizeof(*priv)); > if (!priv) > return -ENOMEM; > > - priv->sbi = inode->i_private; > - priv->env = cl_env_get(&priv->refcheck); > - if (IS_ERR(priv->env)) { > - int err = PTR_ERR(priv->env); > + priv->vsp_sbi = inode->i_private; > + priv->vsp_env = cl_env_get(&priv->vsp_refcheck); > + if (IS_ERR(priv->vsp_env)) { > + int err = PTR_ERR(priv->vsp_env); > > seq_release_private(inode, filp); > return err; > @@ -625,9 +627,9 @@ static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) > static int vvp_dump_pgcache_seq_release(struct inode *inode, struct file *file) > { > struct seq_file *seq = file->private_data; > - struct seq_private *priv = seq->private; > + struct vvp_seq_private *priv = seq->private; > > - cl_env_put(priv->env, &priv->refcheck); > + cl_env_put(priv->vsp_env, &priv->vsp_refcheck); > return seq_release_private(inode, file); > } > > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 04:40:26 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 15:40:26 +1100 Subject: [lustre-devel] [PATCH] lustre: lprocfs: fix return value of lprocfs_read_helper Message-ID: <87y3avc1fp.fsf@notabene.neil.brown.name> This should be 'ret', not zero. Fixes: fdedd94509fd ("staging/lustre/lvfs: remove the lvfs layer") Signed-off-by: NeilBrown --- drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index dc1d540e05c7..edac88440b41 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -1509,7 +1509,7 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc, break; } - return 0; + return ret; } EXPORT_SYMBOL(lprocfs_read_helper); -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Thu Oct 18 04:48:28 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 18 Oct 2018 15:48:28 +1100 Subject: [lustre-devel] [PATCH 00/10] lustre: lnet: fixes for non-x86 systems In-Reply-To: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> Message-ID: <87va5zc12b.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > These are the required patches to make LNet work with non-x86 > platforms like ARM or Power8. The tunables map_on_demand and > concurrent_sends assumed pages were 4K in size which is not > correct. Massively reworked to basically defunct those tunables. > Also the size of the LNet packet was always 256 pages but when > the page size is 64K like some ARM or Power8 systems the maximum > LNet message sent was 16MB not 1MB which is what is expected. > Fixing up the RDMA handling in the ko2iblnd driver also resolved > some performance issues. Thanks. I've applied this series, but I've still suspicious of that little section in patch 3. I hope that can be clarified, or fixed, before I feel the need to move the series from 'lustre-testing' to 'lustre'. Thanks, NeilBrown > > Alexey Lyashkov (1): > lustre: lnd: use less CQ entries for each connection > > Amir Shehata (6): > lustre: lnd: set device capabilities > lustre: o2iblnd: use IB_MR_TYPE_SG_GAPS > lustre: lnd: rework map_on_demand behavior > lustre: lnd: calculate qp max_send_wrs properly > lustre: lnd: remove concurrent_sends tunable > lustre: lnd: correct WR fast reg accounting > > Dmitry Eremin (1): > lustre: o2iblnd: limit cap.max_send_wr for MLX5 > > James Simmons (1): > lustre: lnet: make LNET_MAX_IOV dependent on page size > > John L. Hammond (1): > lustre: o2ib: use splice in kiblnd_peer_connect_failed() > > .../staging/lustre/include/linux/lnet/lib-types.h | 10 +- > .../lustre/include/uapi/linux/lnet/lnet-types.h | 3 - > drivers/staging/lustre/lnet/Kconfig | 10 -- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 138 +++++++++++++++------ > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 68 +++------- > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 133 ++++++++++++++------ > .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 85 ++++++------- > drivers/staging/lustre/lustre/include/lustre_net.h | 1 + > 8 files changed, 256 insertions(+), 192 deletions(-) > > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From jsimmons at infradead.org Sat Oct 20 16:47:44 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 17:47:44 +0100 (BST) Subject: [lustre-devel] [PATCH 14/24] lustre: lnet: reference counts on lnet_peer/lnet_peer_net In-Reply-To: <87o9btduf0.fsf@notabene.neil.brown.name> References: <153895417139.16383.3791701638653772865.stgit@noble> <153895437808.16383.1725584261522697360.stgit@noble> <87o9btduf0.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > >> From: Olaf Weber > >> > >> Peer discovery will be keeping track of lnet_peer structures, > >> so there will be references to an lnet_peer independent of > >> the references implied by lnet_peer_ni structures. Manage > >> this by adding explicit reference counts to lnet_peer_net and > >> lnet_peer. > >> > >> Each lnet_peer_net has a hold on the lnet_peer it links to > >> with its lpn_peer pointer. This hold is only removed when that > >> pointer is assigned a new value or the lnet_peer_net is freed. > >> Just removing an lnet_peer_net from the lp_peer_nets list does > >> not release this hold, it just prevents new lookups of the > >> lnet_peer_net via the lnet_peer. > >> > >> Each lnet_peer_ni has a hold on the lnet_peer_net it links to > >> with its lpni_peer_net pointer. This hold is only removed when > >> that pointer is assigned a new value or the lnet_peer_ni is > >> freed. Just removing an lnet_peer_ni from the lpn_peer_nis > >> list does not release this hold, it just prevents new lookups > >> of the lnet_peer_ni via the lnet_peer_net. > >> > >> This ensures that given a lnet_peer_ni *lpni, we can rely on > >> lpni->lpni_peer_net->lpn_peer pointing to a valid lnet_peer. > >> > >> Keep a count of the total number of lnet_peer_ni attached to > >> an lnet_peer in lp_nnis. > >> > >> Split the global ln_peers list into per-lnet_peer_table lists. > >> The CPT of the peer table in which the lnet_peer is linked is > >> stored in lp_cpt. > >> > >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9480 > >> Signed-off-by: Olaf Weber > >> Reviewed-on: https://review.whamcloud.com/25784 > >> Reviewed-by: Olaf Weber > >> Reviewed-by: Amir Shehata > >> Tested-by: Amir Shehata > >> Signed-off-by: NeilBrown > >> --- > >> .../staging/lustre/include/linux/lnet/lib-lnet.h | 49 +++-- > >> .../staging/lustre/include/linux/lnet/lib-types.h | 50 ++++- > >> drivers/staging/lustre/lnet/lnet/api-ni.c | 1 > >> drivers/staging/lustre/lnet/lnet/lib-move.c | 8 - > >> drivers/staging/lustre/lnet/lnet/peer.c | 210 ++++++++++++++------ > >> 5 files changed, 227 insertions(+), 91 deletions(-) > >> > >> diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > >> index 563417510722..aad25eb0011b 100644 > >> --- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > >> +++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h > >> @@ -310,6 +310,36 @@ lnet_handle2me(struct lnet_handle_me *handle) ..... > >> +++ b/drivers/staging/lustre/lnet/lnet/peer.c > > > > INIT_LIST_HEAD(&ptable->pt_peer_list); seems to be missing from > > lnet_peer_tables_create(). This is in the patch merged into > > lustre-testing. Other than that it looks okay. > > No, it is there. It is just the the lnet_peer_tables_create() has moved, > so it isn't in the same place in the patch. > > ..snip.. > > >> @@ -319,6 +358,8 @@ lnet_peer_tables_create(void) > >> spin_lock_init(&ptable->pt_zombie_lock); > >> INIT_LIST_HEAD(&ptable->pt_zombie_list); > >> > >> + INIT_LIST_HEAD(&ptable->pt_peer_list); > >> + > >> for (j = 0; j < LNET_PEER_HASH_SIZE; j++) > >> INIT_LIST_HEAD(&hash[j]); > >> ptable->pt_hash = hash; /* sign of initialization */ > > here it is. Missed it. Thanks. Reviewed-by: James Simmons From jsimmons at infradead.org Sat Oct 20 16:58:45 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 17:58:45 +0100 (BST) Subject: [lustre-devel] [PATCH 01/10] lustre: lnd: set device capabilities In-Reply-To: <87efcpdsnz.fsf@notabene.neil.brown.name> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-2-git-send-email-jsimmons@infradead.org> <87efcpdsnz.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Amir Shehata > > > > MLX-4, MLX-5 and OPA support different capabilities. Query the > > device and cache the capabilities of the device for future use. > > > > At the time of the patches creation MLX5 could support fast > > registration and gaps while MLX4 and OPA only support FMR > > > > Signed-off-by: Amir Shehata > > WC-bug-id: https://jira.whamcloud.com/browse/LU-10129 > > Reviewed-on: https://review.whamcloud.com/30309 > > Reviewed-by: Alexey Lyashkov > > Reviewed-by: Dmitry Eremin > > Reviewed-by: James Simmons > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 41 ++++++++++++---------- > > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 5 +++ > > 2 files changed, 28 insertions(+), 18 deletions(-) > > > > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > > index bf969b3..b10658b 100644 > > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c > > @@ -1399,6 +1399,7 @@ static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_poo > > else > > CERROR("FMRs are not supported\n"); > > } > > + fpo->fpo_is_fmr = true; > > > > return rc; > > } > > @@ -1408,6 +1409,8 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po > > struct kib_fast_reg_descriptor *frd; > > int i, rc; > > > > + fpo->fpo_is_fmr = false; > > + > > INIT_LIST_HEAD(&fpo->fast_reg.fpo_pool_list); > > fpo->fast_reg.fpo_pool_size = 0; > > for (i = 0; i < fps->fps_pool_size; i++) { > > @@ -1469,23 +1472,7 @@ static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, > > fpo->fpo_hdev = kiblnd_current_hdev(dev); > > dev_attr = &fpo->fpo_hdev->ibh_ibdev->attrs; > > > > - /* Check for FMR or FastReg support */ > > - fpo->fpo_is_fmr = 0; > > - if (fpo->fpo_hdev->ibh_ibdev->alloc_fmr && > > - fpo->fpo_hdev->ibh_ibdev->dealloc_fmr && > > - fpo->fpo_hdev->ibh_ibdev->map_phys_fmr && > > - fpo->fpo_hdev->ibh_ibdev->unmap_fmr) { > > - LCONSOLE_INFO("Using FMR for registration\n"); > > - fpo->fpo_is_fmr = 1; > > - } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { > > - LCONSOLE_INFO("Using FastReg for registration\n"); > > - } else { > > - rc = -ENOSYS; > > - LCONSOLE_ERROR_MSG(rc, "IB device does not support FMRs nor FastRegs, can't register memory\n"); > > - goto out_fpo; > > - } > > - > > - if (fpo->fpo_is_fmr) > > + if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) > > rc = kiblnd_alloc_fmr_pool(fps, fpo); > > else > > rc = kiblnd_alloc_freg_pool(fps, fpo); > > @@ -2261,6 +2248,9 @@ static int kiblnd_net_init_pools(struct kib_net *net, struct lnet_ni *ni, > > > > static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) > > { > > + struct ib_device_attr *dev_attr = &hdev->ibh_ibdev->attrs; > > + int rc = 0; > > + > > /* > > * It's safe to assume a HCA can handle a page size > > * matching that of the native system > > @@ -2269,7 +2259,22 @@ static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) > > hdev->ibh_page_size = 1 << PAGE_SHIFT; > > hdev->ibh_page_mask = ~((__u64)hdev->ibh_page_size - 1); > > > > - hdev->ibh_mr_size = hdev->ibh_ibdev->attrs.max_mr_size; > > + if (hdev->ibh_ibdev->alloc_fmr && > > + hdev->ibh_ibdev->dealloc_fmr && > > + hdev->ibh_ibdev->map_phys_fmr && > > + hdev->ibh_ibdev->unmap_fmr) { > > + LCONSOLE_INFO("Using FMR for registration\n"); > > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FMR_ENABLED; > > + } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { > > + LCONSOLE_INFO("Using FastReg for registration\n"); > > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_ENABLED; > > + } else { > > + CERROR("IB device does not support FMRs nor FastRegs, can't register memory: %d\n", > > + rc); > > + return -ENXIO; > > + } > > + > > + hdev->ibh_mr_size = dev_attr->max_mr_size; > > if (hdev->ibh_mr_size == ~0ULL) { > > hdev->ibh_mr_shift = 64; > > return 0; > > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > > index a4438d2..9f0a47d 100644 > > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > > @@ -73,6 +73,10 @@ > > #define IBLND_N_SCHED 2 > > #define IBLND_N_SCHED_HIGH 4 > > > > +#define IBLND_DEV_CAPS_FASTREG_ENABLED 0x1 > > +#define IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT 0x2 > > +#define IBLND_DEV_CAPS_FMR_ENABLED 0x4 > > + > > BIT(0), BIT(1), .... ??? > > > struct kib_tunables { > > int *kib_dev_failover; /* HCA failover */ > > unsigned int *kib_service; /* IB service number */ > > @@ -162,6 +166,7 @@ struct kib_dev { > > unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ > > struct list_head ibd_nets; > > struct kib_hca_dev *ibd_hdev; > > + u32 ibd_dev_caps; > > "unsigned int" would be better I think, but it isn't very important. Actually better yet it could be changed to an enum. Move the below to just above struct kib_dev { enum ibd_dev_caps { IBLND_DEV_CAPS_FASTREG_ENABLED = BIT(0), IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT = BIT(1), IBLND_DEV_CAPS_FMR_ENABLED = BIT(2), } and change ibd_dev_caps from u32 to enum ibd_dev_caps. Do you mind if that is a follow on patch? > Thanks, > NeilBrown > > > > }; > > > > struct kib_hca_dev { > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sat Oct 20 17:06:13 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 18:06:13 +0100 (BST) Subject: [lustre-devel] [PATCH 03/10] lustre: lnd: rework map_on_demand behavior In-Reply-To: <87bm7tdrvu.fsf@notabene.neil.brown.name> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-4-git-send-email-jsimmons@infradead.org> <87bm7tdrvu.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > @@ -1320,9 +1324,8 @@ static void kiblnd_destroy_fmr_pool(struct kib_fmr_pool *fpo) > > { > > LASSERT(!fpo->fpo_map_count); > > > > - if (fpo->fpo_is_fmr) { > > - if (fpo->fmr.fpo_fmr_pool) > > - ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); > > + if (fpo->fpo_is_fmr && fpo->fmr.fpo_fmr_pool) { > > + ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); > > } else { > > struct kib_fast_reg_descriptor *frd; > > int i = 0; > > This change looks strange. > With the new code: if fpo_fmr_pool is NULL, then the fpo_pool_list is > destroyed, even though fpo_is_fmr. > > Are we sure that is correct?? > I don't really understand this code so it might be correct, but the > change looks wrong. > > Can someone please confirm that it really is right - and maybe explain > why? It is wrong!!! The only reason it didn't show up is that fp_fmr_pool is very unlikely to NULL. I understand why this bug was introduced since its desirable to reduce the indentation. This is the fault of how the code is written. To avoid this in the future it should be written: if (!fpo->fpo_is_fmr) { struct kib_fast_reg_descriptor *frd, *tmp; .... } else if (fpo->fmr.fpo_fmr_pool) { ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); } I opened a ticket for https://jira.whamcloud.com/browse/LU-11552 and submitted a patch - https://review.whamcloud.com/#/c/33408. To address this. So please remove this part from the change. We could redo the patch to include the above or I could just send a follow up patch to make this code clearer. I leave that up to you. From jsimmons at infradead.org Sat Oct 20 17:09:33 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 18:09:33 +0100 (BST) Subject: [lustre-devel] [PATCH 06/28] lustre: ldlm: ELC shouldn't wait on lock flush In-Reply-To: <87sh14cg8q.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-7-git-send-email-jsimmons@infradead.org> <87sh14cg8q.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Andriy Skulysh > > > > The commit 08fd034670b5 ("staging: lustre: ldlm: revert the changes > > for lock canceling policy") removed the fix for LU-4300 when lru_resize > > is disabled. > > > > Introduce ldlm_cancel_aged_no_wait_policy to be used by ELC. > > > > Signed-off-by: Andriy Skulysh > > WC-bug-id: https://jira.whamcloud.com/browse/LU-8578 > > Seagate-bug-id: MRP-3662 > > Reviewed-on: https://review.whamcloud.com/22286 > > Reviewed-by: Vitaly Fertman > > Reviewed-by: Patrick Farrell > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 1 - > > drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 51 +++++++++++++++------- > > 2 files changed, 35 insertions(+), 17 deletions(-) > > > > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > > index 1d7c727..709c527 100644 > > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h > > @@ -96,7 +96,6 @@ enum { > > LDLM_LRU_FLAG_NO_WAIT = BIT(4), /* Cancel locks w/o blocking (neither > > * sending nor waiting for any rpcs) > > */ > > - LDLM_LRU_FLAG_LRUR_NO_WAIT = BIT(5), /* LRUR + NO_WAIT */ > > }; > > > > int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr, > > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > > index 80260b07..3eb5036 100644 > > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c > > @@ -579,8 +579,8 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req, > > req_capsule_filled_sizes(pill, RCL_CLIENT); > > avail = ldlm_capsule_handles_avail(pill, RCL_CLIENT, canceloff); > > > > - flags = ns_connect_lru_resize(ns) ? > > - LDLM_LRU_FLAG_LRUR_NO_WAIT : LDLM_LRU_FLAG_AGED; > > + flags = LDLM_LRU_FLAG_NO_WAIT | ns_connect_lru_resize(ns) ? > > + LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED; > > to_free = !ns_connect_lru_resize(ns) && > > opc == LDLM_ENQUEUE ? 1 : 0; > > Bug. > The commit in SFS-lustre (7ca60f33893) is correct, but you dropped the > parentheses which introduces a bug. > > While the SFS code is correct, it is formatted badly. > It should be > > lru_flags = LDLM_LRU_FLAG_NO_WAIT | > (ns_connect_lru_resize(ns) ? > LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED); > or similar. Thanks for finding that. Shall I submit another patch to fix that or will you fix it up when you apply it to lustre-testing? From jsimmons at infradead.org Sat Oct 20 17:49:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 18:49:51 +0100 (BST) Subject: [lustre-devel] [PATCH 11/28] lustre: llite: use security context if it's enabled in the kernel In-Reply-To: <87pnw8cflq.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-12-git-send-email-jsimmons@infradead.org> <87pnw8cflq.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Alex Zhuravlev > > > > if it's disabled, then Lustre stop to work properly (can not create > > files, etc) > > > > Signed-off-by: Alex Zhuravlev > > WC-bug-id: https://jira.whamcloud.com/browse/LU-9578 > > Reviewed-on: https://review.whamcloud.com/27364 > > Reviewed-by: Andreas Dilger > > Reviewed-by: Chris Horn > > Reviewed-by: James Simmons > > Reviewed-by: Sebastien Buisson > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/llite/llite_lib.c | 3 ++- > > 1 file changed, 2 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c > > index 22b545e..153aa12 100644 > > --- a/drivers/staging/lustre/lustre/llite/llite_lib.c > > +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c > > @@ -243,8 +243,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) > > if (sbi->ll_flags & LL_SBI_ALWAYS_PING) > > data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; > > > > +#ifdef CONFIG_SECURITY > > data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; > > - > > +#endif > > Policy is to avoid #ifdef in .c files where possible. > If we put something like > #ifdef CONFIG_SECURITY > #define OBD_CONNECT2_FILE_SECURITY (OBD_CONNECT2_FILE_SECCTX) > #else > #define OBD_CONNECT2_FILE_SECURITY (0) > #endif > > in a .h file, then use OBD_CONNECT2_FILE_SECURITY both here and in > obd_connect_has_secctx(), > then the latter could would be optimized away by the compiler. Wouldn't > be a big win I guess as it is only used once in a trivial context. I suggest that we move obd_connect_has_secctx() to llite_internal.h. Also that function should return bool. Besides this create an inline function obd_connect_set_secctx() for llite_internal.h. Will submit a patch for OpenSFS branch. Shall I redo this patch or submit a cleanup later? > NeilBrown > > > > data->ocd_brw_size = MD_MAX_BRW_SIZE; > > > > err = obd_connect(NULL, &sbi->ll_md_exp, sbi->ll_md_obd, > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sat Oct 20 18:52:16 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 19:52:16 +0100 (BST) Subject: [lustre-devel] [PATCH 20/28] lustre: obdclass: deprecate OBD_GET_VERSION ioctl In-Reply-To: <87a7ncc8a0.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-21-git-send-email-jsimmons@infradead.org> <87a7ncc8a0.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > > + if (!warned) { > > + warned = true; > > + CWARN("%s: ioctl(OBD_GET_VERSION) is deprecated, use llapi_get_version_string() and/or relink\n", > > + current->comm); > > + } > > Is there a good reason not to use WARN_ON_ONCE() here? Oh that is much nicer. Didn't know about it. Shall I submit a new patch or will it be changed when applied to lustre-testing? From jsimmons at infradead.org Sat Oct 20 18:55:41 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 19:55:41 +0100 (BST) Subject: [lustre-devel] [PATCH 21/28] lustre: llite: enhance vvp_dev data structure naming In-Reply-To: <877eigc85g.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-22-git-send-email-jsimmons@infradead.org> <877eigc85g.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > The new code that added struct seq_private to the vvp_dev.c code > > has very generic naming which doesn't fit the lustre / kernel style. > > See http://wiki.lustre.org/Lustre_Coding_Style_Guidelines for the > > naming conventions. Rename the struct seq_private and it fields. > > The guidelines say: > > unique member names for global structures, using a prefix to identify > the parent structure type, helps readability. > > As this structure is local to vvp_dev.c, I don't think of it as a > "global structure" and so I don't think the rule applies. > > But I don't really care. The gudeline needs to be updated to state "member names for all structures". Some lustre developers handle style issues as strictly as Greg did in staging. It's just a different flavor :-) To let you know your dump cache tree walk patch in lustre-wip landed to OpenSFS tree. I plan to push another set of patches and I can included it with the reviews. > > Signed-off-by: James Simmons > > WC-bug-id: https://jira.whamcloud.com/browse/LU-8066 > > Reviewed-on: https://review.whamcloud.com/33009 > > Reviewed-by: Andreas Dilger > > Reviewed-by: John L. Hammond > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/llite/vvp_dev.c | 54 ++++++++++++++------------- > > 1 file changed, 28 insertions(+), 26 deletions(-) > > > > diff --git a/drivers/staging/lustre/lustre/llite/vvp_dev.c b/drivers/staging/lustre/lustre/llite/vvp_dev.c > > index 31dc3c0..8cc981b 100644 > > --- a/drivers/staging/lustre/lustre/llite/vvp_dev.c > > +++ b/drivers/staging/lustre/lustre/llite/vvp_dev.c > > @@ -391,11 +391,11 @@ struct vvp_pgcache_id { > > struct lu_object_header *vpi_obj; > > }; > > > > -struct seq_private { > > - struct ll_sb_info *sbi; > > - struct lu_env *env; > > - u16 refcheck; > > - struct cl_object *clob; > > +struct vvp_seq_private { > > + struct ll_sb_info *vsp_sbi; > > + struct lu_env *vsp_env; > > + u16 vsp_refcheck; > > + struct cl_object *vsp_clob; > > }; > > > > static void vvp_pgcache_id_unpack(loff_t pos, struct vvp_pgcache_id *id) > > @@ -542,52 +542,54 @@ static void vvp_pgcache_page_show(const struct lu_env *env, > > > > static int vvp_pgcache_show(struct seq_file *f, void *v) > > { > > - struct seq_private *priv = f->private; > > + struct vvp_seq_private *priv = f->private; > > struct page *vmpage = v; > > struct cl_page *page; > > > > seq_printf(f, "%8lx@" DFID ": ", vmpage->index, > > - PFID(lu_object_fid(&priv->clob->co_lu))); > > + PFID(lu_object_fid(&priv->vsp_clob->co_lu))); > > lock_page(vmpage); > > - page = cl_vmpage_page(vmpage, priv->clob); > > + page = cl_vmpage_page(vmpage, priv->vsp_clob); > > unlock_page(vmpage); > > put_page(vmpage); > > > > if (page) { > > - vvp_pgcache_page_show(priv->env, f, page); > > - cl_page_put(priv->env, page); > > + vvp_pgcache_page_show(priv->vsp_env, f, page); > > + cl_page_put(priv->vsp_env, page); > > } else { > > seq_puts(f, "missing\n"); > > } > > - lu_object_ref_del(&priv->clob->co_lu, "dump", current); > > - cl_object_put(priv->env, priv->clob); > > + lu_object_ref_del(&priv->vsp_clob->co_lu, "dump", current); > > + cl_object_put(priv->vsp_env, priv->vsp_clob); > > > > return 0; > > } > > > > static void *vvp_pgcache_start(struct seq_file *f, loff_t *pos) > > { > > - struct seq_private *priv = f->private; > > + struct vvp_seq_private *priv = f->private; > > struct page *ret; > > > > - if (priv->sbi->ll_site->ls_obj_hash->hs_cur_bits > > > + if (priv->vsp_sbi->ll_site->ls_obj_hash->hs_cur_bits > > > 64 - PGC_OBJ_SHIFT) > > ret = ERR_PTR(-EFBIG); > > else > > - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, > > - &priv->clob, pos); > > + ret = vvp_pgcache_find(priv->vsp_env, > > + &priv->vsp_sbi->ll_cl->cd_lu_dev, > > + &priv->vsp_clob, pos); > > > > return ret; > > } > > > > static void *vvp_pgcache_next(struct seq_file *f, void *v, loff_t *pos) > > { > > - struct seq_private *priv = f->private; > > + struct vvp_seq_private *priv = f->private; > > struct page *ret; > > > > *pos += 1; > > - ret = vvp_pgcache_find(priv->env, &priv->sbi->ll_cl->cd_lu_dev, > > - &priv->clob, pos); > > + ret = vvp_pgcache_find(priv->vsp_env, > > + &priv->vsp_sbi->ll_cl->cd_lu_dev, > > + &priv->vsp_clob, pos); > > return ret; > > } > > > > @@ -605,16 +607,16 @@ static void vvp_pgcache_stop(struct seq_file *f, void *v) > > > > static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) > > { > > - struct seq_private *priv; > > + struct vvp_seq_private *priv; > > > > priv = __seq_open_private(filp, &vvp_pgcache_ops, sizeof(*priv)); > > if (!priv) > > return -ENOMEM; > > > > - priv->sbi = inode->i_private; > > - priv->env = cl_env_get(&priv->refcheck); > > - if (IS_ERR(priv->env)) { > > - int err = PTR_ERR(priv->env); > > + priv->vsp_sbi = inode->i_private; > > + priv->vsp_env = cl_env_get(&priv->vsp_refcheck); > > + if (IS_ERR(priv->vsp_env)) { > > + int err = PTR_ERR(priv->vsp_env); > > > > seq_release_private(inode, filp); > > return err; > > @@ -625,9 +627,9 @@ static int vvp_dump_pgcache_seq_open(struct inode *inode, struct file *filp) > > static int vvp_dump_pgcache_seq_release(struct inode *inode, struct file *file) > > { > > struct seq_file *seq = file->private_data; > > - struct seq_private *priv = seq->private; > > + struct vvp_seq_private *priv = seq->private; > > > > - cl_env_put(priv->env, &priv->refcheck); > > + cl_env_put(priv->vsp_env, &priv->vsp_refcheck); > > return seq_release_private(inode, file); > > } > > > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sat Oct 20 19:00:52 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 20:00:52 +0100 (BST) Subject: [lustre-devel] [PATCH 00/10] lustre: lnet: fixes for non-x86 systems In-Reply-To: <87va5zc12b.fsf@notabene.neil.brown.name> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <87va5zc12b.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > These are the required patches to make LNet work with non-x86 > > platforms like ARM or Power8. The tunables map_on_demand and > > concurrent_sends assumed pages were 4K in size which is not > > correct. Massively reworked to basically defunct those tunables. > > Also the size of the LNet packet was always 256 pages but when > > the page size is 64K like some ARM or Power8 systems the maximum > > LNet message sent was 16MB not 1MB which is what is expected. > > Fixing up the RDMA handling in the ko2iblnd driver also resolved > > some performance issues. > > Thanks. > I've applied this series, but I've still suspicious of that little > section in patch 3. > I hope that can be clarified, or fixed, before I feel the need to move > the series from 'lustre-testing' to 'lustre'. Thank you. Yes as I pointed out that code in patch 3 is wrong. I pushed a fix to the OpenSFS branch already. You can drop that change in patch 3. > > Alexey Lyashkov (1): > > lustre: lnd: use less CQ entries for each connection > > > > Amir Shehata (6): > > lustre: lnd: set device capabilities > > lustre: o2iblnd: use IB_MR_TYPE_SG_GAPS > > lustre: lnd: rework map_on_demand behavior > > lustre: lnd: calculate qp max_send_wrs properly > > lustre: lnd: remove concurrent_sends tunable > > lustre: lnd: correct WR fast reg accounting > > > > Dmitry Eremin (1): > > lustre: o2iblnd: limit cap.max_send_wr for MLX5 > > > > James Simmons (1): > > lustre: lnet: make LNET_MAX_IOV dependent on page size > > > > John L. Hammond (1): > > lustre: o2ib: use splice in kiblnd_peer_connect_failed() > > > > .../staging/lustre/include/linux/lnet/lib-types.h | 10 +- > > .../lustre/include/uapi/linux/lnet/lnet-types.h | 3 - > > drivers/staging/lustre/lnet/Kconfig | 10 -- > > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 138 +++++++++++++++------ > > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 68 +++------- > > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 133 ++++++++++++++------ > > .../lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c | 85 ++++++------- > > drivers/staging/lustre/lustre/include/lustre_net.h | 1 + > > 8 files changed, 256 insertions(+), 192 deletions(-) > > > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sat Oct 20 19:06:24 2018 From: jsimmons at infradead.org (James Simmons) Date: Sat, 20 Oct 2018 20:06:24 +0100 (BST) Subject: [lustre-devel] [PATCH] lustre: lprocfs: fix return value of lprocfs_read_helper In-Reply-To: <87y3avc1fp.fsf@notabene.neil.brown.name> References: <87y3avc1fp.fsf@notabene.neil.brown.name> Message-ID: > This should be 'ret', not zero. I bet that was one of my first patches to the linux lustre client since its a really old patch. Thanks for figuring that out. Reviewed-by: James Simmons > Fixes: fdedd94509fd ("staging/lustre/lvfs: remove the lvfs layer") > Signed-off-by: NeilBrown > --- > drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > index dc1d540e05c7..edac88440b41 100644 > --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > @@ -1509,7 +1509,7 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc, > break; > } > > - return 0; > + return ret; > } > EXPORT_SYMBOL(lprocfs_read_helper); > > -- > 2.14.0.rc0.dirty > > From jsimmons at infradead.org Sun Oct 21 22:44:49 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 21 Oct 2018 23:44:49 +0100 (BST) Subject: [lustre-devel] [PATCH 04/28] lustre: ptlrpc: Do not assert when bd_nob_transferred != 0 In-Reply-To: <87va60cgjx.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-5-git-send-email-jsimmons@infradead.org> <87va60cgjx.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Doug Oucharek > > > > There is a case in the routine ptlrpc_register_bulk() where we were > > asserting if bd_nob_transferred != 0 when not resending. There is > > evidence that network errors can create a situation where > > this does happen. So we should not be asserting! > > > > This patch changes that assert to an error return code of -EIO. > > > > Signed-off-by: Doug Oucharek > > WC-bug-id: https://jira.whamcloud.com/browse/LU-9828 > > Reviewed-on: https://review.whamcloud.com/28491 > > Reviewed-by: Dmitry Eremin > > Reviewed-by: Sonia Sharma > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 8 ++++++-- > > 1 file changed, 6 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > > index 27eb1c0..7e7db24 100644 > > --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > > +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c > > @@ -139,8 +139,12 @@ static int ptlrpc_register_bulk(struct ptlrpc_request *req) > > /* cleanup the state of the bulk for it will be reused */ > > if (req->rq_resend || req->rq_send_state == LUSTRE_IMP_REPLAY) > > desc->bd_nob_transferred = 0; > > - else > > - LASSERT(desc->bd_nob_transferred == 0); > > + else if (desc->bd_nob_transferred != 0) > > + /* If the network failed after an RPC was sent, this condition > > + * could happen. Rather than assert (was here before), return > > + * an EIO error. > > + */ > > + return -EIO; > > This looks weird, and the justification is rather lame. > I wonder if this is an attempt to fix the same problem that the smp_mb() > in the previous patch was attempting to fix (and I'm not yet convinced > that either is the correct fix). When the above condition happens the LASSERT ends up taking out the node with a panic which in turn kills the application running on the cluster. When replaced with reporting an EIO error the node survives as well as the job. The job might fail at its IO but it wouldn't fail performing its work flow which is way more important. > > desc->bd_failure = 0; > > > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sun Oct 21 22:48:16 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 21 Oct 2018 23:48:16 +0100 (BST) Subject: [lustre-devel] [PATCH 03/28] lustre: ptlrpc: missing barrier before wake_up In-Reply-To: <87y3awchze.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-4-git-send-email-jsimmons@infradead.org> <87y3awchze.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Lai Siyao > > > > ptlrpc_client_wake_req() misses a memory barrier, which may cause > > strange errors. > > > > Signed-off-by: Lai Siyao > > WC-bug-id: https://jira.whamcloud.com/browse/LU-8935 > > Reviewed-on: https://review.whamcloud.com/26583 > > Reviewed-by: Andreas Dilger > > Reviewed-by: Wang Shilong > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/include/lustre_net.h | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h > > index ce7e98c..468a03e 100644 > > --- a/drivers/staging/lustre/lustre/include/lustre_net.h > > +++ b/drivers/staging/lustre/lustre/include/lustre_net.h > > @@ -2211,6 +2211,8 @@ static inline int ptlrpc_status_ntoh(int n) > > static inline void > > ptlrpc_client_wake_req(struct ptlrpc_request *req) > > { > > + /* ensure ptlrpc_register_bulk see rq_resend as set. */ > > + smp_mb(); > > if (!req->rq_set) > > wake_up(&req->rq_reply_waitq); > > else > > It is good that this memory barrier has a comment, but the comment isn't > very helpful. > There is no matching memory barrier in ptlrpc_register_bulk(), so it > isn't clear what sequencing is important. > > And ptl_send_rpc() tests ->rq_resend *before* ptlrpc_register_bulk() is > called (which also tests it). Presumably these should see that same > value? So why does the comment refer to ptlrpc_register_bulk() instead > of ptl_send_rpc() ?? > > It all seems rather confusing, so it is very hard to be sure that the > code is now correct. > Is someone able to explain? I wasn't going on much here. While the linux kernel request comments to place with memory barriers lustre developers tend to never leave an explaination on why a memory barrier was needed. In this case I examined the original JIRA ticket to find in one of the comments: "It looks like ptlrpc_client_wake_req() misses a memory barrier, which may cause ptlrpc_resend_req() wake up ptlrpc_send_rpc -> ptlrpc_register_bulk, while the latter doesn't see rq_resend set." I attempted to add that as a comment. This is all I had to go one. Now Lai is CC to this email so maybe he remembers what it was all about. > Thanks, > NeilBrown > > > > > -- > > 1.8.3.1 > From jsimmons at infradead.org Sun Oct 21 22:52:37 2018 From: jsimmons at infradead.org (James Simmons) Date: Sun, 21 Oct 2018 23:52:37 +0100 (BST) Subject: [lustre-devel] [PATCH 16/28] lustre: statahead: missing barrier before wake_up In-Reply-To: <87d0s8c8tp.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-17-git-send-email-jsimmons@infradead.org> <87d0s8c8tp.fsf@notabene.neil.brown.name> Message-ID: > On Sun, Oct 14 2018, James Simmons wrote: > > > From: Lai Siyao > > > > A barrier is missing before wake_up() in ll_statahead_interpret(), > > which may cause 'ls' hang. Under the right conditions a basic 'ls' > > can fail. The debug logs show: > > > > statahead.c:683:ll_statahead_interpret()) sa_entry software rc -13 > > statahead.c:1666:ll_statahead()) revalidate statahead software: -11. > > > > Obviously statahead failure didn't notify 'ls' process in time. > > The mi_cbdata can be stale so add a barrier before calling > > wake_up(). > > > > Signed-off-by: Lai Siyao > > Signed-off-by: Bob Glossman > > WC-bug-id: https://jira.whamcloud.com/browse/LU-9210 > > Reviewed-on: https://review.whamcloud.com/27330 > > Reviewed-by: Nathaniel Clark > > Reviewed-by: Oleg Drokin > > Signed-off-by: James Simmons > > --- > > drivers/staging/lustre/lustre/llite/statahead.c | 8 +++++++- > > 1 file changed, 7 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c > > index 1ad308c..0174a4c 100644 > > --- a/drivers/staging/lustre/lustre/llite/statahead.c > > +++ b/drivers/staging/lustre/lustre/llite/statahead.c > > @@ -680,8 +680,14 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, > > > > spin_lock(&lli->lli_sa_lock); > > if (rc) { > > - if (__sa_make_ready(sai, entry, rc)) > > + if (__sa_make_ready(sai, entry, rc)) { > > + /* LU-9210 : Under the right conditions even 'ls' > > + * can cause the statahead to fail. Using a memory > > + * barrier resolves this issue. > > + */ > > + smp_mb(); > > wake_up(&sai->sai_waitq); > > + } > > } else { > > int first = 0; > > entry->se_minfo = minfo; > > -- > > 1.8.3.1 > > Again, this is a fairly lame comment to justify the smp_mb(). > It appears to me that the issue is most likely the value of > entry->se_state. > __sa_make_ready() sets this and revalidate_statahead_dentry tests it > after waiting on sai_waitq. > So I think it would be best if we changed __sa_make_ready() to > > smp_store_release(&entry->se_state, ret < 0 ? SA_ENTRY_INVA : SA_ENTRY_SUCC) > > and in ll_statahead_interpret() have > > if (smp_load_acquire(&entry->se_state) == SA_ENTRY_SUCC && > entry->se_inode) { > > This would make it obvious which variable was important, and would show > the paired synchronization points. If you think this is lame you should be the JIRA ticket and the original patch. It had zero info so I attempted to extract what I could out of the ticket. Hopefully Lai can fill in the details. I have no problems fixing this another way. I don't see a way in the ticket to easily reproduce this problem to see the new approach would fix it :-( From neilb at suse.com Mon Oct 22 02:48:19 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 13:48:19 +1100 Subject: [lustre-devel] [PATCH 01/10] lustre: lnd: set device capabilities In-Reply-To: References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-2-git-send-email-jsimmons@infradead.org> <87efcpdsnz.fsf@notabene.neil.brown.name> Message-ID: <87va5u8znw.fsf@notabene.neil.brown.name> On Sat, Oct 20 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > From: Amir Shehata >> > >> > MLX-4, MLX-5 and OPA support different capabilities. Query the >> > device and cache the capabilities of the device for future use. >> > >> > At the time of the patches creation MLX5 could support fast >> > registration and gaps while MLX4 and OPA only support FMR >> > >> > Signed-off-by: Amir Shehata >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-10129 >> > Reviewed-on: https://review.whamcloud.com/30309 >> > Reviewed-by: Alexey Lyashkov >> > Reviewed-by: Dmitry Eremin >> > Reviewed-by: James Simmons >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c | 41 ++++++++++++---------- >> > .../staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h | 5 +++ >> > 2 files changed, 28 insertions(+), 18 deletions(-) >> > >> > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > index bf969b3..b10658b 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c >> > @@ -1399,6 +1399,7 @@ static int kiblnd_alloc_fmr_pool(struct kib_fmr_poolset *fps, struct kib_fmr_poo >> > else >> > CERROR("FMRs are not supported\n"); >> > } >> > + fpo->fpo_is_fmr = true; >> > >> > return rc; >> > } >> > @@ -1408,6 +1409,8 @@ static int kiblnd_alloc_freg_pool(struct kib_fmr_poolset *fps, struct kib_fmr_po >> > struct kib_fast_reg_descriptor *frd; >> > int i, rc; >> > >> > + fpo->fpo_is_fmr = false; >> > + >> > INIT_LIST_HEAD(&fpo->fast_reg.fpo_pool_list); >> > fpo->fast_reg.fpo_pool_size = 0; >> > for (i = 0; i < fps->fps_pool_size; i++) { >> > @@ -1469,23 +1472,7 @@ static int kiblnd_create_fmr_pool(struct kib_fmr_poolset *fps, >> > fpo->fpo_hdev = kiblnd_current_hdev(dev); >> > dev_attr = &fpo->fpo_hdev->ibh_ibdev->attrs; >> > >> > - /* Check for FMR or FastReg support */ >> > - fpo->fpo_is_fmr = 0; >> > - if (fpo->fpo_hdev->ibh_ibdev->alloc_fmr && >> > - fpo->fpo_hdev->ibh_ibdev->dealloc_fmr && >> > - fpo->fpo_hdev->ibh_ibdev->map_phys_fmr && >> > - fpo->fpo_hdev->ibh_ibdev->unmap_fmr) { >> > - LCONSOLE_INFO("Using FMR for registration\n"); >> > - fpo->fpo_is_fmr = 1; >> > - } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { >> > - LCONSOLE_INFO("Using FastReg for registration\n"); >> > - } else { >> > - rc = -ENOSYS; >> > - LCONSOLE_ERROR_MSG(rc, "IB device does not support FMRs nor FastRegs, can't register memory\n"); >> > - goto out_fpo; >> > - } >> > - >> > - if (fpo->fpo_is_fmr) >> > + if (dev->ibd_dev_caps & IBLND_DEV_CAPS_FMR_ENABLED) >> > rc = kiblnd_alloc_fmr_pool(fps, fpo); >> > else >> > rc = kiblnd_alloc_freg_pool(fps, fpo); >> > @@ -2261,6 +2248,9 @@ static int kiblnd_net_init_pools(struct kib_net *net, struct lnet_ni *ni, >> > >> > static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) >> > { >> > + struct ib_device_attr *dev_attr = &hdev->ibh_ibdev->attrs; >> > + int rc = 0; >> > + >> > /* >> > * It's safe to assume a HCA can handle a page size >> > * matching that of the native system >> > @@ -2269,7 +2259,22 @@ static int kiblnd_hdev_get_attr(struct kib_hca_dev *hdev) >> > hdev->ibh_page_size = 1 << PAGE_SHIFT; >> > hdev->ibh_page_mask = ~((__u64)hdev->ibh_page_size - 1); >> > >> > - hdev->ibh_mr_size = hdev->ibh_ibdev->attrs.max_mr_size; >> > + if (hdev->ibh_ibdev->alloc_fmr && >> > + hdev->ibh_ibdev->dealloc_fmr && >> > + hdev->ibh_ibdev->map_phys_fmr && >> > + hdev->ibh_ibdev->unmap_fmr) { >> > + LCONSOLE_INFO("Using FMR for registration\n"); >> > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FMR_ENABLED; >> > + } else if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { >> > + LCONSOLE_INFO("Using FastReg for registration\n"); >> > + hdev->ibh_dev->ibd_dev_caps |= IBLND_DEV_CAPS_FASTREG_ENABLED; >> > + } else { >> > + CERROR("IB device does not support FMRs nor FastRegs, can't register memory: %d\n", >> > + rc); >> > + return -ENXIO; >> > + } >> > + >> > + hdev->ibh_mr_size = dev_attr->max_mr_size; >> > if (hdev->ibh_mr_size == ~0ULL) { >> > hdev->ibh_mr_shift = 64; >> > return 0; >> > diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > index a4438d2..9f0a47d 100644 >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h >> > @@ -73,6 +73,10 @@ >> > #define IBLND_N_SCHED 2 >> > #define IBLND_N_SCHED_HIGH 4 >> > >> > +#define IBLND_DEV_CAPS_FASTREG_ENABLED 0x1 >> > +#define IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT 0x2 >> > +#define IBLND_DEV_CAPS_FMR_ENABLED 0x4 >> > + >> >> BIT(0), BIT(1), .... ??? >> >> > struct kib_tunables { >> > int *kib_dev_failover; /* HCA failover */ >> > unsigned int *kib_service; /* IB service number */ >> > @@ -162,6 +166,7 @@ struct kib_dev { >> > unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ >> > struct list_head ibd_nets; >> > struct kib_hca_dev *ibd_hdev; >> > + u32 ibd_dev_caps; >> >> "unsigned int" would be better I think, but it isn't very important. > > Actually better yet it could be changed to an enum. Move the below to > just above struct kib_dev { > > enum ibd_dev_caps { > IBLND_DEV_CAPS_FASTREG_ENABLED = BIT(0), > IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT = BIT(1), > IBLND_DEV_CAPS_FMR_ENABLED = BIT(2), > } > > and change ibd_dev_caps from u32 to enum ibd_dev_caps. > > Do you mind if that is a follow on patch? > Yes, that would be good, thanks. I'll apply this patch as it is. Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 03:09:29 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 14:09:29 +1100 Subject: [lustre-devel] [PATCH 03/10] lustre: lnd: rework map_on_demand behavior In-Reply-To: References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-4-git-send-email-jsimmons@infradead.org> <87bm7tdrvu.fsf@notabene.neil.brown.name> Message-ID: <87sh0y8yom.fsf@notabene.neil.brown.name> On Sat, Oct 20 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > @@ -1320,9 +1324,8 @@ static void kiblnd_destroy_fmr_pool(struct kib_fmr_pool *fpo) >> > { >> > LASSERT(!fpo->fpo_map_count); >> > >> > - if (fpo->fpo_is_fmr) { >> > - if (fpo->fmr.fpo_fmr_pool) >> > - ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); >> > + if (fpo->fpo_is_fmr && fpo->fmr.fpo_fmr_pool) { >> > + ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); >> > } else { >> > struct kib_fast_reg_descriptor *frd; >> > int i = 0; >> >> This change looks strange. >> With the new code: if fpo_fmr_pool is NULL, then the fpo_pool_list is >> destroyed, even though fpo_is_fmr. >> >> Are we sure that is correct?? >> I don't really understand this code so it might be correct, but the >> change looks wrong. >> >> Can someone please confirm that it really is right - and maybe explain >> why? > > It is wrong!!! The only reason it didn't show up is that fp_fmr_pool is > very unlikely to NULL. I understand why this bug was introduced since > its desirable to reduce the indentation. This is the fault of how the > code is written. To avoid this in the future it should be written: Thanks for the confirmation. As the 'else' clause is significantly more indented than the 'then' cause, reducing the indentation there seems gratuitous. I've removed the offending hunk from the patch. If you particularly want to proceed with the version below I won't object. > > if (!fpo->fpo_is_fmr) { > struct kib_fast_reg_descriptor *frd, *tmp; > .... > } else if (fpo->fmr.fpo_fmr_pool) { > ib_destroy_fmr_pool(fpo->fmr.fpo_fmr_pool); > } > > I opened a ticket for https://jira.whamcloud.com/browse/LU-11552 and > submitted a patch - https://review.whamcloud.com/#/c/33408. To address > this. Thanks for following up this side too! NeilBrown > > So please remove this part from the change. We could redo the patch to > include the above or I could just send a follow up patch to make this > code clearer. I leave that up to you. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 03:26:42 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 14:26:42 +1100 Subject: [lustre-devel] [PATCH 04/28] lustre: ptlrpc: Do not assert when bd_nob_transferred != 0 In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-5-git-send-email-jsimmons@infradead.org> <87va60cgjx.fsf@notabene.neil.brown.name> Message-ID: <87pnw28xvx.fsf@notabene.neil.brown.name> On Sun, Oct 21 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > From: Doug Oucharek >> > >> > There is a case in the routine ptlrpc_register_bulk() where we were >> > asserting if bd_nob_transferred != 0 when not resending. There is >> > evidence that network errors can create a situation where >> > this does happen. So we should not be asserting! >> > >> > This patch changes that assert to an error return code of -EIO. >> > >> > Signed-off-by: Doug Oucharek >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-9828 >> > Reviewed-on: https://review.whamcloud.com/28491 >> > Reviewed-by: Dmitry Eremin >> > Reviewed-by: Sonia Sharma >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > drivers/staging/lustre/lustre/ptlrpc/niobuf.c | 8 ++++++-- >> > 1 file changed, 6 insertions(+), 2 deletions(-) >> > >> > diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c >> > index 27eb1c0..7e7db24 100644 >> > --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c >> > +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c >> > @@ -139,8 +139,12 @@ static int ptlrpc_register_bulk(struct ptlrpc_request *req) >> > /* cleanup the state of the bulk for it will be reused */ >> > if (req->rq_resend || req->rq_send_state == LUSTRE_IMP_REPLAY) >> > desc->bd_nob_transferred = 0; >> > - else >> > - LASSERT(desc->bd_nob_transferred == 0); >> > + else if (desc->bd_nob_transferred != 0) >> > + /* If the network failed after an RPC was sent, this condition >> > + * could happen. Rather than assert (was here before), return >> > + * an EIO error. >> > + */ >> > + return -EIO; >> >> This looks weird, and the justification is rather lame. >> I wonder if this is an attempt to fix the same problem that the smp_mb() >> in the previous patch was attempting to fix (and I'm not yet convinced >> that either is the correct fix). > > When the above condition happens the LASSERT ends up taking out the > node with a panic which in turn kills the application running on the cluster. > When replaced with reporting an EIO error the node survives as well as the > job. The job might fail at its IO but it wouldn't fail performing its work > flow which is way more important. Yes, a meaningless error is better than a crash, but a proper fix is better still. As I said, my guess is that the memory barrier in the previous patch might have fixed the bug, so the LASSERT can remain. Doug: is there any chance that this might be the case? Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 03:44:38 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 14:44:38 +1100 Subject: [lustre-devel] [PATCH 06/28] lustre: ldlm: ELC shouldn't wait on lock flush In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-7-git-send-email-jsimmons@infradead.org> <87sh14cg8q.fsf@notabene.neil.brown.name> Message-ID: <87mur68x21.fsf@notabene.neil.brown.name> On Sat, Oct 20 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > From: Andriy Skulysh >> > >> > The commit 08fd034670b5 ("staging: lustre: ldlm: revert the changes >> > for lock canceling policy") removed the fix for LU-4300 when lru_resize >> > is disabled. >> > >> > Introduce ldlm_cancel_aged_no_wait_policy to be used by ELC. >> > >> > Signed-off-by: Andriy Skulysh >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-8578 >> > Seagate-bug-id: MRP-3662 >> > Reviewed-on: https://review.whamcloud.com/22286 >> > Reviewed-by: Vitaly Fertman >> > Reviewed-by: Patrick Farrell >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > drivers/staging/lustre/lustre/ldlm/ldlm_internal.h | 1 - >> > drivers/staging/lustre/lustre/ldlm/ldlm_request.c | 51 +++++++++++++++------- >> > 2 files changed, 35 insertions(+), 17 deletions(-) >> > >> > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h >> > index 1d7c727..709c527 100644 >> > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h >> > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h >> > @@ -96,7 +96,6 @@ enum { >> > LDLM_LRU_FLAG_NO_WAIT = BIT(4), /* Cancel locks w/o blocking (neither >> > * sending nor waiting for any rpcs) >> > */ >> > - LDLM_LRU_FLAG_LRUR_NO_WAIT = BIT(5), /* LRUR + NO_WAIT */ >> > }; >> > >> > int ldlm_cancel_lru(struct ldlm_namespace *ns, int nr, >> > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c >> > index 80260b07..3eb5036 100644 >> > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_request.c >> > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_request.c >> > @@ -579,8 +579,8 @@ int ldlm_prep_elc_req(struct obd_export *exp, struct ptlrpc_request *req, >> > req_capsule_filled_sizes(pill, RCL_CLIENT); >> > avail = ldlm_capsule_handles_avail(pill, RCL_CLIENT, canceloff); >> > >> > - flags = ns_connect_lru_resize(ns) ? >> > - LDLM_LRU_FLAG_LRUR_NO_WAIT : LDLM_LRU_FLAG_AGED; >> > + flags = LDLM_LRU_FLAG_NO_WAIT | ns_connect_lru_resize(ns) ? >> > + LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED; >> > to_free = !ns_connect_lru_resize(ns) && >> > opc == LDLM_ENQUEUE ? 1 : 0; >> >> Bug. >> The commit in SFS-lustre (7ca60f33893) is correct, but you dropped the >> parentheses which introduces a bug. >> >> While the SFS code is correct, it is formatted badly. >> It should be >> >> lru_flags = LDLM_LRU_FLAG_NO_WAIT | >> (ns_connect_lru_resize(ns) ? >> LDLM_LRU_FLAG_LRUR : LDLM_LRU_FLAG_AGED); >> or similar. > > Thanks for finding that. Shall I submit another patch to fix that or will > you fix it up when you apply it to lustre-testing? I've fixed up the patch - thanks. NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 03:47:26 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 14:47:26 +1100 Subject: [lustre-devel] [PATCH 11/28] lustre: llite: use security context if it's enabled in the kernel In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-12-git-send-email-jsimmons@infradead.org> <87pnw8cflq.fsf@notabene.neil.brown.name> Message-ID: <87k1ma8wxd.fsf@notabene.neil.brown.name> On Sat, Oct 20 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > From: Alex Zhuravlev >> > >> > if it's disabled, then Lustre stop to work properly (can not create >> > files, etc) >> > >> > Signed-off-by: Alex Zhuravlev >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-9578 >> > Reviewed-on: https://review.whamcloud.com/27364 >> > Reviewed-by: Andreas Dilger >> > Reviewed-by: Chris Horn >> > Reviewed-by: James Simmons >> > Reviewed-by: Sebastien Buisson >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > drivers/staging/lustre/lustre/llite/llite_lib.c | 3 ++- >> > 1 file changed, 2 insertions(+), 1 deletion(-) >> > >> > diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c >> > index 22b545e..153aa12 100644 >> > --- a/drivers/staging/lustre/lustre/llite/llite_lib.c >> > +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c >> > @@ -243,8 +243,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) >> > if (sbi->ll_flags & LL_SBI_ALWAYS_PING) >> > data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; >> > >> > +#ifdef CONFIG_SECURITY >> > data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; >> > - >> > +#endif >> >> Policy is to avoid #ifdef in .c files where possible. >> If we put something like >> #ifdef CONFIG_SECURITY >> #define OBD_CONNECT2_FILE_SECURITY (OBD_CONNECT2_FILE_SECCTX) >> #else >> #define OBD_CONNECT2_FILE_SECURITY (0) >> #endif >> >> in a .h file, then use OBD_CONNECT2_FILE_SECURITY both here and in >> obd_connect_has_secctx(), >> then the latter could would be optimized away by the compiler. Wouldn't >> be a big win I guess as it is only used once in a trivial context. > > I suggest that we move obd_connect_has_secctx() to llite_internal.h. Also > that function should return bool. Besides this create an inline function > obd_connect_set_secctx() for llite_internal.h. Will submit a patch for > OpenSFS branch. Shall I redo this patch or submit a cleanup later? Sounds like a good plan. Please submit a cleanup. I'll commit this patch as-is (as it isn't exactly "broken", and a resolution has been agreed). Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 03:58:01 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 14:58:01 +1100 Subject: [lustre-devel] [PATCH 15/28] lustre: llite: fix for stat under kthread and X86_X32 In-Reply-To: <87ftx4c9e6.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-16-git-send-email-jsimmons@infradead.org> <87ftx4c9e6.fsf@notabene.neil.brown.name> Message-ID: <87h8he8wfq.fsf@notabene.neil.brown.name> On Thu, Oct 18 2018, NeilBrown wrote: > On Sun, Oct 14 2018, James Simmons wrote: > >> From: Frank Zago >> >> Under the following conditions, ll_getattr will flatten the inode >> number when it shouldn't: >> >> - the X86_X32 architecture is defined CONFIG_X86_X32, and not even >> used, >> - ll_getattr is called from a kernel thread (though vfs_getattr for >> instance.) >> >> This has the result that inode numbers are different whether the same >> file is stat'ed from a kernel thread, or from a syscall. For instance, >> 4198401 vs. 144115205272502273. >> >> ll_getattr calls ll_need_32bit_api to determine whether the task is 32 >> bits. When the combination is kthread+X86_X32, that function returns >> that the task is 32 bits, which is incorrect, as the kernel is 64 >> bits. >> >> The solution is to check whether the call is from a kernel thread >> (which is 64 bits) and act consequently. >> >> Signed-off-by: Frank Zago >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9468 >> Reviewed-on: https://review.whamcloud.com/26992 >> Reviewed-by: Andreas Dilger >> Reviewed-by: Dmitry Eremin >> Signed-off-by: James Simmons >> --- >> drivers/staging/lustre/lustre/llite/dir.c | 6 +++--- >> drivers/staging/lustre/lustre/llite/lcommon_cl.c | 2 +- >> .../staging/lustre/lustre/llite/llite_internal.h | 22 +++++++++++++++++----- >> 3 files changed, 21 insertions(+), 9 deletions(-) >> >> diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c >> index 231b351..19c5e9c 100644 >> --- a/drivers/staging/lustre/lustre/llite/dir.c >> +++ b/drivers/staging/lustre/lustre/llite/dir.c >> @@ -202,7 +202,7 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data, >> { >> struct ll_sb_info *sbi = ll_i2sbi(inode); >> __u64 pos = *ppos; >> - int is_api32 = ll_need_32bit_api(sbi); >> + bool is_api32 = ll_need_32bit_api(sbi); >> int is_hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; >> struct page *page; >> bool done = false; >> @@ -296,7 +296,7 @@ static int ll_readdir(struct file *filp, struct dir_context *ctx) >> struct ll_sb_info *sbi = ll_i2sbi(inode); >> __u64 pos = lfd ? lfd->lfd_pos : 0; >> int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH; >> - int api32 = ll_need_32bit_api(sbi); >> + bool api32 = ll_need_32bit_api(sbi); >> struct md_op_data *op_data; >> int rc; >> >> @@ -1674,7 +1674,7 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin) >> struct inode *inode = file->f_mapping->host; >> struct ll_file_data *fd = LUSTRE_FPRIVATE(file); >> struct ll_sb_info *sbi = ll_i2sbi(inode); >> - int api32 = ll_need_32bit_api(sbi); >> + bool api32 = ll_need_32bit_api(sbi); >> loff_t ret = -EINVAL; >> >> switch (origin) { >> diff --git a/drivers/staging/lustre/lustre/llite/lcommon_cl.c b/drivers/staging/lustre/lustre/llite/lcommon_cl.c >> index 30f17ea..20a3c74 100644 >> --- a/drivers/staging/lustre/lustre/llite/lcommon_cl.c >> +++ b/drivers/staging/lustre/lustre/llite/lcommon_cl.c >> @@ -267,7 +267,7 @@ void cl_inode_fini(struct inode *inode) >> /** >> * build inode number from passed @fid >> */ >> -__u64 cl_fid_build_ino(const struct lu_fid *fid, int api32) >> +u64 cl_fid_build_ino(const struct lu_fid *fid, bool api32) >> { >> if (BITS_PER_LONG == 32 || api32) >> return fid_flatten32(fid); >> diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h >> index dcb2fed..796a8ae 100644 >> --- a/drivers/staging/lustre/lustre/llite/llite_internal.h >> +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h >> @@ -651,13 +651,25 @@ static inline struct inode *ll_info2i(struct ll_inode_info *lli) >> __u32 ll_i2suppgid(struct inode *i); >> void ll_i2gids(__u32 *suppgids, struct inode *i1, struct inode *i2); >> >> -static inline int ll_need_32bit_api(struct ll_sb_info *sbi) >> +static inline bool ll_need_32bit_api(struct ll_sb_info *sbi) >> { >> #if BITS_PER_LONG == 32 >> - return 1; >> + return true; >> #elif defined(CONFIG_COMPAT) >> - return unlikely(in_compat_syscall() || >> - (sbi->ll_flags & LL_SBI_32BIT_API)); >> + if (unlikely(sbi->ll_flags & LL_SBI_32BIT_API)) >> + return true; >> + >> +#ifdef CONFIG_X86_X32 >> + /* in_compat_syscall() returns true when called from a kthread >> + * and CONFIG_X86_X32 is enabled, which is wrong. So check >> + * whether the caller comes from a syscall (ie. not a kthread) >> + * before calling in_compat_syscall(). >> + */ >> + if (current->flags & PF_KTHREAD) >> + return false; >> +#endif > > This is wrong. We should fix in_compat_syscall(), not work around it > here. > (and then there is that fact that the patch changes 'int' to 'bool' > without explaining that in the change description). > > I've sent a query to some relevant people (Cc:ed to James) to ask about > fixing in_compat_syscall(). Upstream say in_compat_syscall() should only be called from a syscall, so I have change the patch to the below. We probably need to remove this in_compat_syscall() before going mainline. NeilBrown -static inline int ll_need_32bit_api(struct ll_sb_info *sbi) +static inline bool ll_need_32bit_api(struct ll_sb_info *sbi) { #if BITS_PER_LONG == 32 - return 1; -#elif defined(CONFIG_COMPAT) - return unlikely(in_compat_syscall() || - (sbi->ll_flags & LL_SBI_32BIT_API)); + return true; +#else + if (unlikely(sbi->ll_flags & LL_SBI_32BIT_API)) + return true; + +#if defined(CONFIG_COMPAT) + /* in_compat_syscall() is only meaningful inside a syscall. + * As this can be called from a kthread (e.g. nfsd), we + * need to catch that case first. kthreads never need the + * 32bit api. + */ + if (current->flags & PF_KTHREAD) + return false; + + return unlikely(in_compat_syscall()); #else - return unlikely(sbi->ll_flags & LL_SBI_32BIT_API); + return false; +#endif #endif } -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 04:04:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 15:04:37 +1100 Subject: [lustre-devel] [PATCH 16/28] lustre: statahead: missing barrier before wake_up In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-17-git-send-email-jsimmons@infradead.org> <87d0s8c8tp.fsf@notabene.neil.brown.name> Message-ID: <87efci8w4q.fsf@notabene.neil.brown.name> On Sun, Oct 21 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> >> > From: Lai Siyao >> > >> > A barrier is missing before wake_up() in ll_statahead_interpret(), >> > which may cause 'ls' hang. Under the right conditions a basic 'ls' >> > can fail. The debug logs show: >> > >> > statahead.c:683:ll_statahead_interpret()) sa_entry software rc -13 >> > statahead.c:1666:ll_statahead()) revalidate statahead software: -11. >> > >> > Obviously statahead failure didn't notify 'ls' process in time. >> > The mi_cbdata can be stale so add a barrier before calling >> > wake_up(). >> > >> > Signed-off-by: Lai Siyao >> > Signed-off-by: Bob Glossman >> > WC-bug-id: https://jira.whamcloud.com/browse/LU-9210 >> > Reviewed-on: https://review.whamcloud.com/27330 >> > Reviewed-by: Nathaniel Clark >> > Reviewed-by: Oleg Drokin >> > Signed-off-by: James Simmons >> > --- >> > drivers/staging/lustre/lustre/llite/statahead.c | 8 +++++++- >> > 1 file changed, 7 insertions(+), 1 deletion(-) >> > >> > diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c >> > index 1ad308c..0174a4c 100644 >> > --- a/drivers/staging/lustre/lustre/llite/statahead.c >> > +++ b/drivers/staging/lustre/lustre/llite/statahead.c >> > @@ -680,8 +680,14 @@ static int ll_statahead_interpret(struct ptlrpc_request *req, >> > >> > spin_lock(&lli->lli_sa_lock); >> > if (rc) { >> > - if (__sa_make_ready(sai, entry, rc)) >> > + if (__sa_make_ready(sai, entry, rc)) { >> > + /* LU-9210 : Under the right conditions even 'ls' >> > + * can cause the statahead to fail. Using a memory >> > + * barrier resolves this issue. >> > + */ >> > + smp_mb(); >> > wake_up(&sai->sai_waitq); >> > + } >> > } else { >> > int first = 0; >> > entry->se_minfo = minfo; >> > -- >> > 1.8.3.1 >> >> Again, this is a fairly lame comment to justify the smp_mb(). >> It appears to me that the issue is most likely the value of >> entry->se_state. >> __sa_make_ready() sets this and revalidate_statahead_dentry tests it >> after waiting on sai_waitq. >> So I think it would be best if we changed __sa_make_ready() to >> >> smp_store_release(&entry->se_state, ret < 0 ? SA_ENTRY_INVA : SA_ENTRY_SUCC) >> >> and in ll_statahead_interpret() have >> >> if (smp_load_acquire(&entry->se_state) == SA_ENTRY_SUCC && >> entry->se_inode) { >> >> This would make it obvious which variable was important, and would show >> the paired synchronization points. > > If you think this is lame you should be the JIRA ticket and the original > patch. It had zero info so I attempted to extract what I could out of the > ticket. Hopefully Lai can fill in the details. I have no problems fixing > this another way. I don't see a way in the ticket to easily reproduce this > problem to see the new approach would fix it :-( I have imposed the version that I think is correct. See below. Thanks, NeilBrown --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -322,7 +322,11 @@ __sa_make_ready(struct ll_statahead_info *sai, struct sa_entry *entry, int ret) } } list_add(&entry->se_list, pos); - entry->se_state = ret < 0 ? SA_ENTRY_INVA : SA_ENTRY_SUCC; + /* + * LU-9210: ll_statahead_interpet must be able to see this before + * we wake it up + */ + smp_store_release(&entry->se_state, ret < 0 ? SA_ENTRY_INVA : SA_ENTRY_SUCC); return (index == sai->sai_index_wait); } @@ -1390,7 +1394,12 @@ static int revalidate_statahead_dentry(struct inode *dir, } } - if (entry->se_state == SA_ENTRY_SUCC && entry->se_inode) { + /* + * We need to see the value that was set immediately before we + * were woken up. + */ + if (smp_load_acquire(&entry->se_state) == SA_ENTRY_SUCC && + entry->se_inode) { struct inode *inode = entry->se_inode; struct lookup_intent it = { .it_op = IT_GETATTR, .it_lock_handle = entry->se_handle }; -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 04:08:24 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 15:08:24 +1100 Subject: [lustre-devel] [PATCH 20/28] lustre: obdclass: deprecate OBD_GET_VERSION ioctl In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-21-git-send-email-jsimmons@infradead.org> <87a7ncc8a0.fsf@notabene.neil.brown.name> Message-ID: <87bm7m8vyf.fsf@notabene.neil.brown.name> On Sat, Oct 20 2018, James Simmons wrote: >> On Sun, Oct 14 2018, James Simmons wrote: >> > >> > + if (!warned) { >> > + warned = true; >> > + CWARN("%s: ioctl(OBD_GET_VERSION) is deprecated, use llapi_get_version_string() and/or relink\n", >> > + current->comm); >> > + } >> >> Is there a good reason not to use WARN_ON_ONCE() here? > > Oh that is much nicer. Didn't know about it. Shall I submit a new > patch or will it be changed when applied to lustre-testing? I've made the change directly - no need to resubmit. Thanks, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 22 04:36:36 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 22 Oct 2018 15:36:36 +1100 Subject: [lustre-devel] [PATCH 00/28] lustre: more assorted fixes for lustre 2.10 In-Reply-To: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> Message-ID: <878t2q8unf.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > Another bacth of assorted fixes missing in the linux client from > lustre 2.10. All of these should be order independent and don't > collide with the PFL work that will land at a later date. Thanks, I've applied these and the other series. And pushed it all out. I ran a test and something went wrong - I haven't had a chance to look properly yet.... I'm make sure tests mostly pass before moving it out of lustre-testing. Thanks a lot, NeilBrown -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Tue Oct 23 22:34:17 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 24 Oct 2018 09:34:17 +1100 Subject: [lustre-devel] [PATCH] lustre: lu_object: fix possible hang waiting for LCS_LEAVING In-Reply-To: <878t2q8unf.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <878t2q8unf.fsf@notabene.neil.brown.name> Message-ID: <87d0s070nq.fsf@notabene.neil.brown.name> As lu_context_key_quiesce() spins waiting for LCS_LEAVING to change, it is important the we set and then clear in within a non-preemptible region. If the thread that spins pre-empty the thread that sets-and-clears the state while the state is LCS_LEAVING, then it can spin indefinitely, particularly on a single-CPU machine. Also update the comment to explain this dependency. Fixes: ac3f8fd6e61b ("staging: lustre: remove locking from lu_context_exit()") --- This is the cause of the "something" that went wrong in my recent testing that I mentioned. I wonder if preempt_enable() has recently been enhanced to encourage a preempt, to make this sort of bug easier to see. drivers/staging/lustre/lustre/obdclass/lu_object.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c index cb57abf03644..51497c144dd6 100644 --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c @@ -1654,17 +1654,20 @@ void lu_context_exit(struct lu_context *ctx) unsigned int i; LINVRNT(ctx->lc_state == LCS_ENTERED); - /* - * Ensure lu_context_key_quiesce() sees LCS_LEAVING - * or we see LCT_QUIESCENT - */ - smp_store_mb(ctx->lc_state, LCS_LEAVING); /* * Disable preempt to ensure we get a warning if * any lct_exit ever tries to sleep. That would hurt * lu_context_key_quiesce() which spins waiting for us. + * This also ensure we aren't preempted while the state + * is LCS_LEAVING, as that too would cause problems for + * lu_context_key_quiesce(). */ preempt_disable(); + /* + * Ensure lu_context_key_quiesce() sees LCS_LEAVING + * or we see LCT_QUIESCENT + */ + smp_store_mb(ctx->lc_state, LCS_LEAVING); if (ctx->lc_tags & LCT_HAS_EXIT && ctx->lc_value) { for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { struct lu_context_key *key; @@ -1677,8 +1680,8 @@ void lu_context_exit(struct lu_context *ctx) } } - preempt_enable(); smp_store_release(&ctx->lc_state, LCS_LEFT); + preempt_enable(); } EXPORT_SYMBOL(lu_context_exit); -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From jsimmons at infradead.org Tue Oct 23 23:04:37 2018 From: jsimmons at infradead.org (James Simmons) Date: Wed, 24 Oct 2018 00:04:37 +0100 (BST) Subject: [lustre-devel] [PATCH 01/10] lustre: lnd: set device capabilities In-Reply-To: <87va5u8znw.fsf@notabene.neil.brown.name> References: <1539543332-28679-1-git-send-email-jsimmons@infradead.org> <1539543332-28679-2-git-send-email-jsimmons@infradead.org> <87efcpdsnz.fsf@notabene.neil.brown.name> <87va5u8znw.fsf@notabene.neil.brown.name> Message-ID: > >> > index a4438d2..9f0a47d 100644 > >> > --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > >> > +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h > >> > @@ -73,6 +73,10 @@ > >> > #define IBLND_N_SCHED 2 > >> > #define IBLND_N_SCHED_HIGH 4 > >> > > >> > +#define IBLND_DEV_CAPS_FASTREG_ENABLED 0x1 > >> > +#define IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT 0x2 > >> > +#define IBLND_DEV_CAPS_FMR_ENABLED 0x4 > >> > + > >> > >> BIT(0), BIT(1), .... ??? > >> > >> > struct kib_tunables { > >> > int *kib_dev_failover; /* HCA failover */ > >> > unsigned int *kib_service; /* IB service number */ > >> > @@ -162,6 +166,7 @@ struct kib_dev { > >> > unsigned int ibd_can_failover; /* IPoIB interface is a bonding master */ > >> > struct list_head ibd_nets; > >> > struct kib_hca_dev *ibd_hdev; > >> > + u32 ibd_dev_caps; > >> > >> "unsigned int" would be better I think, but it isn't very important. > > > > Actually better yet it could be changed to an enum. Move the below to > > just above struct kib_dev { > > > > enum ibd_dev_caps { > > IBLND_DEV_CAPS_FASTREG_ENABLED = BIT(0), > > IBLND_DEV_CAPS_FASTREG_GAPS_SUPPORT = BIT(1), > > IBLND_DEV_CAPS_FMR_ENABLED = BIT(2), > > } > > > > and change ibd_dev_caps from u32 to enum ibd_dev_caps. > > > > Do you mind if that is a follow on patch? > > > > Yes, that would be good, thanks. > I'll apply this patch as it is. New patch at https://review.whamcloud.com/#/c/33409 I will push shortly to linux client. From jsimmons at infradead.org Tue Oct 23 23:07:08 2018 From: jsimmons at infradead.org (James Simmons) Date: Wed, 24 Oct 2018 00:07:08 +0100 (BST) Subject: [lustre-devel] [PATCH 11/28] lustre: llite: use security context if it's enabled in the kernel In-Reply-To: <87k1ma8wxd.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-12-git-send-email-jsimmons@infradead.org> <87pnw8cflq.fsf@notabene.neil.brown.name> <87k1ma8wxd.fsf@notabene.neil.brown.name> Message-ID: > >> > diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c > >> > index 22b545e..153aa12 100644 > >> > --- a/drivers/staging/lustre/lustre/llite/llite_lib.c > >> > +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c > >> > @@ -243,8 +243,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) > >> > if (sbi->ll_flags & LL_SBI_ALWAYS_PING) > >> > data->ocd_connect_flags &= ~OBD_CONNECT_PINGLESS; > >> > > >> > +#ifdef CONFIG_SECURITY > >> > data->ocd_connect_flags2 |= OBD_CONNECT2_FILE_SECCTX; > >> > - > >> > +#endif > >> > >> Policy is to avoid #ifdef in .c files where possible. > >> If we put something like > >> #ifdef CONFIG_SECURITY > >> #define OBD_CONNECT2_FILE_SECURITY (OBD_CONNECT2_FILE_SECCTX) > >> #else > >> #define OBD_CONNECT2_FILE_SECURITY (0) > >> #endif > >> > >> in a .h file, then use OBD_CONNECT2_FILE_SECURITY both here and in > >> obd_connect_has_secctx(), > >> then the latter could would be optimized away by the compiler. Wouldn't > >> be a big win I guess as it is only used once in a trivial context. > > > > I suggest that we move obd_connect_has_secctx() to llite_internal.h. Also > > that function should return bool. Besides this create an inline function > > obd_connect_set_secctx() for llite_internal.h. Will submit a patch for > > OpenSFS branch. Shall I redo this patch or submit a cleanup later? > > Sounds like a good plan. Please submit a cleanup. I'll commit this > patch as-is (as it isn't exactly "broken", and a resolution has been > agreed). New patch is at https://review.whamcloud.com/#/c/33410. Will be coming to linux client soon. From neilb at suse.com Fri Oct 26 01:39:38 2018 From: neilb at suse.com (NeilBrown) Date: Fri, 26 Oct 2018 12:39:38 +1100 Subject: [lustre-devel] [PATCH] lustre: initialize libcfs_debug_file_path Message-ID: <87y3al4hb9.fsf@notabene.neil.brown.name> This variable is assumed by the code to either be "NONE" or a file name - it shouldn't be NULL. So initialise to the compiled default. Signed-off-by: NeilBrown --- I'm going though failed tests, looking for things to fix. This fixes 77c. drivers/staging/lustre/lnet/libcfs/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c index 90d756c83520..f9544367389d 100644 --- a/drivers/staging/lustre/lnet/libcfs/debug.c +++ b/drivers/staging/lustre/lnet/libcfs/debug.c @@ -224,7 +224,7 @@ char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT; EXPORT_SYMBOL(libcfs_debug_file_path_arr); /* We need to pass a pointer here, but elsewhere this must be a const */ -static char *libcfs_debug_file_path; +static char *libcfs_debug_file_path = LIBCFS_DEBUG_FILE_PATH_DEFAULT; module_param(libcfs_debug_file_path, charp, 0644); MODULE_PARM_DESC(libcfs_debug_file_path, "Path for dumping debug logs, set 'NONE' to prevent log dumping"); -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Fri Oct 26 03:33:55 2018 From: neilb at suse.com (NeilBrown) Date: Fri, 26 Oct 2018 14:33:55 +1100 Subject: [lustre-devel] [PATCH] lustre: accept suffix when parsing max_pages_per_rpc In-Reply-To: <87y3al4hb9.fsf@notabene.neil.brown.name> References: <87y3al4hb9.fsf@notabene.neil.brown.name> Message-ID: <87va5p4c0s.fsf@notabene.neil.brown.name> upstream lustre allows size suffixes (K, M, G, etc) for max_pages_per_rpc. We should too. Signed-off-by: NeilBrown --- This fixes test 101g. drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index edac88440b41..feba2ef5a3bc 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -1868,11 +1868,12 @@ ssize_t max_pages_per_rpc_store(struct kobject *kobj, struct attribute *attr, struct obd_connect_data *ocd; unsigned long long val; int chunk_mask; + char *endp; int rc; - rc = kstrtoull(buffer, 10, &val); - if (rc) - return rc; + val = memparse(buffer, &endp); + if (*endp) + return -EINVAL; /* if the max_pages is specified in bytes, convert to pages */ if (val >= ONE_MB_BRW_SIZE) -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 29 00:03:02 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 29 Oct 2018 11:03:02 +1100 Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: <1539543498-29105-13-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-13-git-send-email-jsimmons@infradead.org> Message-ID: <87va5l39hl.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Alex Zhuravlev > > Even if there are no RPC requests on the set, there is no need to > wake up every second. The thread is woken up when a request is added > to the set or when the STOP bit is set, so it is sufficient to only > wake up when there are requests on the set to worry about. > > Signed-off-by: Alex Zhuravlev > WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 > Reviewed-on: https://review.whamcloud.com/28776 > Reviewed-by: Andreas Dilger > Reviewed-by: Patrick Farrell > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > index c201a88..5b4977b 100644 > --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) > } > } > > - return rc; > + return rc || test_bit(LIOD_STOP, &pc->pc_flags); > } > > /** > @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) > lu_context_enter(env.le_ses); > if (wait_event_idle_timeout(set->set_waitq, > ptlrpcd_check(&env, pc), > - (timeout ? timeout : 1) * HZ) == 0) > + timeout * HZ) == 0) > ptlrpc_expired_set(set); This is incorrect. A timeout of zero means the timeout happens after zero jiffies (immediately), it doesn't mean there is no timeout. If we want a "timeout" of zero to mean "Wait forever", we need something like: wait_event_idle_timeout(....., timeout ? (timeout * HZ) : MAX_SCHEDULE_TIMEOUT) == 0 I've updated the patch accordingly. Thanks, NeilBrown > > lu_context_exit(&env.le_ctx); > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From paf at cray.com Mon Oct 29 01:35:46 2018 From: paf at cray.com (Patrick Farrell) Date: Mon, 29 Oct 2018 01:35:46 +0000 Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: <87va5l39hl.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-13-git-send-email-jsimmons@infradead.org>, <87va5l39hl.fsf@notabene.neil.brown.name> Message-ID: Neil, Does your statement imply this would spin? It definitely doesn’t just spin (that behavior in a main “wait for work” spot of a (depending on settings) ~per-CPU daemon would render systems unusable and this patch has been in testing for a while). So what is the detailed behavior of a “timeout that expires immediately”? - Patrick ________________________________ From: lustre-devel on behalf of NeilBrown Sent: Sunday, October 28, 2018 7:03:02 PM To: James Simmons; Andreas Dilger; Oleg Drokin Cc: Lustre Development List Subject: Re: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second On Sun, Oct 14 2018, James Simmons wrote: > From: Alex Zhuravlev > > Even if there are no RPC requests on the set, there is no need to > wake up every second. The thread is woken up when a request is added > to the set or when the STOP bit is set, so it is sufficient to only > wake up when there are requests on the set to worry about. > > Signed-off-by: Alex Zhuravlev > WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 > Reviewed-on: https://review.whamcloud.com/28776 > Reviewed-by: Andreas Dilger > Reviewed-by: Patrick Farrell > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons > --- > drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > index c201a88..5b4977b 100644 > --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) > } > } > > - return rc; > + return rc || test_bit(LIOD_STOP, &pc->pc_flags); > } > > /** > @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) > lu_context_enter(env.le_ses); > if (wait_event_idle_timeout(set->set_waitq, > ptlrpcd_check(&env, pc), > - (timeout ? timeout : 1) * HZ) == 0) > + timeout * HZ) == 0) > ptlrpc_expired_set(set); This is incorrect. A timeout of zero means the timeout happens after zero jiffies (immediately), it doesn't mean there is no timeout. If we want a "timeout" of zero to mean "Wait forever", we need something like: wait_event_idle_timeout(....., timeout ? (timeout * HZ) : MAX_SCHEDULE_TIMEOUT) == 0 I've updated the patch accordingly. Thanks, NeilBrown > > lu_context_exit(&env.le_ctx); > -- > 1.8.3.1 -------------- next part -------------- An HTML attachment was scrubbed... URL: From neilb at suse.com Mon Oct 29 02:41:37 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 29 Oct 2018 13:41:37 +1100 Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-13-git-send-email-jsimmons@infradead.org> <87va5l39hl.fsf@notabene.neil.brown.name> Message-ID: <87pnvt325a.fsf@notabene.neil.brown.name> On Mon, Oct 29 2018, Patrick Farrell wrote: > Neil, > > Does your statement imply this would spin? It definitely doesn’t just > spin (that behavior in a main “wait for work” spot of a (depending on > settings) ~per-CPU daemon would render systems unusable and this patch > has been in testing for a while). So what is the detailed behavior of > a “timeout that expires immediately”? Hi Patrick, it definitely spins for me. I should have clarified that the SFS patch e81847bd0651 LU-9660 ptlrpc: do not wakeup every second is correct, as __l_wait_event() treats a timeout value of 0 as meaning an indefinite timeout. The error was in the conversion to wait_event_idle_timeout(). The various wait_event*timeout() functions treat 0 as 1 less than 1. If you want to not have a timeout, you need to not use the *_timeout() version. If a timeout is undesirable rather than fatal, then MAX_SCHEDULE_TIMEOUT can be used. In this case, that seemed best. Thanks, NeilBrown > > - Patrick > > > ________________________________ > From: lustre-devel on behalf of NeilBrown > Sent: Sunday, October 28, 2018 7:03:02 PM > To: James Simmons; Andreas Dilger; Oleg Drokin > Cc: Lustre Development List > Subject: Re: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second > > On Sun, Oct 14 2018, James Simmons wrote: > >> From: Alex Zhuravlev >> >> Even if there are no RPC requests on the set, there is no need to >> wake up every second. The thread is woken up when a request is added >> to the set or when the STOP bit is set, so it is sufficient to only >> wake up when there are requests on the set to worry about. >> >> Signed-off-by: Alex Zhuravlev >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 >> Reviewed-on: https://review.whamcloud.com/28776 >> Reviewed-by: Andreas Dilger >> Reviewed-by: Patrick Farrell >> Reviewed-by: Oleg Drokin >> Signed-off-by: James Simmons >> --- >> drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- >> 1 file changed, 2 insertions(+), 2 deletions(-) >> >> diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c >> index c201a88..5b4977b 100644 >> --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c >> +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c >> @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) >> } >> } >> >> - return rc; >> + return rc || test_bit(LIOD_STOP, &pc->pc_flags); >> } >> >> /** >> @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) >> lu_context_enter(env.le_ses); >> if (wait_event_idle_timeout(set->set_waitq, >> ptlrpcd_check(&env, pc), >> - (timeout ? timeout : 1) * HZ) == 0) >> + timeout * HZ) == 0) >> ptlrpc_expired_set(set); > > This is incorrect. > A timeout of zero means the timeout happens after zero jiffies > (immediately), it doesn't mean there is no timeout. > If we want a "timeout" of zero to mean "Wait forever", we need something > like: > > wait_event_idle_timeout(....., > timeout ? (timeout * HZ) : MAX_SCHEDULE_TIMEOUT) == 0 > > I've updated the patch accordingly. > > Thanks, > NeilBrown > >> >> lu_context_exit(&env.le_ctx); >> -- >> 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From jsimmons at infradead.org Mon Oct 29 03:31:36 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 03:31:36 +0000 (GMT) Subject: [lustre-devel] [PATCH] lustre: lu_object: fix possible hang waiting for LCS_LEAVING In-Reply-To: <87d0s070nq.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <878t2q8unf.fsf@notabene.neil.brown.name> <87d0s070nq.fsf@notabene.neil.brown.name> Message-ID: > As lu_context_key_quiesce() spins waiting for LCS_LEAVING to > change, it is important the we set and then clear in within a > non-preemptible region. If the thread that spins pre-empty the > thread that sets-and-clears the state while the state is LCS_LEAVING, > then it can spin indefinitely, particularly on a single-CPU machine. > > Also update the comment to explain this dependency. > > Fixes: ac3f8fd6e61b ("staging: lustre: remove locking from lu_context_exit()") > --- > > This is the cause of the "something" that went wrong in my recent > testing that I mentioned. I wonder if preempt_enable() has recently > been enhanced to encourage a preempt, to make this sort of bug easier to > see. > Reduced my cpu load :-) Reviewed-by: James Simmons > drivers/staging/lustre/lustre/obdclass/lu_object.c | 15 +++++++++------ > 1 file changed, 9 insertions(+), 6 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c > index cb57abf03644..51497c144dd6 100644 > --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c > +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c > @@ -1654,17 +1654,20 @@ void lu_context_exit(struct lu_context *ctx) > unsigned int i; > > LINVRNT(ctx->lc_state == LCS_ENTERED); > - /* > - * Ensure lu_context_key_quiesce() sees LCS_LEAVING > - * or we see LCT_QUIESCENT > - */ > - smp_store_mb(ctx->lc_state, LCS_LEAVING); > /* > * Disable preempt to ensure we get a warning if > * any lct_exit ever tries to sleep. That would hurt > * lu_context_key_quiesce() which spins waiting for us. > + * This also ensure we aren't preempted while the state > + * is LCS_LEAVING, as that too would cause problems for > + * lu_context_key_quiesce(). > */ > preempt_disable(); > + /* > + * Ensure lu_context_key_quiesce() sees LCS_LEAVING > + * or we see LCT_QUIESCENT > + */ > + smp_store_mb(ctx->lc_state, LCS_LEAVING); > if (ctx->lc_tags & LCT_HAS_EXIT && ctx->lc_value) { > for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { > struct lu_context_key *key; > @@ -1677,8 +1680,8 @@ void lu_context_exit(struct lu_context *ctx) > } > } > > - preempt_enable(); > smp_store_release(&ctx->lc_state, LCS_LEFT); > + preempt_enable(); > } > EXPORT_SYMBOL(lu_context_exit); > > -- > 2.14.0.rc0.dirty > > From jsimmons at infradead.org Mon Oct 29 03:32:23 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 03:32:23 +0000 (GMT) Subject: [lustre-devel] [PATCH] lustre: initialize libcfs_debug_file_path In-Reply-To: <87y3al4hb9.fsf@notabene.neil.brown.name> References: <87y3al4hb9.fsf@notabene.neil.brown.name> Message-ID: > This variable is assumed by the code to either > be "NONE" or a file name - it shouldn't be NULL. > > So initialise to the compiled default. > > Signed-off-by: NeilBrown > --- > > I'm going though failed tests, looking for things to fix. > This fixes 77c. Reviewed-by: James Simmons > drivers/staging/lustre/lnet/libcfs/debug.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c > index 90d756c83520..f9544367389d 100644 > --- a/drivers/staging/lustre/lnet/libcfs/debug.c > +++ b/drivers/staging/lustre/lnet/libcfs/debug.c > @@ -224,7 +224,7 @@ char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT; > EXPORT_SYMBOL(libcfs_debug_file_path_arr); > > /* We need to pass a pointer here, but elsewhere this must be a const */ > -static char *libcfs_debug_file_path; > +static char *libcfs_debug_file_path = LIBCFS_DEBUG_FILE_PATH_DEFAULT; > module_param(libcfs_debug_file_path, charp, 0644); > MODULE_PARM_DESC(libcfs_debug_file_path, > "Path for dumping debug logs, set 'NONE' to prevent log dumping"); > -- > 2.14.0.rc0.dirty > > From jsimmons at infradead.org Mon Oct 29 03:37:51 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 03:37:51 +0000 (GMT) Subject: [lustre-devel] [PATCH] lustre: accept suffix when parsing max_pages_per_rpc In-Reply-To: <87va5p4c0s.fsf@notabene.neil.brown.name> References: <87y3al4hb9.fsf@notabene.neil.brown.name> <87va5p4c0s.fsf@notabene.neil.brown.name> Message-ID: > upstream lustre allows size suffixes (K, M, G, etc) for > max_pages_per_rpc. We should too. > > Signed-off-by: NeilBrown > --- > > This fixes test 101g. Reviewed-by: James Simmons > drivers/staging/lustre/lustre/obdclass/lprocfs_status.c | 7 ++++--- > 1 file changed, 4 insertions(+), 3 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > index edac88440b41..feba2ef5a3bc 100644 > --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c > @@ -1868,11 +1868,12 @@ ssize_t max_pages_per_rpc_store(struct kobject *kobj, struct attribute *attr, > struct obd_connect_data *ocd; > unsigned long long val; > int chunk_mask; > + char *endp; > int rc; > > - rc = kstrtoull(buffer, 10, &val); > - if (rc) > - return rc; > + val = memparse(buffer, &endp); > + if (*endp) > + return -EINVAL; > > /* if the max_pages is specified in bytes, convert to pages */ > if (val >= ONE_MB_BRW_SIZE) > -- > 2.14.0.rc0.dirty > > From jsimmons at infradead.org Mon Oct 29 03:42:10 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 03:42:10 +0000 (GMT) Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: <87pnvt325a.fsf@notabene.neil.brown.name> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-13-git-send-email-jsimmons@infradead.org> <87va5l39hl.fsf@notabene.neil.brown.name> <87pnvt325a.fsf@notabene.neil.brown.name> Message-ID: > > Neil, > > > > Does your statement imply this would spin? It definitely doesn’t just > > spin (that behavior in a main “wait for work” spot of a (depending on > > settings) ~per-CPU daemon would render systems unusable and this patch > > has been in testing for a while). So what is the detailed behavior of > > a “timeout that expires immediately”? > > Hi Patrick, > it definitely spins for me. Ah that is where the high cpu load is coming from. > I should have clarified that the SFS patch > > e81847bd0651 LU-9660 ptlrpc: do not wakeup every second > > is correct, as __l_wait_event() treats a timeout value of 0 as meaning an > indefinite timeout. > The error was in the conversion to wait_event_idle_timeout(). The > various wait_event*timeout() functions treat 0 as 1 less than 1. > If you want to not have a timeout, you need to not use the *_timeout() > version. > If a timeout is undesirable rather than fatal, then > MAX_SCHEDULE_TIMEOUT can be used. In this case, that seemed best. I missed that in the conversion. Now that I know that the mapping I will do the future server code port correctly ;-) > > - Patrick > > > > > > ________________________________ > > From: lustre-devel on behalf of NeilBrown > > Sent: Sunday, October 28, 2018 7:03:02 PM > > To: James Simmons; Andreas Dilger; Oleg Drokin > > Cc: Lustre Development List > > Subject: Re: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second > > > > On Sun, Oct 14 2018, James Simmons wrote: > > > >> From: Alex Zhuravlev > >> > >> Even if there are no RPC requests on the set, there is no need to > >> wake up every second. The thread is woken up when a request is added > >> to the set or when the STOP bit is set, so it is sufficient to only > >> wake up when there are requests on the set to worry about. > >> > >> Signed-off-by: Alex Zhuravlev > >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 > >> Reviewed-on: https://review.whamcloud.com/28776 > >> Reviewed-by: Andreas Dilger > >> Reviewed-by: Patrick Farrell > >> Reviewed-by: Oleg Drokin > >> Signed-off-by: James Simmons > >> --- > >> drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- > >> 1 file changed, 2 insertions(+), 2 deletions(-) > >> > >> diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> index c201a88..5b4977b 100644 > >> --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) > >> } > >> } > >> > >> - return rc; > >> + return rc || test_bit(LIOD_STOP, &pc->pc_flags); > >> } > >> > >> /** > >> @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) > >> lu_context_enter(env.le_ses); > >> if (wait_event_idle_timeout(set->set_waitq, > >> ptlrpcd_check(&env, pc), > >> - (timeout ? timeout : 1) * HZ) == 0) > >> + timeout * HZ) == 0) > >> ptlrpc_expired_set(set); > > > > This is incorrect. > > A timeout of zero means the timeout happens after zero jiffies > > (immediately), it doesn't mean there is no timeout. > > If we want a "timeout" of zero to mean "Wait forever", we need something > > like: > > > > wait_event_idle_timeout(....., > > timeout ? (timeout * HZ) : MAX_SCHEDULE_TIMEOUT) == 0 > > > > I've updated the patch accordingly. > > > > Thanks, > > NeilBrown > > > >> > >> lu_context_exit(&env.le_ctx); > >> -- > >> 1.8.3.1 > From jsimmons at infradead.org Mon Oct 29 03:49:52 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 03:49:52 +0000 (GMT) Subject: [lustre-devel] Using loff_t or u64 for PFL port Message-ID: While doing the PFL port I noticed a inconsistent use of loff_t and u64. While in Greg's branch several patches landed to make the prototypes match the function with changing any unmatching loff_t/u64 to use u64. I don't know if using u64 solely as the proper solution. What is the proper unit to use? From neilb at suse.com Mon Oct 29 04:31:55 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 29 Oct 2018 15:31:55 +1100 Subject: [lustre-devel] [PATCH] lustre: lu_object: fix possible hang waiting for LCS_LEAVING In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <878t2q8unf.fsf@notabene.neil.brown.name> <87d0s070nq.fsf@notabene.neil.brown.name> Message-ID: <87muqx2x1g.fsf@notabene.neil.brown.name> On Mon, Oct 29 2018, James Simmons wrote: >> As lu_context_key_quiesce() spins waiting for LCS_LEAVING to >> change, it is important the we set and then clear in within a >> non-preemptible region. If the thread that spins pre-empty the >> thread that sets-and-clears the state while the state is LCS_LEAVING, >> then it can spin indefinitely, particularly on a single-CPU machine. >> >> Also update the comment to explain this dependency. >> >> Fixes: ac3f8fd6e61b ("staging: lustre: remove locking from lu_context_exit()") >> --- >> >> This is the cause of the "something" that went wrong in my recent >> testing that I mentioned. I wonder if preempt_enable() has recently >> been enhanced to encourage a preempt, to make this sort of bug easier to >> see. >> > > Reduced my cpu load :-) > > Reviewed-by: James Simmons Thanks, NeilBrown > >> drivers/staging/lustre/lustre/obdclass/lu_object.c | 15 +++++++++------ >> 1 file changed, 9 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/staging/lustre/lustre/obdclass/lu_object.c b/drivers/staging/lustre/lustre/obdclass/lu_object.c >> index cb57abf03644..51497c144dd6 100644 >> --- a/drivers/staging/lustre/lustre/obdclass/lu_object.c >> +++ b/drivers/staging/lustre/lustre/obdclass/lu_object.c >> @@ -1654,17 +1654,20 @@ void lu_context_exit(struct lu_context *ctx) >> unsigned int i; >> >> LINVRNT(ctx->lc_state == LCS_ENTERED); >> - /* >> - * Ensure lu_context_key_quiesce() sees LCS_LEAVING >> - * or we see LCT_QUIESCENT >> - */ >> - smp_store_mb(ctx->lc_state, LCS_LEAVING); >> /* >> * Disable preempt to ensure we get a warning if >> * any lct_exit ever tries to sleep. That would hurt >> * lu_context_key_quiesce() which spins waiting for us. >> + * This also ensure we aren't preempted while the state >> + * is LCS_LEAVING, as that too would cause problems for >> + * lu_context_key_quiesce(). >> */ >> preempt_disable(); >> + /* >> + * Ensure lu_context_key_quiesce() sees LCS_LEAVING >> + * or we see LCT_QUIESCENT >> + */ >> + smp_store_mb(ctx->lc_state, LCS_LEAVING); >> if (ctx->lc_tags & LCT_HAS_EXIT && ctx->lc_value) { >> for (i = 0; i < ARRAY_SIZE(lu_keys); ++i) { >> struct lu_context_key *key; >> @@ -1677,8 +1680,8 @@ void lu_context_exit(struct lu_context *ctx) >> } >> } >> >> - preempt_enable(); >> smp_store_release(&ctx->lc_state, LCS_LEFT); >> + preempt_enable(); >> } >> EXPORT_SYMBOL(lu_context_exit); >> >> -- >> 2.14.0.rc0.dirty >> >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Mon Oct 29 04:34:15 2018 From: neilb at suse.com (NeilBrown) Date: Mon, 29 Oct 2018 15:34:15 +1100 Subject: [lustre-devel] [PATCH] lustre: initialize libcfs_debug_file_path In-Reply-To: References: <87y3al4hb9.fsf@notabene.neil.brown.name> Message-ID: <87k1m12wxk.fsf@notabene.neil.brown.name> On Mon, Oct 29 2018, James Simmons wrote: >> This variable is assumed by the code to either >> be "NONE" or a file name - it shouldn't be NULL. >> >> So initialise to the compiled default. >> >> Signed-off-by: NeilBrown >> --- >> >> I'm going though failed tests, looking for things to fix. >> This fixes 77c. > > Reviewed-by: James Simmons Thanks for these two reviews. NeilBrown > >> drivers/staging/lustre/lnet/libcfs/debug.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/drivers/staging/lustre/lnet/libcfs/debug.c b/drivers/staging/lustre/lnet/libcfs/debug.c >> index 90d756c83520..f9544367389d 100644 >> --- a/drivers/staging/lustre/lnet/libcfs/debug.c >> +++ b/drivers/staging/lustre/lnet/libcfs/debug.c >> @@ -224,7 +224,7 @@ char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT; >> EXPORT_SYMBOL(libcfs_debug_file_path_arr); >> >> /* We need to pass a pointer here, but elsewhere this must be a const */ >> -static char *libcfs_debug_file_path; >> +static char *libcfs_debug_file_path = LIBCFS_DEBUG_FILE_PATH_DEFAULT; >> module_param(libcfs_debug_file_path, charp, 0644); >> MODULE_PARM_DESC(libcfs_debug_file_path, >> "Path for dumping debug logs, set 'NONE' to prevent log dumping"); >> -- >> 2.14.0.rc0.dirty >> >> -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From adilger at whamcloud.com Mon Oct 29 09:23:04 2018 From: adilger at whamcloud.com (Andreas Dilger) Date: Mon, 29 Oct 2018 09:23:04 +0000 Subject: [lustre-devel] Using loff_t or u64 for PFL port In-Reply-To: References: Message-ID: <8C539D08-D7F6-4B17-8A8D-01FEFF03BD2E@whamcloud.com> On Oct 28, 2018, at 21:49, James Simmons wrote: > > > While doing the PFL port I noticed a inconsistent use of loff_t and u64. > While in Greg's branch several patches landed to make the prototypes > match the function with changing any unmatching loff_t/u64 to use u64. > I don't know if using u64 solely as the proper solution. What is the > proper unit to use? James, could you please clarify what part of the code you are referencing? Cheers, Andreas --- Andreas Dilger Principal Lustre Architect Whamcloud From paf at cray.com Mon Oct 29 14:17:51 2018 From: paf at cray.com (Patrick Farrell) Date: Mon, 29 Oct 2018 14:17:51 +0000 Subject: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second In-Reply-To: References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-13-git-send-email-jsimmons@infradead.org> <87va5l39hl.fsf@notabene.neil.brown.name> <87pnvt325a.fsf@notabene.neil.brown.name>, Message-ID: Ah, OK! Thanks, Neil. That makes sense. I just knew there was no way that had been missed in the WC branch - Just as I'm sure you two noticed it immediately in your testing. Also useful to know about the timeout functions and 0. Regards, Patrick ________________________________ From: James Simmons Sent: Sunday, October 28, 2018 10:42:10 PM To: NeilBrown Cc: Patrick Farrell; Andreas Dilger; Oleg Drokin; Lustre Development List Subject: Re: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second > > Neil, > > > > Does your statement imply this would spin? It definitely doesn’t just > > spin (that behavior in a main “wait for work” spot of a (depending on > > settings) ~per-CPU daemon would render systems unusable and this patch > > has been in testing for a while). So what is the detailed behavior of > > a “timeout that expires immediately”? > > Hi Patrick, > it definitely spins for me. Ah that is where the high cpu load is coming from. > I should have clarified that the SFS patch > > e81847bd0651 LU-9660 ptlrpc: do not wakeup every second > > is correct, as __l_wait_event() treats a timeout value of 0 as meaning an > indefinite timeout. > The error was in the conversion to wait_event_idle_timeout(). The > various wait_event*timeout() functions treat 0 as 1 less than 1. > If you want to not have a timeout, you need to not use the *_timeout() > version. > If a timeout is undesirable rather than fatal, then > MAX_SCHEDULE_TIMEOUT can be used. In this case, that seemed best. I missed that in the conversion. Now that I know that the mapping I will do the future server code port correctly ;-) > > - Patrick > > > > > > ________________________________ > > From: lustre-devel on behalf of NeilBrown > > Sent: Sunday, October 28, 2018 7:03:02 PM > > To: James Simmons; Andreas Dilger; Oleg Drokin > > Cc: Lustre Development List > > Subject: Re: [lustre-devel] [PATCH 12/28] lustre: ptlrpc: do not wakeup every second > > > > On Sun, Oct 14 2018, James Simmons wrote: > > > >> From: Alex Zhuravlev > >> > >> Even if there are no RPC requests on the set, there is no need to > >> wake up every second. The thread is woken up when a request is added > >> to the set or when the STOP bit is set, so it is sufficient to only > >> wake up when there are requests on the set to worry about. > >> > >> Signed-off-by: Alex Zhuravlev > >> WC-bug-id: https://jira.whamcloud.com/browse/LU-9660 > >> Reviewed-on: https://review.whamcloud.com/28776 > >> Reviewed-by: Andreas Dilger > >> Reviewed-by: Patrick Farrell > >> Reviewed-by: Oleg Drokin > >> Signed-off-by: James Simmons > >> --- > >> drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c | 4 ++-- > >> 1 file changed, 2 insertions(+), 2 deletions(-) > >> > >> diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> index c201a88..5b4977b 100644 > >> --- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> +++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c > >> @@ -371,7 +371,7 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc) > >> } > >> } > >> > >> - return rc; > >> + return rc || test_bit(LIOD_STOP, &pc->pc_flags); > >> } > >> > >> /** > >> @@ -441,7 +441,7 @@ static int ptlrpcd(void *arg) > >> lu_context_enter(env.le_ses); > >> if (wait_event_idle_timeout(set->set_waitq, > >> ptlrpcd_check(&env, pc), > >> - (timeout ? timeout : 1) * HZ) == 0) > >> + timeout * HZ) == 0) > >> ptlrpc_expired_set(set); > > > > This is incorrect. > > A timeout of zero means the timeout happens after zero jiffies > > (immediately), it doesn't mean there is no timeout. > > If we want a "timeout" of zero to mean "Wait forever", we need something > > like: > > > > wait_event_idle_timeout(....., > > timeout ? (timeout * HZ) : MAX_SCHEDULE_TIMEOUT) == 0 > > > > I've updated the patch accordingly. > > > > Thanks, > > NeilBrown > > > >> > >> lu_context_exit(&env.le_ctx); > >> -- > >> 1.8.3.1 > -------------- next part -------------- An HTML attachment was scrubbed... URL: From jsimmons at infradead.org Mon Oct 29 15:18:14 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 15:18:14 +0000 (GMT) Subject: [lustre-devel] Using loff_t or u64 for PFL port In-Reply-To: <8C539D08-D7F6-4B17-8A8D-01FEFF03BD2E@whamcloud.com> References: <8C539D08-D7F6-4B17-8A8D-01FEFF03BD2E@whamcloud.com> Message-ID: > On Oct 28, 2018, at 21:49, James Simmons wrote: > > > > > > While doing the PFL port I noticed a inconsistent use of loff_t and u64. > > While in Greg's branch several patches landed to make the prototypes > > match the function with changing any unmatching loff_t/u64 to use u64. > > I don't know if using u64 solely as the proper solution. What is the > > proper unit to use? > > James, could you please clarify what part of the code you are referencing? I see where the divergence happened. The linux client commit 21aef7d9d6544 (staging/lustre: get rid of obd_* typedefs) Changed the old obd_off to u64 while in the OpenSFS branch some were changed to loff_t. A good example is int lov_stripe_offset(struct lov_stripe_md *lsm, int index, loff_t lov_off, int stripeno, loff_t *obd_off); For upstream client its: int lov_stripe_offset(struct lov_stripe_md *lsm, u64 lov_off, int stripeno, u64 *u64); The big difference between the two is that loff_t can be a negative value. I can compile a list of the difference so an audit cna be done. Then we can go over what should be loff_t and what should be u64. From jsimmons at infradead.org Mon Oct 29 17:06:11 2018 From: jsimmons at infradead.org (James Simmons) Date: Mon, 29 Oct 2018 17:06:11 +0000 (GMT) Subject: [lustre-devel] Limitations of kernel read ahead Message-ID: Currently the lustre client has its own read ahead handling in the CLIO layer. The reason for this is due to some limitations in the read ahead code for the linux kernel. Some work to use the kernel's read ahead was attempted for the LU-8964 work but the general work for LU-8964 had other issues. Alternative work to LU-8964 has emerged under ticket https://jira.whamcloud.com/browse/LU-8709 with early code at: https://review.whamcloud.com/#/c/23552 Also I have included a link to a presentation of this work and it gives insight on how lustre does its own read ahead. https://www.eofs.eu/_media/events/lad16/19_parallel_readahead_framework_li_xi.pdf Now that this seems to be the targeted work for read ahead the discussion has come up about why this new work doesn't use the kernel read ahead again. I wasn't involved in the discussion about the limitations but I have included the people interested in this work so progress can be done to imporve the linux kernels version of read ahead. From neilb at suse.com Tue Oct 30 06:41:08 2018 From: neilb at suse.com (NeilBrown) Date: Tue, 30 Oct 2018 17:41:08 +1100 Subject: [lustre-devel] [PATCH 18/28] lustre: mdc: expose changelog through char devices In-Reply-To: <1539543498-29105-19-git-send-email-jsimmons@infradead.org> References: <1539543498-29105-1-git-send-email-jsimmons@infradead.org> <1539543498-29105-19-git-send-email-jsimmons@infradead.org> Message-ID: <87efc82ayj.fsf@notabene.neil.brown.name> On Sun, Oct 14 2018, James Simmons wrote: > From: Henri Doreau > > Register one character device per MDT in order to allow non-llapi to > read them and to make delivery more efficient. > > - open() spawns a thread to prefetch records and enqueue them into a > local buffer (unless the device is open in write-only mode). > - lseek() can be used to jump to a specific record, in which case the > offset is a record number (with SEEK_SET) or a number of records to > skip (SEEK_CUR). Movement can only be done forward. > - read() copies records to userland. No truncation happens, so short > reads are likely. > - write() is used to transmit control commands to the device. > The only available one is changelog_clear, which is done by writing > "clear:cl:" into the device. > - close() terminates the prefetch thread if any, and releases resources. > > It is possible to poll() on the device to get notified when new records > are available for read. > > Signed-off-by: Henri Doreau > WC-bug-id: https://jira.whamcloud.com/browse/LU-7659 > Reviewed-on: https://review.whamcloud.com/18900 > Reviewed-by: Andreas Dilger > Reviewed-by: John L. Hammond > Reviewed-by: Oleg Drokin > Signed-off-by: James Simmons This patches causes problems around sanity test 161a. If you run -only '160h 160i 161a' it hangs. Adding Commit: 89e52326b5bd ("LU-10166 mdc: invalid free in changelog reader") seems to fix the problem, so I'll port that into the series immediately after this patch. NeilBrown > --- > .../include/uapi/linux/lustre/lustre_ioctl.h | 2 +- > .../include/uapi/linux/lustre/lustre_kernelcomm.h | 3 - > .../lustre/include/uapi/linux/lustre/lustre_user.h | 7 - > drivers/staging/lustre/lustre/include/obd.h | 2 + > drivers/staging/lustre/lustre/ldlm/ldlm_lib.c | 2 + > drivers/staging/lustre/lustre/llite/dir.c | 8 - > drivers/staging/lustre/lustre/lmv/lmv_obd.c | 13 - > drivers/staging/lustre/lustre/mdc/Makefile | 2 +- > drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 722 +++++++++++++++++++++ > drivers/staging/lustre/lustre/mdc/mdc_internal.h | 4 + > drivers/staging/lustre/lustre/mdc/mdc_request.c | 198 +----- > 11 files changed, 745 insertions(+), 218 deletions(-) > create mode 100644 drivers/staging/lustre/lustre/mdc/mdc_changelog.c > > diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h > index 6e4e109..098b6451 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h > +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_ioctl.h > @@ -172,7 +172,7 @@ static inline __u32 obd_ioctl_packlen(struct obd_ioctl_data *data) > #define OBD_GET_VERSION _IOWR('f', 144, OBD_IOC_DATA_TYPE) > /* OBD_IOC_GSS_SUPPORT _IOWR('f', 145, OBD_IOC_DATA_TYPE) */ > /* OBD_IOC_CLOSE_UUID _IOWR('f', 147, OBD_IOC_DATA_TYPE) */ > -#define OBD_IOC_CHANGELOG_SEND _IOW('f', 148, OBD_IOC_DATA_TYPE) > +/* OBD_IOC_CHANGELOG_SEND _IOW('f', 148, OBD_IOC_DATA_TYPE) */ > #define OBD_IOC_GETDEVICE _IOWR('f', 149, OBD_IOC_DATA_TYPE) > #define OBD_IOC_FID2PATH _IOWR('f', 150, OBD_IOC_DATA_TYPE) > /* lustre/lustre_user.h 151-153 */ > diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h > index 94dadbe..d84a8fc 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h > +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_kernelcomm.h > @@ -54,15 +54,12 @@ struct kuc_hdr { > __u16 kuc_msglen; > } __aligned(sizeof(__u64)); > > -#define KUC_CHANGELOG_MSG_MAXSIZE (sizeof(struct kuc_hdr) + CR_MAXSIZE) > - > #define KUC_MAGIC 0x191C /*Lustre9etLinC */ > > /* kuc_msgtype values are defined in each transport */ > enum kuc_transport_type { > KUC_TRANSPORT_GENERIC = 1, > KUC_TRANSPORT_HSM = 2, > - KUC_TRANSPORT_CHANGELOG = 3, > }; > > enum kuc_generic_message_type { > diff --git a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h > index b8525e5..715f1c5 100644 > --- a/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h > +++ b/drivers/staging/lustre/include/uapi/linux/lustre/lustre_user.h > @@ -967,13 +967,6 @@ static inline void changelog_remap_rec(struct changelog_rec *rec, > rec->cr_flags = (rec->cr_flags & CLF_FLAGMASK) | crf_wanted; > } > > -struct ioc_changelog { > - __u64 icc_recno; > - __u32 icc_mdtindex; > - __u32 icc_id; > - __u32 icc_flags; > -}; > - > enum changelog_message_type { > CL_RECORD = 10, /* message is a changelog_rec */ > CL_EOF = 11, /* at end of current changelog */ > diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h > index 11e7ae8..76ae0b3 100644 > --- a/drivers/staging/lustre/lustre/include/obd.h > +++ b/drivers/staging/lustre/lustre/include/obd.h > @@ -345,6 +345,8 @@ struct client_obd { > void *cl_lru_work; > /* hash tables for osc_quota_info */ > struct rhashtable cl_quota_hash[MAXQUOTAS]; > + /* Links to the global list of registered changelog devices */ > + struct list_head cl_chg_dev_linkage; > }; > > #define obd2cli_tgt(obd) ((char *)(obd)->u.cli.cl_target_uuid.uuid) > diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c > index 32eda4f..732ef3a 100644 > --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c > +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lib.c > @@ -395,6 +395,8 @@ int client_obd_setup(struct obd_device *obddev, struct lustre_cfg *lcfg) > init_waitqueue_head(&cli->cl_mod_rpcs_waitq); > cli->cl_mod_tag_bitmap = NULL; > > + INIT_LIST_HEAD(&cli->cl_chg_dev_linkage); > + > if (connect_op == MDS_CONNECT) { > cli->cl_max_mod_rpcs_in_flight = cli->cl_max_rpcs_in_flight - 1; > cli->cl_mod_tag_bitmap = kcalloc(BITS_TO_LONGS(OBD_MAX_RIF_MAX), > diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c > index 19c5e9c..36cea8d 100644 > --- a/drivers/staging/lustre/lustre/llite/dir.c > +++ b/drivers/staging/lustre/lustre/llite/dir.c > @@ -1481,14 +1481,6 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg) > return obd_iocontrol(cmd, sbi->ll_md_exp, 0, NULL, > (void __user *)arg); > } > - case OBD_IOC_CHANGELOG_SEND: > - case OBD_IOC_CHANGELOG_CLEAR: > - if (!capable(CAP_SYS_ADMIN)) > - return -EPERM; > - > - rc = copy_and_ioctl(cmd, sbi->ll_md_exp, (void __user *)arg, > - sizeof(struct ioc_changelog)); > - return rc; > case OBD_IOC_FID2PATH: > return ll_fid2path(inode, (void __user *)arg); > case LL_IOC_GETPARENT: > diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c > index 952c68e..32bb9fc 100644 > --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c > +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c > @@ -951,19 +951,6 @@ static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp, > kfree(oqctl); > break; > } > - case OBD_IOC_CHANGELOG_SEND: > - case OBD_IOC_CHANGELOG_CLEAR: { > - struct ioc_changelog *icc = karg; > - > - if (icc->icc_mdtindex >= count) > - return -ENODEV; > - > - tgt = lmv->tgts[icc->icc_mdtindex]; > - if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) > - return -ENODEV; > - rc = obd_iocontrol(cmd, tgt->ltd_exp, sizeof(*icc), icc, NULL); > - break; > - } > case LL_IOC_GET_CONNECT_FLAGS: { > tgt = lmv->tgts[0]; > > diff --git a/drivers/staging/lustre/lustre/mdc/Makefile b/drivers/staging/lustre/lustre/mdc/Makefile > index 64cf49e..5f48e91 100644 > --- a/drivers/staging/lustre/lustre/mdc/Makefile > +++ b/drivers/staging/lustre/lustre/mdc/Makefile > @@ -2,4 +2,4 @@ ccflags-y += -I$(srctree)/drivers/staging/lustre/include > ccflags-y += -I$(srctree)/drivers/staging/lustre/lustre/include > > obj-$(CONFIG_LUSTRE_FS) += mdc.o > -mdc-y := mdc_request.o mdc_reint.o mdc_lib.o mdc_locks.o lproc_mdc.o > +mdc-y := mdc_changelog.o mdc_request.o mdc_reint.o mdc_lib.o mdc_locks.o lproc_mdc.o > diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c > new file mode 100644 > index 0000000..a5f3c64 > --- /dev/null > +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c > @@ -0,0 +1,722 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * GPL HEADER START > + * > + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 only, > + * as published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but > + * WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * General Public License version 2 for more details (a copy is included > + * in the LICENSE file that accompanied this code). > + * > + * You should have received a copy of the GNU General Public License > + * version 2 along with this program; If not, see > + * http://www.gnu.org/licenses/gpl-2.0.html > + * > + * GPL HEADER END > + */ > +/* > + * Copyright (c) 2017, Commissariat a l'Energie Atomique et aux Energies > + * Alternatives. > + * > + * Author: Henri Doreau > + */ > + > +#define DEBUG_SUBSYSTEM S_MDC > + > +#include > +#include > +#include > +#include > + > +#include > + > +#include "mdc_internal.h" > + > +/* > + * -- Changelog delivery through character device -- > + */ > + > +/** > + * Mutex to protect chlg_registered_devices below > + */ > +static DEFINE_MUTEX(chlg_registered_dev_lock); > + > +/** > + * Global linked list of all registered devices (one per MDT). > + */ > +static LIST_HEAD(chlg_registered_devices); > + > +struct chlg_registered_dev { > + /* Device name of the form "changelog-{MDTNAME}" */ > + char ced_name[32]; > + /* Misc device descriptor */ > + struct miscdevice ced_misc; > + /* OBDs referencing this device (multiple mount point) */ > + struct list_head ced_obds; > + /* Reference counter for proper deregistration */ > + struct kref ced_refs; > + /* Link within the global chlg_registered_devices */ > + struct list_head ced_link; > +}; > + > +struct chlg_reader_state { > + /* Shortcut to the corresponding OBD device */ > + struct obd_device *crs_obd; > + /* An error occurred that prevents from reading further */ > + bool crs_err; > + /* EOF, no more records available */ > + bool crs_eof; > + /* Userland reader closed connection */ > + bool crs_closed; > + /* Desired start position */ > + u64 crs_start_offset; > + /* Wait queue for the catalog processing thread */ > + wait_queue_head_t crs_waitq_prod; > + /* Wait queue for the record copy threads */ > + wait_queue_head_t crs_waitq_cons; > + /* Mutex protecting crs_rec_count and crs_rec_queue */ > + struct mutex crs_lock; > + /* Number of item in the list */ > + u64 crs_rec_count; > + /* List of prefetched enqueued_record::enq_linkage_items */ > + struct list_head crs_rec_queue; > +}; > + > +struct chlg_rec_entry { > + /* Link within the chlg_reader_state::crs_rec_queue list */ > + struct list_head enq_linkage; > + /* Data (enq_record) field length */ > + u64 enq_length; > + /* Copy of a changelog record (see struct llog_changelog_rec) */ > + struct changelog_rec enq_record[]; > +}; > + > +enum { > + /* Number of records to prefetch locally. */ > + CDEV_CHLG_MAX_PREFETCH = 1024, > +}; > + > +/** > + * ChangeLog catalog processing callback invoked on each record. > + * If the current record is eligible to userland delivery, push > + * it into the crs_rec_queue where the consumer code will fetch it. > + * > + * @param[in] env (unused) > + * @param[in] llh Client-side handle used to identify the llog > + * @param[in] hdr Header of the current llog record > + * @param[in,out] data chlg_reader_state passed from caller > + * > + * @return 0 or LLOG_PROC_* control code on success, negated error on failure. > + */ > +static int chlg_read_cat_process_cb(const struct lu_env *env, > + struct llog_handle *llh, > + struct llog_rec_hdr *hdr, void *data) > +{ > + struct llog_changelog_rec *rec; > + struct chlg_reader_state *crs = data; > + struct chlg_rec_entry *enq; > + size_t len; > + int rc; > + > + LASSERT(crs); > + LASSERT(hdr); > + > + rec = container_of(hdr, struct llog_changelog_rec, cr_hdr); > + > + if (rec->cr_hdr.lrh_type != CHANGELOG_REC) { > + rc = -EINVAL; > + CERROR("%s: not a changelog rec %x/%d in llog : rc = %d\n", > + crs->crs_obd->obd_name, rec->cr_hdr.lrh_type, > + rec->cr.cr_type, rc); > + return rc; > + } > + > + /* Skip undesired records */ > + if (rec->cr.cr_index < crs->crs_start_offset) > + return 0; > + > + CDEBUG(D_HSM, "%llu %02d%-5s %llu 0x%x t=" DFID " p=" DFID " %.*s\n", > + rec->cr.cr_index, rec->cr.cr_type, > + changelog_type2str(rec->cr.cr_type), rec->cr.cr_time, > + rec->cr.cr_flags & CLF_FLAGMASK, > + PFID(&rec->cr.cr_tfid), PFID(&rec->cr.cr_pfid), > + rec->cr.cr_namelen, changelog_rec_name(&rec->cr)); > + > + wait_event_idle(crs->crs_waitq_prod, > + (crs->crs_rec_count < CDEV_CHLG_MAX_PREFETCH || > + crs->crs_closed)); > + > + if (crs->crs_closed) > + return LLOG_PROC_BREAK; > + > + len = changelog_rec_size(&rec->cr) + rec->cr.cr_namelen; > + enq = kzalloc(sizeof(*enq) + len, GFP_KERNEL); > + if (!enq) > + return -ENOMEM; > + > + INIT_LIST_HEAD(&enq->enq_linkage); > + enq->enq_length = len; > + memcpy(enq->enq_record, &rec->cr, len); > + > + mutex_lock(&crs->crs_lock); > + list_add_tail(&enq->enq_linkage, &crs->crs_rec_queue); > + crs->crs_rec_count++; > + mutex_unlock(&crs->crs_lock); > + > + wake_up_all(&crs->crs_waitq_cons); > + > + return 0; > +} > + > +/** > + * Remove record from the list it is attached to and free it. > + */ > +static void enq_record_delete(struct chlg_rec_entry *rec) > +{ > + list_del(&rec->enq_linkage); > + kfree(rec); > +} > + > +/** > + * Release resources associated to a changelog_reader_state instance. > + * > + * @param crs CRS instance to release. > + */ > +static void crs_free(struct chlg_reader_state *crs) > +{ > + struct chlg_rec_entry *rec; > + struct chlg_rec_entry *tmp; > + > + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) > + enq_record_delete(rec); > + > + kfree(crs); > +} > + > +/** > + * Record prefetch thread entry point. Opens the changelog catalog and starts > + * reading records. > + * > + * @param[in,out] args chlg_reader_state passed from caller. > + * @return 0 on success, negated error code on failure. > + */ > +static int chlg_load(void *args) > +{ > + struct chlg_reader_state *crs = args; > + struct obd_device *obd = crs->crs_obd; > + struct llog_ctxt *ctx = NULL; > + struct llog_handle *llh = NULL; > + int rc; > + > + ctx = llog_get_context(obd, LLOG_CHANGELOG_REPL_CTXT); > + if (!ctx) { > + rc = -ENOENT; > + goto err_out; > + } > + > + rc = llog_open(NULL, ctx, &llh, NULL, CHANGELOG_CATALOG, > + LLOG_OPEN_EXISTS); > + if (rc) { > + CERROR("%s: fail to open changelog catalog: rc = %d\n", > + obd->obd_name, rc); > + goto err_out; > + } > + > + rc = llog_init_handle(NULL, llh, LLOG_F_IS_CAT | LLOG_F_EXT_JOBID, > + NULL); > + if (rc) { > + CERROR("%s: fail to init llog handle: rc = %d\n", > + obd->obd_name, rc); > + goto err_out; > + } > + > + rc = llog_cat_process(NULL, llh, chlg_read_cat_process_cb, crs, 0, 0); > + if (rc < 0) { > + CERROR("%s: fail to process llog: rc = %d\n", > + obd->obd_name, rc); > + goto err_out; > + } > + > +err_out: > + crs->crs_err = true; > + wake_up_all(&crs->crs_waitq_cons); > + > + if (llh) > + llog_cat_close(NULL, llh); > + > + if (ctx) > + llog_ctxt_put(ctx); > + > + wait_event_idle(crs->crs_waitq_prod, crs->crs_closed); > + crs_free(crs); > + return rc; > +} > + > +/** > + * Read handler, dequeues records from the chlg_reader_state if any. > + * No partial records are copied to userland so this function can return less > + * data than required (short read). > + * > + * @param[in] file File pointer to the character device. > + * @param[out] buff Userland buffer where to copy the records. > + * @param[in] count Userland buffer size. > + * @param[out] ppos File position, updated with the index number of the next > + * record to read. > + * @return number of copied bytes on success, negated error code on failure. > + */ > +static ssize_t chlg_read(struct file *file, char __user *buff, size_t count, > + loff_t *ppos) > +{ > + struct chlg_reader_state *crs = file->private_data; > + struct chlg_rec_entry *rec; > + struct chlg_rec_entry *tmp; > + ssize_t written_total = 0; > + LIST_HEAD(consumed); > + > + if (file->f_flags & O_NONBLOCK && crs->crs_rec_count == 0) > + return -EAGAIN; > + > + wait_event_idle(crs->crs_waitq_cons, > + crs->crs_rec_count > 0 || crs->crs_eof || crs->crs_err); > + > + mutex_lock(&crs->crs_lock); > + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) { > + if (written_total + rec->enq_length > count) > + break; > + > + if (copy_to_user(buff, rec->enq_record, rec->enq_length)) { > + if (written_total == 0) > + written_total = -EFAULT; > + break; > + } > + > + buff += rec->enq_length; > + written_total += rec->enq_length; > + > + crs->crs_rec_count--; > + list_move_tail(&rec->enq_linkage, &consumed); > + > + crs->crs_start_offset = rec->enq_record->cr_index + 1; > + } > + mutex_unlock(&crs->crs_lock); > + > + if (written_total > 0) > + wake_up_all(&crs->crs_waitq_prod); > + > + list_for_each_entry_safe(rec, tmp, &consumed, enq_linkage) > + enq_record_delete(rec); > + > + *ppos = crs->crs_start_offset; > + > + return written_total; > +} > + > +/** > + * Jump to a given record index. Helper for chlg_llseek(). > + * > + * @param[in,out] crs Internal reader state. > + * @param[in] offset Desired offset (index record). > + * @return 0 on success, negated error code on failure. > + */ > +static int chlg_set_start_offset(struct chlg_reader_state *crs, u64 offset) > +{ > + struct chlg_rec_entry *rec; > + struct chlg_rec_entry *tmp; > + > + mutex_lock(&crs->crs_lock); > + if (offset < crs->crs_start_offset) { > + mutex_unlock(&crs->crs_lock); > + return -ERANGE; > + } > + > + crs->crs_start_offset = offset; > + list_for_each_entry_safe(rec, tmp, &crs->crs_rec_queue, enq_linkage) { > + struct changelog_rec *cr = rec->enq_record; > + > + if (cr->cr_index >= crs->crs_start_offset) > + break; > + > + crs->crs_rec_count--; > + enq_record_delete(rec); > + } > + > + mutex_unlock(&crs->crs_lock); > + wake_up_all(&crs->crs_waitq_prod); > + return 0; > +} > + > +/** > + * Move read pointer to a certain record index, encoded as an offset. > + * > + * @param[in,out] file File pointer to the changelog character device > + * @param[in] off Offset to skip, actually a record index, not byte count > + * @param[in] whence Relative/Absolute interpretation of the offset > + * @return the resulting position on success or negated error code on failure. > + */ > +static loff_t chlg_llseek(struct file *file, loff_t off, int whence) > +{ > + struct chlg_reader_state *crs = file->private_data; > + loff_t pos; > + int rc; > + > + switch (whence) { > + case SEEK_SET: > + pos = off; > + break; > + case SEEK_CUR: > + pos = file->f_pos + off; > + break; > + case SEEK_END: > + default: > + return -EINVAL; > + } > + > + /* We cannot go backward */ > + if (pos < file->f_pos) > + return -EINVAL; > + > + rc = chlg_set_start_offset(crs, pos); > + if (rc != 0) > + return rc; > + > + file->f_pos = pos; > + return pos; > +} > + > +/** > + * Clear record range for a given changelog reader. > + * > + * @param[in] crs Current internal state. > + * @param[in] reader Changelog reader ID (cl1, cl2...) > + * @param[in] record Record index up which to clear > + * @return 0 on success, negated error code on failure. > + */ > +static int chlg_clear(struct chlg_reader_state *crs, u32 reader, u64 record) > +{ > + struct obd_device *obd = crs->crs_obd; > + struct changelog_setinfo cs = { > + .cs_recno = record, > + .cs_id = reader > + }; > + > + return obd_set_info_async(NULL, obd->obd_self_export, > + strlen(KEY_CHANGELOG_CLEAR), > + KEY_CHANGELOG_CLEAR, sizeof(cs), &cs, NULL); > +} > + > +/** Maximum changelog control command size */ > +#define CHLG_CONTROL_CMD_MAX 64 > + > +/** > + * Handle writes() into the changelog character device. Write() can be used > + * to request special control operations. > + * > + * @param[in] file File pointer to the changelog character device > + * @param[in] buff User supplied data (written data) > + * @param[in] count Number of written bytes > + * @param[in] off (unused) > + * @return number of written bytes on success, negated error code on failure. > + */ > +static ssize_t chlg_write(struct file *file, const char __user *buff, > + size_t count, loff_t *off) > +{ > + struct chlg_reader_state *crs = file->private_data; > + char *kbuf; > + u64 record; > + u32 reader; > + int rc = 0; > + > + if (count > CHLG_CONTROL_CMD_MAX) > + return -EINVAL; > + > + kbuf = kzalloc(CHLG_CONTROL_CMD_MAX, GFP_KERNEL); > + if (!kbuf) > + return -ENOMEM; > + > + if (copy_from_user(kbuf, buff, count)) { > + rc = -EFAULT; > + goto out_kbuf; > + } > + > + kbuf[CHLG_CONTROL_CMD_MAX - 1] = '\0'; > + > + if (sscanf(kbuf, "clear:cl%u:%llu", &reader, &record) == 2) > + rc = chlg_clear(crs, reader, record); > + else > + rc = -EINVAL; > + > +out_kbuf: > + kfree(kbuf); > + return rc < 0 ? rc : count; > +} > + > +/** > + * Find the OBD device associated to a changelog character device. > + * @param[in] cdev character device instance descriptor > + * @return corresponding OBD device or NULL if none was found. > + */ > +static struct obd_device *chlg_obd_get(dev_t cdev) > +{ > + int minor = MINOR(cdev); > + struct obd_device *obd = NULL; > + struct chlg_registered_dev *curr; > + > + mutex_lock(&chlg_registered_dev_lock); > + list_for_each_entry(curr, &chlg_registered_devices, ced_link) { > + if (curr->ced_misc.minor == minor) { > + /* take the first available OBD device attached */ > + obd = list_first_entry(&curr->ced_obds, > + struct obd_device, > + u.cli.cl_chg_dev_linkage); > + break; > + } > + } > + mutex_unlock(&chlg_registered_dev_lock); > + return obd; > +} > + > +/** > + * Open handler, initialize internal CRS state and spawn prefetch thread if > + * needed. > + * @param[in] inode Inode struct for the open character device. > + * @param[in] file Corresponding file pointer. > + * @return 0 on success, negated error code on failure. > + */ > +static int chlg_open(struct inode *inode, struct file *file) > +{ > + struct chlg_reader_state *crs; > + struct obd_device *obd = chlg_obd_get(inode->i_rdev); > + struct task_struct *task; > + int rc; > + > + if (!obd) > + return -ENODEV; > + > + crs = kzalloc(sizeof(*crs), GFP_KERNEL); > + if (!crs) > + return -ENOMEM; > + > + crs->crs_obd = obd; > + crs->crs_err = false; > + crs->crs_eof = false; > + crs->crs_closed = false; > + > + mutex_init(&crs->crs_lock); > + INIT_LIST_HEAD(&crs->crs_rec_queue); > + init_waitqueue_head(&crs->crs_waitq_prod); > + init_waitqueue_head(&crs->crs_waitq_cons); > + > + if (file->f_mode & FMODE_READ) { > + task = kthread_run(chlg_load, crs, "chlg_load_thread"); > + if (IS_ERR(task)) { > + rc = PTR_ERR(task); > + CERROR("%s: cannot start changelog thread: rc = %d\n", > + obd->obd_name, rc); > + goto err_crs; > + } > + } > + > + file->private_data = crs; > + return 0; > + > +err_crs: > + kfree(crs); > + return rc; > +} > + > +/** > + * Close handler, release resources. > + * > + * @param[in] inode Inode struct for the open character device. > + * @param[in] file Corresponding file pointer. > + * @return 0 on success, negated error code on failure. > + */ > +static int chlg_release(struct inode *inode, struct file *file) > +{ > + struct chlg_reader_state *crs = file->private_data; > + > + if (file->f_mode & FMODE_READ) { > + crs->crs_closed = true; > + wake_up_all(&crs->crs_waitq_prod); > + } else { > + /* No producer thread, release resource ourselves */ > + crs_free(crs); > + } > + return 0; > +} > + > +/** > + * Poll handler, indicates whether the device is readable (new records) and > + * writable (always). > + * > + * @param[in] file Device file pointer. > + * @param[in] wait (opaque) > + * @return combination of the poll status flags. > + */ > +static unsigned int chlg_poll(struct file *file, poll_table *wait) > +{ > + struct chlg_reader_state *crs = file->private_data; > + unsigned int mask = 0; > + > + mutex_lock(&crs->crs_lock); > + poll_wait(file, &crs->crs_waitq_cons, wait); > + if (crs->crs_rec_count > 0) > + mask |= POLLIN | POLLRDNORM; > + if (crs->crs_err) > + mask |= POLLERR; > + if (crs->crs_eof) > + mask |= POLLHUP; > + mutex_unlock(&crs->crs_lock); > + return mask; > +} > + > +static const struct file_operations chlg_fops = { > + .owner = THIS_MODULE, > + .llseek = chlg_llseek, > + .read = chlg_read, > + .write = chlg_write, > + .open = chlg_open, > + .release = chlg_release, > + .poll = chlg_poll, > +}; > + > +/** > + * This uses obd_name of the form: "testfs-MDT0000-mdc-ffff88006501600" > + * and returns a name of the form: "changelog-testfs-MDT0000". > + */ > +static void get_chlg_name(char *name, size_t name_len, struct obd_device *obd) > +{ > + int i; > + > + snprintf(name, name_len, "changelog-%s", obd->obd_name); > + > + /* Find the 2nd '-' from the end and truncate on it */ > + for (i = 0; i < 2; i++) { > + char *p = strrchr(name, '-'); > + > + if (!p) > + return; > + *p = '\0'; > + } > +} > + > +/** > + * Find a changelog character device by name. > + * All devices registered during MDC setup are listed in a global list with > + * their names attached. > + */ > +static struct chlg_registered_dev * > +chlg_registered_dev_find_by_name(const char *name) > +{ > + struct chlg_registered_dev *dit; > + > + list_for_each_entry(dit, &chlg_registered_devices, ced_link) > + if (strcmp(name, dit->ced_name) == 0) > + return dit; > + return NULL; > +} > + > +/** > + * Find chlg_registered_dev structure for a given OBD device. > + * This is bad O(n^2) but for each filesystem: > + * - N is # of MDTs times # of mount points > + * - this only runs at shutdown > + */ > +static struct chlg_registered_dev * > +chlg_registered_dev_find_by_obd(const struct obd_device *obd) > +{ > + struct chlg_registered_dev *dit; > + struct obd_device *oit; > + > + list_for_each_entry(dit, &chlg_registered_devices, ced_link) > + list_for_each_entry(oit, &dit->ced_obds, > + u.cli.cl_chg_dev_linkage) > + if (oit == obd) > + return dit; > + return NULL; > +} > + > +/** > + * Changelog character device initialization. > + * Register a misc character device with a dynamic minor number, under a name > + * of the form: 'changelog-fsname-MDTxxxx'. Reference this OBD device with it. > + * > + * @param[in] obd This MDC obd_device. > + * @return 0 on success, negated error code on failure. > + */ > +int mdc_changelog_cdev_init(struct obd_device *obd) > +{ > + struct chlg_registered_dev *exist; > + struct chlg_registered_dev *entry; > + int rc; > + > + entry = kzalloc(sizeof(*entry), GFP_KERNEL); > + if (!entry) > + return -ENOMEM; > + > + get_chlg_name(entry->ced_name, sizeof(entry->ced_name), obd); > + > + entry->ced_misc.minor = MISC_DYNAMIC_MINOR; > + entry->ced_misc.name = entry->ced_name; > + entry->ced_misc.fops = &chlg_fops; > + > + kref_init(&entry->ced_refs); > + INIT_LIST_HEAD(&entry->ced_obds); > + INIT_LIST_HEAD(&entry->ced_link); > + > + mutex_lock(&chlg_registered_dev_lock); > + exist = chlg_registered_dev_find_by_name(entry->ced_name); > + if (exist) { > + kref_get(&exist->ced_refs); > + list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &exist->ced_obds); > + rc = 0; > + goto out_unlock; > + } > + > + /* Register new character device */ > + rc = misc_register(&entry->ced_misc); > + if (rc != 0) > + goto out_unlock; > + > + list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &entry->ced_obds); > + list_add_tail(&entry->ced_link, &chlg_registered_devices); > + > + entry = NULL; /* prevent it from being freed below */ > + > +out_unlock: > + mutex_unlock(&chlg_registered_dev_lock); > + kfree(entry); > + return rc; > +} > + > +/** > + * Deregister a changelog character device whose refcount has reached zero. > + */ > +static void chlg_dev_clear(struct kref *kref) > +{ > + struct chlg_registered_dev *entry = container_of(kref, > + struct chlg_registered_dev, > + ced_refs); > + list_del(&entry->ced_link); > + misc_deregister(&entry->ced_misc); > + kfree(entry); > +} > + > +/** > + * Release OBD, decrease reference count of the corresponding changelog device. > + */ > +void mdc_changelog_cdev_finish(struct obd_device *obd) > +{ > + struct chlg_registered_dev *dev = chlg_registered_dev_find_by_obd(obd); > + > + mutex_lock(&chlg_registered_dev_lock); > + list_del_init(&obd->u.cli.cl_chg_dev_linkage); > + kref_put(&dev->ced_refs, chlg_dev_clear); > + mutex_unlock(&chlg_registered_dev_lock); > +} > diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h > index 941a896..6da9046 100644 > --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h > +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h > @@ -129,6 +129,10 @@ enum ldlm_mode mdc_lock_match(struct obd_export *exp, __u64 flags, > enum ldlm_mode mode, > struct lustre_handle *lockh); > > +int mdc_changelog_cdev_init(struct obd_device *obd); > + > +void mdc_changelog_cdev_finish(struct obd_device *obd); > + > static inline int mdc_prep_elc_req(struct obd_export *exp, > struct ptlrpc_request *req, int opc, > struct list_head *cancels, int count) > diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c > index 8f8e3d2..3692b1c 100644 > --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c > +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c > @@ -35,7 +35,6 @@ > > # include > # include > -# include > # include > # include > # include > @@ -1810,174 +1809,6 @@ static int mdc_ioc_hsm_request(struct obd_export *exp, > return rc; > } > > -static struct kuc_hdr *changelog_kuc_hdr(char *buf, size_t len, u32 flags) > -{ > - struct kuc_hdr *lh = (struct kuc_hdr *)buf; > - > - LASSERT(len <= KUC_CHANGELOG_MSG_MAXSIZE); > - > - lh->kuc_magic = KUC_MAGIC; > - lh->kuc_transport = KUC_TRANSPORT_CHANGELOG; > - lh->kuc_flags = flags; > - lh->kuc_msgtype = CL_RECORD; > - lh->kuc_msglen = len; > - return lh; > -} > - > -struct changelog_show { > - __u64 cs_startrec; > - enum changelog_send_flag cs_flags; > - struct file *cs_fp; > - char *cs_buf; > - struct obd_device *cs_obd; > -}; > - > -static inline char *cs_obd_name(struct changelog_show *cs) > -{ > - return cs->cs_obd->obd_name; > -} > - > -static int changelog_kkuc_cb(const struct lu_env *env, struct llog_handle *llh, > - struct llog_rec_hdr *hdr, void *data) > -{ > - struct changelog_show *cs = data; > - struct llog_changelog_rec *rec = (struct llog_changelog_rec *)hdr; > - struct kuc_hdr *lh; > - size_t len; > - int rc; > - > - if (rec->cr_hdr.lrh_type != CHANGELOG_REC) { > - rc = -EINVAL; > - CERROR("%s: not a changelog rec %x/%d: rc = %d\n", > - cs_obd_name(cs), rec->cr_hdr.lrh_type, > - rec->cr.cr_type, rc); > - return rc; > - } > - > - if (rec->cr.cr_index < cs->cs_startrec) { > - /* Skip entries earlier than what we are interested in */ > - CDEBUG(D_HSM, "rec=%llu start=%llu\n", > - rec->cr.cr_index, cs->cs_startrec); > - return 0; > - } > - > - CDEBUG(D_HSM, "%llu %02d%-5s %llu 0x%x t=" DFID " p=" DFID > - " %.*s\n", rec->cr.cr_index, rec->cr.cr_type, > - changelog_type2str(rec->cr.cr_type), rec->cr.cr_time, > - rec->cr.cr_flags & CLF_FLAGMASK, > - PFID(&rec->cr.cr_tfid), PFID(&rec->cr.cr_pfid), > - rec->cr.cr_namelen, changelog_rec_name(&rec->cr)); > - > - len = sizeof(*lh) + changelog_rec_size(&rec->cr) + rec->cr.cr_namelen; > - > - /* Set up the message */ > - lh = changelog_kuc_hdr(cs->cs_buf, len, cs->cs_flags); > - memcpy(lh + 1, &rec->cr, len - sizeof(*lh)); > - > - rc = libcfs_kkuc_msg_put(cs->cs_fp, lh); > - CDEBUG(D_HSM, "kucmsg fp %p len %zu rc %d\n", cs->cs_fp, len, rc); > - > - return rc; > -} > - > -static int mdc_changelog_send_thread(void *csdata) > -{ > - enum llog_flag flags = LLOG_F_IS_CAT; > - struct changelog_show *cs = csdata; > - struct llog_ctxt *ctxt = NULL; > - struct llog_handle *llh = NULL; > - struct kuc_hdr *kuch; > - int rc; > - > - CDEBUG(D_HSM, "changelog to fp=%p start %llu\n", > - cs->cs_fp, cs->cs_startrec); > - > - cs->cs_buf = kzalloc(KUC_CHANGELOG_MSG_MAXSIZE, GFP_NOFS); > - if (!cs->cs_buf) { > - rc = -ENOMEM; > - goto out; > - } > - > - /* Set up the remote catalog handle */ > - ctxt = llog_get_context(cs->cs_obd, LLOG_CHANGELOG_REPL_CTXT); > - if (!ctxt) { > - rc = -ENOENT; > - goto out; > - } > - rc = llog_open(NULL, ctxt, &llh, NULL, CHANGELOG_CATALOG, > - LLOG_OPEN_EXISTS); > - if (rc) { > - CERROR("%s: fail to open changelog catalog: rc = %d\n", > - cs_obd_name(cs), rc); > - goto out; > - } > - > - if (cs->cs_flags & CHANGELOG_FLAG_JOBID) > - flags |= LLOG_F_EXT_JOBID; > - > - rc = llog_init_handle(NULL, llh, flags, NULL); > - if (rc) { > - CERROR("llog_init_handle failed %d\n", rc); > - goto out; > - } > - > - rc = llog_cat_process(NULL, llh, changelog_kkuc_cb, cs, 0, 0); > - > - /* Send EOF no matter what our result */ > - kuch = changelog_kuc_hdr(cs->cs_buf, sizeof(*kuch), cs->cs_flags); > - kuch->kuc_msgtype = CL_EOF; > - libcfs_kkuc_msg_put(cs->cs_fp, kuch); > - > -out: > - fput(cs->cs_fp); > - if (llh) > - llog_cat_close(NULL, llh); > - if (ctxt) > - llog_ctxt_put(ctxt); > - kfree(cs->cs_buf); > - kfree(cs); > - return rc; > -} > - > -static int mdc_ioc_changelog_send(struct obd_device *obd, > - struct ioc_changelog *icc) > -{ > - struct changelog_show *cs; > - struct task_struct *task; > - int rc; > - > - /* Freed in mdc_changelog_send_thread */ > - cs = kzalloc(sizeof(*cs), GFP_NOFS); > - if (!cs) > - return -ENOMEM; > - > - cs->cs_obd = obd; > - cs->cs_startrec = icc->icc_recno; > - /* matching fput in mdc_changelog_send_thread */ > - cs->cs_fp = fget(icc->icc_id); > - cs->cs_flags = icc->icc_flags; > - > - /* > - * New thread because we should return to user app before > - * writing into our pipe > - */ > - task = kthread_run(mdc_changelog_send_thread, cs, > - "mdc_clg_send_thread"); > - if (IS_ERR(task)) { > - rc = PTR_ERR(task); > - CERROR("%s: can't start changelog thread: rc = %d\n", > - cs_obd_name(cs), rc); > - kfree(cs); > - } else { > - rc = 0; > - CDEBUG(D_HSM, "%s: started changelog thread\n", > - cs_obd_name(cs)); > - } > - > - CERROR("Failed to start changelog thread: %d\n", rc); > - return rc; > -} > - > static int mdc_ioc_hsm_ct_start(struct obd_export *exp, > struct lustre_kernelcomm *lk); > > @@ -2087,21 +1918,6 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len, > return -EINVAL; > } > switch (cmd) { > - case OBD_IOC_CHANGELOG_SEND: > - rc = mdc_ioc_changelog_send(obd, karg); > - goto out; > - case OBD_IOC_CHANGELOG_CLEAR: { > - struct ioc_changelog *icc = karg; > - struct changelog_setinfo cs = { > - .cs_recno = icc->icc_recno, > - .cs_id = icc->icc_id > - }; > - > - rc = obd_set_info_async(NULL, exp, strlen(KEY_CHANGELOG_CLEAR), > - KEY_CHANGELOG_CLEAR, sizeof(cs), &cs, > - NULL); > - goto out; > - } > case OBD_IOC_FID2PATH: > rc = mdc_ioc_fid2path(exp, karg); > goto out; > @@ -2670,12 +2486,22 @@ static int mdc_setup(struct obd_device *obd, struct lustre_cfg *cfg) > > rc = mdc_llog_init(obd); > if (rc) { > - CERROR("failed to setup llogging subsystems\n"); > + CERROR("%s: failed to setup llogging subsystems: rc = %d\n", > + obd->obd_name, rc); > goto err_llog_cleanup; > } > > + rc = mdc_changelog_cdev_init(obd); > + if (rc) { > + CERROR("%s: failed to setup changelog char device: rc = %d\n", > + obd->obd_name, rc); > + goto err_changelog_cleanup; > + } > + > return 0; > > +err_changelog_cleanup: > + mdc_llog_finish(obd); > err_llog_cleanup: > ldebugfs_free_md_stats(obd); > ptlrpc_lprocfs_unregister_obd(obd); > @@ -2714,6 +2540,8 @@ static int mdc_precleanup(struct obd_device *obd) > if (obd->obd_type->typ_refcnt <= 1) > libcfs_kkuc_group_rem(0, KUC_GRP_HSM); > > + mdc_changelog_cdev_finish(obd); > + > obd_cleanup_client_import(obd); > ptlrpc_lprocfs_unregister_obd(obd); > lprocfs_obd_cleanup(obd); > -- > 1.8.3.1 -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From adilger at whamcloud.com Tue Oct 30 07:16:45 2018 From: adilger at whamcloud.com (Andreas Dilger) Date: Tue, 30 Oct 2018 07:16:45 +0000 Subject: [lustre-devel] Limitations of kernel read ahead In-Reply-To: <62D5855B-8FE1-4157-858C-01B182D759AD@ddn.com> References: <62D5855B-8FE1-4157-858C-01B182D759AD@ddn.com> Message-ID: One other enhancement that would be good to make for the readahead is to add opportunistic readahead for random access of smaller files (as determined by file size and client RAM) as discussed in LU-11416. This has shown significant improvement for random access (about 40x speedup when doing random read IOPS on a 1GB file). On Oct 29, 2018, at 20:00, Li Xi wrote: > > Thank you for summarize this, James! > > I think everyone agrees that the current readahead algorithm of Lustre needs to be improved. And evidences show that the readahead algorithm of Linux kernel would not suitable for Lustre either. There are several reasons for this. In general, the readahead algorithm of kernel is designed for local file system with small readahead window. It is single thread, synchronous readahead, only usable for sequential read. Because the read operation of Lustre is has longer latency than local file system, while its bandwidth is typically higher than local file system, we need totally different algorithm for Lustre readahead. The readahead algorithm needs to be 1) asynchronous to hide latency for application 2) multiple threaded to utilize the high bandwidth 3) use big readahead window to align with the big RPC size 4) work for sequential read, stride read and potentially small & random read. > > The work of LU-8709 was started with these targets and got pretty good numbers even without detailed tuning. We (the Whamcloud team) would like to rework on it with a goal of merging it in the next releases of Lustre. > > Regards, > Li Xi > > 在 2018/10/30 上午2:06,“James Simmons” 写入: >> >> >> Currently the lustre client has its own read ahead handling in the CLIO >> layer. The reason for this is due to some limitations in the read ahead >> code for the linux kernel. Some work to use the kernel's read ahead was >> attempted for the LU-8964 work but the general work for LU-8964 had other >> issues. Alternative work to LU-8964 has emerged under ticket >> >> https://jira.whamcloud.com/browse/LU-8709 >> >> with early code at: >> >> https://review.whamcloud.com/#/c/23552 >> >> Also I have included a link to a presentation of this work and it gives >> insight on how lustre does its own read ahead. >> >> https://www.eofs.eu/_media/events/lad16/19_parallel_readahead_framework_li_xi.pdf >> >> Now that this seems to be the targeted work for read ahead the discussion >> has come up about why this new work doesn't use the kernel read ahead >> again. I wasn't involved in the discussion about the limitations but I >> have included the people interested in this work so progress can be done >> to imporve the linux kernels version of read ahead. >> >> Cheers, Andreas --- Andreas Dilger CTO Whamcloud From paf at cray.com Tue Oct 30 14:55:25 2018 From: paf at cray.com (Patrick Farrell) Date: Tue, 30 Oct 2018 14:55:25 +0000 Subject: [lustre-devel] Using loff_t or u64 for PFL port In-Reply-To: References: <8C539D08-D7F6-4B17-8A8D-01FEFF03BD2E@whamcloud.com> Message-ID: <004DC75C-D5DA-4875-B090-AEB23B1AE267@cray.com> This would be good to clean up - A few subtle bugs related to loff_t/u64 usage in interfaces have come up over time (and been addressed each time), but I've never found time to try to clean it all up. - Patrick On 10/29/18, 10:18 AM, "lustre-devel on behalf of James Simmons" wrote: > On Oct 28, 2018, at 21:49, James Simmons wrote: > > > > > > While doing the PFL port I noticed a inconsistent use of loff_t and u64. > > While in Greg's branch several patches landed to make the prototypes > > match the function with changing any unmatching loff_t/u64 to use u64. > > I don't know if using u64 solely as the proper solution. What is the > > proper unit to use? > > James, could you please clarify what part of the code you are referencing? I see where the divergence happened. The linux client commit 21aef7d9d6544 (staging/lustre: get rid of obd_* typedefs) Changed the old obd_off to u64 while in the OpenSFS branch some were changed to loff_t. A good example is int lov_stripe_offset(struct lov_stripe_md *lsm, int index, loff_t lov_off, int stripeno, loff_t *obd_off); For upstream client its: int lov_stripe_offset(struct lov_stripe_md *lsm, u64 lov_off, int stripeno, u64 *u64); The big difference between the two is that loff_t can be a negative value. I can compile a list of the difference so an audit cna be done. Then we can go over what should be loff_t and what should be u64. _______________________________________________ lustre-devel mailing list lustre-devel at lists.lustre.org http://lists.lustre.org/listinfo.cgi/lustre-devel-lustre.org From neilb at suse.com Wed Oct 31 01:29:45 2018 From: neilb at suse.com (NeilBrown) Date: Wed, 31 Oct 2018 12:29:45 +1100 Subject: [lustre-devel] [PATCH] lustre: mdc: fix possible deadlock in chlg_open() Message-ID: <87bm7a3nue.fsf@notabene.neil.brown.name> Lockdep reports a possible deadlock between chlg_open() and mdc_changelog_cdev_init() mdc_changelog_cdev_init() takes chlg_registered_dev_lock and then calls misc_register() which takes misc_mtx. chlg_open() is called while misc_mtx is held, and tries to take chlg_registered_dev_lock. If these two functions race, a deadlock can occur as each thread will hold one of the locks while trying to take the other. chlg_open() does not need to take a lock. It only uses the lock to stablize a list while looking for the matching chlg_registered_dev, and this can be found directly by examining file->private_data. So remove chlg_obd_get(), and use file->private_Data to find the obd_device. Signed-off-by: NeilBrown --- Note that this bug exists in upstream (OpenSFS) lustre as well. drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 35 +++++------------------ 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c index d83507cbf95c..645e7f24a859 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c @@ -444,31 +444,6 @@ static ssize_t chlg_write(struct file *file, const char __user *buff, return rc < 0 ? rc : count; } -/** - * Find the OBD device associated to a changelog character device. - * @param[in] cdev character device instance descriptor - * @return corresponding OBD device or NULL if none was found. - */ -static struct obd_device *chlg_obd_get(dev_t cdev) -{ - int minor = MINOR(cdev); - struct obd_device *obd = NULL; - struct chlg_registered_dev *curr; - - mutex_lock(&chlg_registered_dev_lock); - list_for_each_entry(curr, &chlg_registered_devices, ced_link) { - if (curr->ced_misc.minor == minor) { - /* take the first available OBD device attached */ - obd = list_first_entry(&curr->ced_obds, - struct obd_device, - u.cli.cl_chg_dev_linkage); - break; - } - } - mutex_unlock(&chlg_registered_dev_lock); - return obd; -} - /** * Open handler, initialize internal CRS state and spawn prefetch thread if * needed. @@ -479,12 +454,16 @@ static struct obd_device *chlg_obd_get(dev_t cdev) static int chlg_open(struct inode *inode, struct file *file) { struct chlg_reader_state *crs; - struct obd_device *obd = chlg_obd_get(inode->i_rdev); + struct miscdevice *misc = file->private_data; + struct chlg_registered_dev *dev; + struct obd_device *obd; struct task_struct *task; int rc; - if (!obd) - return -ENODEV; + dev = container_of(misc, struct chlg_registered_dev, ced_misc); + obd = list_first_entry(&dev->ced_obds, + struct obd_device, + u.cli.cl_chg_dev_linkage); crs = kzalloc(sizeof(*crs), GFP_KERNEL); if (!crs) -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From quentin.bouget at cea.fr Wed Oct 31 12:24:28 2018 From: quentin.bouget at cea.fr (quentin.bouget at cea.fr) Date: Wed, 31 Oct 2018 13:24:28 +0100 Subject: [lustre-devel] [PATCH] lustre: mdc: fix possible deadlock in chlg_open() In-Reply-To: <87bm7a3nue.fsf@notabene.neil.brown.name> References: <87bm7a3nue.fsf@notabene.neil.brown.name> Message-ID: <7db27e7d-e685-af8f-80d8-891a0d8db4d5@cea.fr> Le 31/10/2018 à 02:29, NeilBrown a écrit : > Lockdep reports a possible deadlock between chlg_open() and > mdc_changelog_cdev_init() > > mdc_changelog_cdev_init() takes chlg_registered_dev_lock and then > calls misc_register() which takes misc_mtx. > chlg_open() is called while misc_mtx is held, and tries to take > chlg_registered_dev_lock. > If these two functions race, a deadlock can occur as each thread will > hold one of the locks while trying to take the other. > > chlg_open() does not need to take a lock. It only uses the > lock to stablize a list while looking for the matching > chlg_registered_dev, and this can be found directly by examining > file->private_data. > > So remove chlg_obd_get(), and use file->private_Data to find the > obd_device. > > Signed-off-by: NeilBrown > --- > > Note that this bug exists in upstream (OpenSFS) lustre as well. I think you need to modify mdc_changelog_cdev_init() as well so that misc_register() comes after the two list_add_tail() statements. If someone opens the device a bit a too fast after it becomes visible, they might find an empty list at `dev->ced_obds'. Previously, holding `chlg_registered_dev_loc' implicitely prevented that. Is it possible that maybe the kernel shouldn't hold `misc_mtx' while calling chlg_open()? Quentin Bouget > > drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 35 +++++------------------ > 1 file changed, 7 insertions(+), 28 deletions(-) > > diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c > index d83507cbf95c..645e7f24a859 100644 > --- a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c > +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c > @@ -444,31 +444,6 @@ static ssize_t chlg_write(struct file *file, const char __user *buff, > return rc < 0 ? rc : count; > } > > -/** > - * Find the OBD device associated to a changelog character device. > - * @param[in] cdev character device instance descriptor > - * @return corresponding OBD device or NULL if none was found. > - */ > -static struct obd_device *chlg_obd_get(dev_t cdev) > -{ > - int minor = MINOR(cdev); > - struct obd_device *obd = NULL; > - struct chlg_registered_dev *curr; > - > - mutex_lock(&chlg_registered_dev_lock); > - list_for_each_entry(curr, &chlg_registered_devices, ced_link) { > - if (curr->ced_misc.minor == minor) { > - /* take the first available OBD device attached */ > - obd = list_first_entry(&curr->ced_obds, > - struct obd_device, > - u.cli.cl_chg_dev_linkage); > - break; > - } > - } > - mutex_unlock(&chlg_registered_dev_lock); > - return obd; > -} > - > /** > * Open handler, initialize internal CRS state and spawn prefetch thread if > * needed. > @@ -479,12 +454,16 @@ static struct obd_device *chlg_obd_get(dev_t cdev) > static int chlg_open(struct inode *inode, struct file *file) > { > struct chlg_reader_state *crs; > - struct obd_device *obd = chlg_obd_get(inode->i_rdev); > + struct miscdevice *misc = file->private_data; > + struct chlg_registered_dev *dev; > + struct obd_device *obd; > struct task_struct *task; > int rc; > > - if (!obd) > - return -ENODEV; > + dev = container_of(misc, struct chlg_registered_dev, ced_misc); > + obd = list_first_entry(&dev->ced_obds, > + struct obd_device, > + u.cli.cl_chg_dev_linkage); > > crs = kzalloc(sizeof(*crs), GFP_KERNEL); > if (!crs) > > > _______________________________________________ > lustre-devel mailing list > lustre-devel at lists.lustre.org > http://lists.lustre.org/listinfo.cgi/lustre-devel-lustre.org -------------- next part -------------- An HTML attachment was scrubbed... URL: From lixi at ddn.com Tue Oct 30 02:00:21 2018 From: lixi at ddn.com (Li Xi) Date: Tue, 30 Oct 2018 02:00:21 +0000 Subject: [lustre-devel] Limitations of kernel read ahead In-Reply-To: References: Message-ID: <62D5855B-8FE1-4157-858C-01B182D759AD@ddn.com> Thank you for summarize this, James! I think everyone agrees that the current readahead algorithm of Lustre needs to be improved. And evidences show that the readahead algorithm of Linux kernel would not suitable for Lustre either. There are several reasons for this. In general, the readahead algorithm of kernel is designed for local file system with small readahead window. It is single thread, synchronous readahead, only usable for sequential read. Because the read operation of Lustre is has longer latency than local file system, while its bandwidth is typically higher than local file system, we need totally different algorithm for Lustre readahead. The readahead algorithm needs to be 1) asynchronous to hide latency for application 2) multiple threaded to utilize the high bandwidth 3) use big readahead window to align with the big RPC size 4) work for sequential read, stride read and potentially small & random read. The work of LU-8709 was started with these targets and got pretty good numbers even without detailed tuning. We (the Whamcloud team) would like to rework on it with a goal of merging it in the next releases of Lustre. Regards, Li Xi 在 2018/10/30 上午2:06,“James Simmons” 写入: Currently the lustre client has its own read ahead handling in the CLIO layer. The reason for this is due to some limitations in the read ahead code for the linux kernel. Some work to use the kernel's read ahead was attempted for the LU-8964 work but the general work for LU-8964 had other issues. Alternative work to LU-8964 has emerged under ticket https://jira.whamcloud.com/browse/LU-8709 with early code at: https://review.whamcloud.com/#/c/23552 Also I have included a link to a presentation of this work and it gives insight on how lustre does its own read ahead. https://www.eofs.eu/_media/events/lad16/19_parallel_readahead_framework_li_xi.pdf Now that this seems to be the targeted work for read ahead the discussion has come up about why this new work doesn't use the kernel read ahead again. I wasn't involved in the discussion about the limitations but I have included the people interested in this work so progress can be done to imporve the linux kernels version of read ahead. From neilb at suse.com Wed Oct 31 20:56:59 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 01 Nov 2018 07:56:59 +1100 Subject: [lustre-devel] [PATCH] lustre: mdc: fix possible deadlock in chlg_open() In-Reply-To: <7db27e7d-e685-af8f-80d8-891a0d8db4d5@cea.fr> References: <87bm7a3nue.fsf@notabene.neil.brown.name> <7db27e7d-e685-af8f-80d8-891a0d8db4d5@cea.fr> Message-ID: <878t2d3kdg.fsf@notabene.neil.brown.name> On Wed, Oct 31 2018, quentin.bouget at cea.fr wrote: > Le 31/10/2018 à 02:29, NeilBrown a écrit : >> Lockdep reports a possible deadlock between chlg_open() and >> mdc_changelog_cdev_init() >> >> mdc_changelog_cdev_init() takes chlg_registered_dev_lock and then >> calls misc_register() which takes misc_mtx. >> chlg_open() is called while misc_mtx is held, and tries to take >> chlg_registered_dev_lock. >> If these two functions race, a deadlock can occur as each thread will >> hold one of the locks while trying to take the other. >> >> chlg_open() does not need to take a lock. It only uses the >> lock to stablize a list while looking for the matching >> chlg_registered_dev, and this can be found directly by examining >> file->private_data. >> >> So remove chlg_obd_get(), and use file->private_Data to find the >> obd_device. >> >> Signed-off-by: NeilBrown >> --- >> >> Note that this bug exists in upstream (OpenSFS) lustre as well. > I think you need to modify mdc_changelog_cdev_init() as well so that > misc_register() comes after the two list_add_tail() statements. Yes, definitely. Thanks for that. I'll change the patch. > > If someone opens the device a bit a too fast after it becomes visible, > they might find an empty list at `dev->ced_obds'. > Previously, holding `chlg_registered_dev_loc' implicitely prevented that. > > Is it possible that maybe the kernel shouldn't hold `misc_mtx' while > calling chlg_open()? No, it really should. It protects against races between chlg_open and misc_unregister(). Thanks, NeilBrown > > Quentin Bouget >> >> drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 35 +++++------------------ >> 1 file changed, 7 insertions(+), 28 deletions(-) >> >> diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c >> index d83507cbf95c..645e7f24a859 100644 >> --- a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c >> +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c >> @@ -444,31 +444,6 @@ static ssize_t chlg_write(struct file *file, const char __user *buff, >> return rc < 0 ? rc : count; >> } >> >> -/** >> - * Find the OBD device associated to a changelog character device. >> - * @param[in] cdev character device instance descriptor >> - * @return corresponding OBD device or NULL if none was found. >> - */ >> -static struct obd_device *chlg_obd_get(dev_t cdev) >> -{ >> - int minor = MINOR(cdev); >> - struct obd_device *obd = NULL; >> - struct chlg_registered_dev *curr; >> - >> - mutex_lock(&chlg_registered_dev_lock); >> - list_for_each_entry(curr, &chlg_registered_devices, ced_link) { >> - if (curr->ced_misc.minor == minor) { >> - /* take the first available OBD device attached */ >> - obd = list_first_entry(&curr->ced_obds, >> - struct obd_device, >> - u.cli.cl_chg_dev_linkage); >> - break; >> - } >> - } >> - mutex_unlock(&chlg_registered_dev_lock); >> - return obd; >> -} >> - >> /** >> * Open handler, initialize internal CRS state and spawn prefetch thread if >> * needed. >> @@ -479,12 +454,16 @@ static struct obd_device *chlg_obd_get(dev_t cdev) >> static int chlg_open(struct inode *inode, struct file *file) >> { >> struct chlg_reader_state *crs; >> - struct obd_device *obd = chlg_obd_get(inode->i_rdev); >> + struct miscdevice *misc = file->private_data; >> + struct chlg_registered_dev *dev; >> + struct obd_device *obd; >> struct task_struct *task; >> int rc; >> >> - if (!obd) >> - return -ENODEV; >> + dev = container_of(misc, struct chlg_registered_dev, ced_misc); >> + obd = list_first_entry(&dev->ced_obds, >> + struct obd_device, >> + u.cli.cl_chg_dev_linkage); >> >> crs = kzalloc(sizeof(*crs), GFP_KERNEL); >> if (!crs) >> >> >> _______________________________________________ >> lustre-devel mailing list >> lustre-devel at lists.lustre.org >> http://lists.lustre.org/listinfo.cgi/lustre-devel-lustre.org -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: From neilb at suse.com Wed Oct 31 23:01:33 2018 From: neilb at suse.com (NeilBrown) Date: Thu, 01 Nov 2018 10:01:33 +1100 Subject: [lustre-devel] [PATCH v2] lustre: mdc: fix possible deadlock in chlg_open() In-Reply-To: <7db27e7d-e685-af8f-80d8-891a0d8db4d5@cea.fr> References: <87bm7a3nue.fsf@notabene.neil.brown.name> <7db27e7d-e685-af8f-80d8-891a0d8db4d5@cea.fr> Message-ID: <875zxh3elu.fsf@notabene.neil.brown.name> Lockdep reports a possible deadlock between chlg_open() and mdc_changelog_cdev_init() mdc_changelog_cdev_init() takes chlg_registered_dev_lock and then calls misc_register() which takes misc_mtx. chlg_open() is called while misc_mtx is held, and tries to take chlg_registered_dev_lock. If these two functions race, a deadlock can occur as each thread will hold one of the locks while trying to take the other. chlg_open() does not need to take a lock. It only uses the lock to stablize a list while looking for the matching chlg_registered_dev, and this can be found directly by examining file->private_data. So remove chlg_obd_get(), and use file->private_data to find the obd_device. Also ensure the device is fully initialized before calling misc_register(). This means setting up some list linkage before the call, and tearing it down if there is an error. Signed-off-by: NeilBrown --- This is the revised version with the problem identified by Quentin fixed. drivers/staging/lustre/lustre/mdc/mdc_changelog.c | 46 +++++++---------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c index d83507cbf95c..af29ea73c48a 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_changelog.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_changelog.c @@ -444,31 +444,6 @@ static ssize_t chlg_write(struct file *file, const char __user *buff, return rc < 0 ? rc : count; } -/** - * Find the OBD device associated to a changelog character device. - * @param[in] cdev character device instance descriptor - * @return corresponding OBD device or NULL if none was found. - */ -static struct obd_device *chlg_obd_get(dev_t cdev) -{ - int minor = MINOR(cdev); - struct obd_device *obd = NULL; - struct chlg_registered_dev *curr; - - mutex_lock(&chlg_registered_dev_lock); - list_for_each_entry(curr, &chlg_registered_devices, ced_link) { - if (curr->ced_misc.minor == minor) { - /* take the first available OBD device attached */ - obd = list_first_entry(&curr->ced_obds, - struct obd_device, - u.cli.cl_chg_dev_linkage); - break; - } - } - mutex_unlock(&chlg_registered_dev_lock); - return obd; -} - /** * Open handler, initialize internal CRS state and spawn prefetch thread if * needed. @@ -479,12 +454,16 @@ static struct obd_device *chlg_obd_get(dev_t cdev) static int chlg_open(struct inode *inode, struct file *file) { struct chlg_reader_state *crs; - struct obd_device *obd = chlg_obd_get(inode->i_rdev); + struct miscdevice *misc = file->private_data; + struct chlg_registered_dev *dev; + struct obd_device *obd; struct task_struct *task; int rc; - if (!obd) - return -ENODEV; + dev = container_of(misc, struct chlg_registered_dev, ced_misc); + obd = list_first_entry(&dev->ced_obds, + struct obd_device, + u.cli.cl_chg_dev_linkage); crs = kzalloc(sizeof(*crs), GFP_KERNEL); if (!crs) @@ -669,13 +648,16 @@ int mdc_changelog_cdev_init(struct obd_device *obd) goto out_unlock; } + list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &entry->ced_obds); + list_add_tail(&entry->ced_link, &chlg_registered_devices); + /* Register new character device */ rc = misc_register(&entry->ced_misc); - if (rc != 0) + if (rc != 0) { + list_del_init(&obd->u.cli.cl_chg_dev_linkage); + list_del(&entry->ced_link); goto out_unlock; - - list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &entry->ced_obds); - list_add_tail(&entry->ced_link, &chlg_registered_devices); + } entry = NULL; /* prevent it from being freed below */ -- 2.14.0.rc0.dirty -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 832 bytes Desc: not available URL: