Commit 21b75b01 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: fix 4.1 connection registration race

If a connection is closed just after a sequence or create_session
is sent over it, we could end up trying to register a callback that will
never get called since the xprt is already marked dead.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent c8ddb271
...@@ -673,16 +673,17 @@ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) ...@@ -673,16 +673,17 @@ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
} }
static void nfsd4_register_conn(struct nfsd4_conn *conn) static int nfsd4_register_conn(struct nfsd4_conn *conn)
{ {
conn->cn_xpt_user.callback = nfsd4_conn_lost; conn->cn_xpt_user.callback = nfsd4_conn_lost;
register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
} }
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
{ {
struct nfsd4_conn *conn; struct nfsd4_conn *conn;
u32 flags = NFS4_CDFC4_FORE; u32 flags = NFS4_CDFC4_FORE;
int ret;
if (ses->se_flags & SESSION4_BACK_CHAN) if (ses->se_flags & SESSION4_BACK_CHAN)
flags |= NFS4_CDFC4_BACK; flags |= NFS4_CDFC4_BACK;
...@@ -690,7 +691,10 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) ...@@ -690,7 +691,10 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
if (!conn) if (!conn)
return nfserr_jukebox; return nfserr_jukebox;
nfsd4_hash_conn(conn, ses); nfsd4_hash_conn(conn, ses);
nfsd4_register_conn(conn); ret = nfsd4_register_conn(conn);
if (ret)
/* oops; xprt is already down: */
nfsd4_conn_lost(&conn->cn_xpt_user);
return nfs_ok; return nfs_ok;
} }
...@@ -1644,6 +1648,7 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi ...@@ -1644,6 +1648,7 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi
{ {
struct nfs4_client *clp = ses->se_client; struct nfs4_client *clp = ses->se_client;
struct nfsd4_conn *c; struct nfsd4_conn *c;
int ret;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
c = __nfsd4_find_conn(new->cn_xprt, ses); c = __nfsd4_find_conn(new->cn_xprt, ses);
...@@ -1654,7 +1659,10 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi ...@@ -1654,7 +1659,10 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi
} }
__nfsd4_hash_conn(new, ses); __nfsd4_hash_conn(new, ses);
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
nfsd4_register_conn(new); ret = nfsd4_register_conn(new);
if (ret)
/* oops; xprt is already down: */
nfsd4_conn_lost(&new->cn_xpt_user);
return; return;
} }
......
...@@ -82,18 +82,28 @@ struct svc_xprt { ...@@ -82,18 +82,28 @@ struct svc_xprt {
struct net *xpt_net; struct net *xpt_net;
}; };
static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
{ {
spin_lock(&xpt->xpt_lock); spin_lock(&xpt->xpt_lock);
list_add(&u->list, &xpt->xpt_users); list_del_init(&u->list);
spin_unlock(&xpt->xpt_lock); spin_unlock(&xpt->xpt_lock);
} }
static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
{ {
spin_lock(&xpt->xpt_lock); spin_lock(&xpt->xpt_lock);
list_del_init(&u->list); if (test_bit(XPT_CLOSE, &xpt->xpt_flags)) {
/*
* The connection is about to be deleted soon (or,
* worse, may already be deleted--in which case we've
* already notified the xpt_users).
*/
spin_unlock(&xpt->xpt_lock); spin_unlock(&xpt->xpt_lock);
return -ENOTCONN;
}
list_add(&u->list, &xpt->xpt_users);
spin_unlock(&xpt->xpt_lock);
return 0;
} }
int svc_reg_xprt_class(struct svc_xprt_class *); int svc_reg_xprt_class(struct svc_xprt_class *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment