Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take a XPRT ref when hooking events #204

Merged
merged 1 commit into from
Apr 6, 2020
Merged

Take a XPRT ref when hooking events #204

merged 1 commit into from
Apr 6, 2020

Conversation

dang
Copy link
Collaborator

@dang dang commented Feb 21, 2020

The epoll loop needs a ref on the XPRT, so that it stays alive while in
epoll(). svc_rqst_rearm_events_locked() takes a ref, but the initial
svc_rqst_hook_events() does not. This means that, if the XPRT times
out, the cleanup will drop a ref, and the epoll loop will drop a ref,
causing one to many refs to be dropped. This leaves the client
potentially with a dangling ref.

Take the ref for the epoll loop when initially hooking the events.

Signed-off-by: Daniel Gryniewicz [email protected]

Copy link

@malahal malahal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will test it out and let you know.

@madhuthorat
Copy link

madhuthorat commented Feb 23, 2020

The fix helped to avoid the crash (avoiding use after free of xprt).
But when we ran cthon tests, they failed as lot of connections to statd remain open. Eventually we run out of FDs and SM_MON requests fail.

In /var/log/messages:
Feb 23 17:03:17 mynode rpc.statd[1545]: Failed to insert: creating /var/lib/nfs/statd/sm/10.0.100.51: Too many open files
Feb 23 17:03:17 mynode rpc.statd[1545]: STAT_FAIL to mynode.in.ibm.com for SM_MON of 10.0.100.51
Feb 23 17:03:17 mynode rpc.statd[1545]: Failed to insert: creating /var/lib/nfs/statd/sm/10.0.100.51: Too many open files
Feb 23 17:03:17 mynode rpc.statd[1545]: STAT_FAIL to mynode.in.ibm.com for SM_MON of 10.0.100.51

Following CRIT logs noticed:
2020-02-23 14:03:33 : epoch 00030945 : mynode : gpfs.ganesha.nfsd-32251[svc_30] nsm_connect :NLM :CRIT :connect to statd failed: RPC: Unknown protocol
2020-02-23 14:03:33 : epoch 00030945 : mynode : gpfs.ganesha.nfsd-32251[svc_30] nsm_monitor_noretry :NLM :CRIT :Monitor 10.0.100.52 nsm_connect failed
2020-02-23 14:03:34 : epoch 00030945 : mynode : gpfs.ganesha.nfsd-32251[svc_87] nsm_monitor_noretry :NLM :CRIT :Monitor 10.0.100.52 SM_MON failed (1)
2020-02-23 14:03:34 : epoch 00030945 : mynode : gpfs.ganesha.nfsd-32251[svc_87] nsm_monitor_noretry :NLM :CRIT :Monitor 10.0.100.52 SM_MON failed (1)

[mynode] # lsof -p $(pidof gpfs.ganesha.nfsd) | wc -l
1969

@dang dang force-pushed the hook branch 2 times, most recently from 3f4d585 to 80572c0 Compare February 28, 2020 19:55
@dang
Copy link
Collaborator Author

dang commented Feb 28, 2020

@malahal Okay, this one seems to work properly. There's still a leak, but I think it's in Ganesha (I think the backchannel clients have a refcount bug). There's an associated Ganesha patch that needs to be merged along with this, or the listening sockets also leak:
dang/nfs-ganesha@55b9340

@malahal
Copy link

malahal commented Mar 1, 2020

I read all documentation I could regarding epoll and threads! Looks like the API itself is broken. The best way to guaranty REF over epoll is taking REF while hooking and re-arming. If we only take REF while hooking and RELEASE while unhooking, unfortunately events CAN happen after unhook. There is no way to prevent execution of event code after unhook. This could lead to accessing freed memory!

The issue with REF/RELEASE while hooking/re-arming and event handing is that the "refcount" count can go to zero only after handing an "event". This seems to be the issue with leaking sockets with rpc.statd. A work around here could be to have an extra refcount in the back channel to avoid creating too many sockets.

@malahal
Copy link

malahal commented Mar 1, 2020

Workaround for rpc.statd did work, but it leaks connections to portmapper and other sockets with remote clients with NLM. Maybe, unhook should have some fuzzy logic to wait for any additional events that could happen. Maybe, a sleep of one second (or socket pair based trick) may work.

@dang
Copy link
Collaborator Author

dang commented Mar 2, 2020

Hmm... This is an interesting problem. Let me think about it for a bit.

@dang
Copy link
Collaborator Author

dang commented Mar 3, 2020

Okay, this should close that hole. It works for me, and tests correctly (modulo the client leak mentioned above, which I need to look at next).

@malahal
Copy link

malahal commented Mar 15, 2020

Found 2/3 issues with this code:
#1. UDP xprt refcount is going negative since it removed the additional ref that existed in old code
#2. TCP connections fron NFS clients are NOT getting closed. This code probably added an extra ref count for them. The old code was messy and somehow avoided this I think!
#3. connections initiated by ganesha to NFS clients (at nlockmgr port) are going to zero refcount but they are NOT getting closed due to not having CLNT_CREATE_FLAG_CLOSE flag. This might be an existing issue though.

https://github.com/malahal/ntirpc/commits/hook has fixes for #1, #2 and #3 (based on 2.7 code though). The top commit is just a clean up patch, but the following 3 commits should fix the issues reported here.

@dang
Copy link
Collaborator Author

dang commented Mar 17, 2020

I have 1 and 2 in my branch now. I'm not seeing how 3 can matter, since the hash table has a ref, and releases it at the end of DESTROY. If the RELEASE is freeing the xprt before the DESTROY, that's a bug.

@malahal
Copy link

malahal commented Mar 20, 2020

I have 1 and 2 in my branch now. I'm not seeing how 3 can matter, since the hash table has a ref, and releases it at the end of DESTROY. If the RELEASE is freeing the xprt before the DESTROY, that's a bug.

The 3rd one is about not having SVC_XPRT_FLAG_CLOSE flag. The xprt memory gets freed but the fd would be still open without this flag, see "svc_vc_destroy_task()" for details.

If you are talking about my TOP commit that has re-order of destroy and release, then that is an issue if some other threads can call DESTROY on the xprt. I don't know if that can happen though. the idea seems to be that multiple threads could call SVC_DESTROY().

@dang
Copy link
Collaborator Author

dang commented Mar 23, 2020

Okay, so that branch doesn't have a fix for #3? I'm only seeing 3 commits there.

There is a race when unhooking events from epoll, where the event could
be ready for delivery (or even delivered, but the thread not scheduled)
and so the event is processed after the unhook, and therefore after the
XPRT has been freed.  To close this, stop putting a pointer to the rec
in the event data, and instead put the FD in there and use it to look up
the XPRT.  This ensures that, if we got the XPRT from lookup, it's valid
and ref'd for the duration of the event.

Once we're no longer storing a XPRT pointer in the epoll event, we don't
need a refcount across the hook/event/unhook series.  Remove these
refcounts, allowing a destroyed XPRT to just be freed.

Signed-off-by: Daniel Gryniewicz <[email protected]>
@malahal
Copy link

malahal commented Apr 4, 2020

I have 1 and 2 in my branch now. I'm not seeing how 3 can matter, since the hash table has a ref, and releases it at the end of DESTROY. If the RELEASE is freeing the xprt before the DESTROY, that's a bug.

Sorry, I must have rebased the branch. You suggested to fix the #3 in ganesha repo to avoid API change. The patch here in out ibm2.7 branch (ganesha repo though):

commit 5b67cd1
Author: Malahal Naineni [email protected]
Date: Tue Mar 17 01:13:56 2020 +0530

Fix closing fds started by ganesha as a client.

clnt_vc_ncreate() isn't passing CLNT_CREATE_FLAG_CLOSE flag leading to
sockets in CLOSE_WAIT state. Use the flag to close sockets when they
reach 0 refcount. Fix it by directly calling clnt_vc_ncreatef() with the
right flags.

Change-Id: I6d5b2de5d6afd0d543192bd6038db71bd52c20dd
Signed-off-by: Malahal Naineni <[email protected]>

@dang
Copy link
Collaborator Author

dang commented Apr 6, 2020

Okay, that looks good. I'll merge this, then.

@dang dang merged commit 344a636 into nfs-ganesha:next Apr 6, 2020
@dang dang deleted the hook branch April 6, 2020 16:40
@dang dang mentioned this pull request Apr 6, 2020
@malahal
Copy link

malahal commented Apr 7, 2020

Okay, that looks good. I'll merge this, then.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants