aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c51
1 files changed, 42 insertions, 9 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index c7c1a7afa197..b7e9793b58f5 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -625,6 +625,25 @@ static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4
625 new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); 625 new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
626} 626}
627 627
628static void free_conn(struct nfsd4_conn *c)
629{
630 svc_xprt_put(c->cn_xprt);
631 kfree(c);
632}
633
634static void nfsd4_conn_lost(struct svc_xpt_user *u)
635{
636 struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
637 struct nfs4_client *clp = c->cn_session->se_client;
638
639 spin_lock(&clp->cl_lock);
640 if (!list_empty(&c->cn_persession)) {
641 list_del(&c->cn_persession);
642 free_conn(c);
643 }
644 spin_unlock(&clp->cl_lock);
645}
646
628static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) 647static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
629{ 648{
630 struct nfs4_client *clp = ses->se_client; 649 struct nfs4_client *clp = ses->se_client;
@@ -636,18 +655,34 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses)
636 conn->cn_flags = NFS4_CDFC4_FORE; 655 conn->cn_flags = NFS4_CDFC4_FORE;
637 svc_xprt_get(rqstp->rq_xprt); 656 svc_xprt_get(rqstp->rq_xprt);
638 conn->cn_xprt = rqstp->rq_xprt; 657 conn->cn_xprt = rqstp->rq_xprt;
658 conn->cn_session = ses;
639 659
640 spin_lock(&clp->cl_lock); 660 spin_lock(&clp->cl_lock);
641 list_add(&conn->cn_persession, &ses->se_conns); 661 list_add(&conn->cn_persession, &ses->se_conns);
642 spin_unlock(&clp->cl_lock); 662 spin_unlock(&clp->cl_lock);
643 663
664 conn->cn_xpt_user.callback = nfsd4_conn_lost;
665 register_xpt_user(rqstp->rq_xprt, &conn->cn_xpt_user);
644 return nfs_ok; 666 return nfs_ok;
645} 667}
646 668
647static void free_conn(struct nfsd4_conn *c) 669static void nfsd4_del_conns(struct nfsd4_session *s)
648{ 670{
649 svc_xprt_put(c->cn_xprt); 671 struct nfs4_client *clp = s->se_client;
650 kfree(c); 672 struct nfsd4_conn *c;
673
674 spin_lock(&clp->cl_lock);
675 while (!list_empty(&s->se_conns)) {
676 c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
677 list_del_init(&c->cn_persession);
678 spin_unlock(&clp->cl_lock);
679
680 unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
681 free_conn(c);
682
683 spin_lock(&clp->cl_lock);
684 }
685 spin_unlock(&clp->cl_lock);
651} 686}
652 687
653void free_session(struct kref *kref) 688void free_session(struct kref *kref)
@@ -656,12 +691,7 @@ void free_session(struct kref *kref)
656 int mem; 691 int mem;
657 692
658 ses = container_of(kref, struct nfsd4_session, se_ref); 693 ses = container_of(kref, struct nfsd4_session, se_ref);
659 while (!list_empty(&ses->se_conns)) { 694 nfsd4_del_conns(ses);
660 struct nfsd4_conn *c;
661 c = list_first_entry(&ses->se_conns, struct nfsd4_conn, cn_persession);
662 list_del(&c->cn_persession);
663 free_conn(c);
664 }
665 spin_lock(&nfsd_drc_lock); 695 spin_lock(&nfsd_drc_lock);
666 mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); 696 mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
667 nfsd_drc_mem_used -= mem; 697 nfsd_drc_mem_used -= mem;
@@ -1552,6 +1582,9 @@ nfsd4_destroy_session(struct svc_rqst *r,
1552 /* wait for callbacks */ 1582 /* wait for callbacks */
1553 nfsd4_shutdown_callback(ses->se_client); 1583 nfsd4_shutdown_callback(ses->se_client);
1554 nfs4_unlock_state(); 1584 nfs4_unlock_state();
1585
1586 nfsd4_del_conns(ses);
1587
1555 nfsd4_put_session(ses); 1588 nfsd4_put_session(ses);
1556 status = nfs_ok; 1589 status = nfs_ok;
1557out: 1590out: