diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 51 | ||||
-rw-r--r-- | fs/nfsd/state.h | 3 |
2 files changed, 45 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 | ||
628 | static void free_conn(struct nfsd4_conn *c) | ||
629 | { | ||
630 | svc_xprt_put(c->cn_xprt); | ||
631 | kfree(c); | ||
632 | } | ||
633 | |||
634 | static 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 | |||
628 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) | 647 | static __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 | ||
647 | static void free_conn(struct nfsd4_conn *c) | 669 | static 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 | ||
653 | void free_session(struct kref *kref) | 688 | void 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; |
1557 | out: | 1590 | out: |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 29413c2ed270..8d5e2370cce0 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #ifndef _NFSD4_STATE_H | 35 | #ifndef _NFSD4_STATE_H |
36 | #define _NFSD4_STATE_H | 36 | #define _NFSD4_STATE_H |
37 | 37 | ||
38 | #include <linux/sunrpc/svc_xprt.h> | ||
38 | #include <linux/nfsd/nfsfh.h> | 39 | #include <linux/nfsd/nfsfh.h> |
39 | #include "nfsfh.h" | 40 | #include "nfsfh.h" |
40 | 41 | ||
@@ -155,6 +156,8 @@ struct nfsd4_clid_slot { | |||
155 | struct nfsd4_conn { | 156 | struct nfsd4_conn { |
156 | struct list_head cn_persession; | 157 | struct list_head cn_persession; |
157 | struct svc_xprt *cn_xprt; | 158 | struct svc_xprt *cn_xprt; |
159 | struct svc_xpt_user cn_xpt_user; | ||
160 | struct nfsd4_session *cn_session; | ||
158 | /* CDFC4_FORE, CDFC4_BACK: */ | 161 | /* CDFC4_FORE, CDFC4_BACK: */ |
159 | unsigned char cn_flags; | 162 | unsigned char cn_flags; |
160 | }; | 163 | }; |