diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-06-06 18:37:16 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-10-01 19:29:44 -0400 |
commit | 19cf5c026f3ee06027523e59478e3fa54f573e5e (patch) | |
tree | e1162b69d7a558193b740344794d647a3d15e121 /fs/nfsd/nfs4state.c | |
parent | edc7a894034acb4c7ff8305716ca5df8aaf8e642 (diff) |
nfsd4: use callbacks on svc_xprt_deletion
Remove connections from the list when they go down.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 51 |
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 | ||
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: |