diff options
author | J. Bruce Fields <bfields@citi.umich.edu> | 2010-03-22 15:37:17 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2010-10-01 19:29:44 -0400 |
commit | edc7a894034acb4c7ff8305716ca5df8aaf8e642 (patch) | |
tree | 7db61c8c76fc3e58e499989665f2f26987c058a1 | |
parent | c7662518c781edc8059cd9737d18168154bf7510 (diff) |
nfsd: provide callbacks on svc_xprt deletion
NFSv4.1 needs warning when a client tcp connection goes down, if that
connection is being used as a backchannel, so that it can warn the
client that it has lost the backchannel connection.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | include/linux/sunrpc/svc_xprt.h | 25 | ||||
-rw-r--r-- | net/sunrpc/svc_xprt.c | 15 |
2 files changed, 40 insertions, 0 deletions
diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index bb182979569e..bbdb680ffbe9 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h | |||
@@ -33,6 +33,16 @@ struct svc_xprt_class { | |||
33 | u32 xcl_max_payload; | 33 | u32 xcl_max_payload; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | /* | ||
37 | * This is embedded in an object that wants a callback before deleting | ||
38 | * an xprt; intended for use by NFSv4.1, which needs to know when a | ||
39 | * client's tcp connection (and hence possibly a backchannel) goes away. | ||
40 | */ | ||
41 | struct svc_xpt_user { | ||
42 | struct list_head list; | ||
43 | void (*callback)(struct svc_xpt_user *); | ||
44 | }; | ||
45 | |||
36 | struct svc_xprt { | 46 | struct svc_xprt { |
37 | struct svc_xprt_class *xpt_class; | 47 | struct svc_xprt_class *xpt_class; |
38 | struct svc_xprt_ops *xpt_ops; | 48 | struct svc_xprt_ops *xpt_ops; |
@@ -67,10 +77,25 @@ struct svc_xprt { | |||
67 | struct sockaddr_storage xpt_remote; /* remote peer's address */ | 77 | struct sockaddr_storage xpt_remote; /* remote peer's address */ |
68 | size_t xpt_remotelen; /* length of address */ | 78 | size_t xpt_remotelen; /* length of address */ |
69 | struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */ | 79 | struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */ |
80 | struct list_head xpt_users; /* callbacks on free */ | ||
70 | 81 | ||
71 | struct net *xpt_net; | 82 | struct net *xpt_net; |
72 | }; | 83 | }; |
73 | 84 | ||
85 | static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) | ||
86 | { | ||
87 | spin_lock(&xpt->xpt_lock); | ||
88 | list_add(&u->list, &xpt->xpt_users); | ||
89 | spin_unlock(&xpt->xpt_lock); | ||
90 | } | ||
91 | |||
92 | static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) | ||
93 | { | ||
94 | spin_lock(&xpt->xpt_lock); | ||
95 | list_del_init(&u->list); | ||
96 | spin_unlock(&xpt->xpt_lock); | ||
97 | } | ||
98 | |||
74 | int svc_reg_xprt_class(struct svc_xprt_class *); | 99 | int svc_reg_xprt_class(struct svc_xprt_class *); |
75 | void svc_unreg_xprt_class(struct svc_xprt_class *); | 100 | void svc_unreg_xprt_class(struct svc_xprt_class *); |
76 | void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *, | 101 | void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *, |
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 678b6ee4da7b..12025eedc781 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -156,6 +156,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt, | |||
156 | INIT_LIST_HEAD(&xprt->xpt_list); | 156 | INIT_LIST_HEAD(&xprt->xpt_list); |
157 | INIT_LIST_HEAD(&xprt->xpt_ready); | 157 | INIT_LIST_HEAD(&xprt->xpt_ready); |
158 | INIT_LIST_HEAD(&xprt->xpt_deferred); | 158 | INIT_LIST_HEAD(&xprt->xpt_deferred); |
159 | INIT_LIST_HEAD(&xprt->xpt_users); | ||
159 | mutex_init(&xprt->xpt_mutex); | 160 | mutex_init(&xprt->xpt_mutex); |
160 | spin_lock_init(&xprt->xpt_lock); | 161 | spin_lock_init(&xprt->xpt_lock); |
161 | set_bit(XPT_BUSY, &xprt->xpt_flags); | 162 | set_bit(XPT_BUSY, &xprt->xpt_flags); |
@@ -881,6 +882,19 @@ static void svc_age_temp_xprts(unsigned long closure) | |||
881 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); | 882 | mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ); |
882 | } | 883 | } |
883 | 884 | ||
885 | static void call_xpt_users(struct svc_xprt *xprt) | ||
886 | { | ||
887 | struct svc_xpt_user *u; | ||
888 | |||
889 | spin_lock(&xprt->xpt_lock); | ||
890 | while (!list_empty(&xprt->xpt_users)) { | ||
891 | u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list); | ||
892 | list_del(&u->list); | ||
893 | u->callback(u); | ||
894 | } | ||
895 | spin_unlock(&xprt->xpt_lock); | ||
896 | } | ||
897 | |||
884 | /* | 898 | /* |
885 | * Remove a dead transport | 899 | * Remove a dead transport |
886 | */ | 900 | */ |
@@ -913,6 +927,7 @@ void svc_delete_xprt(struct svc_xprt *xprt) | |||
913 | while ((dr = svc_deferred_dequeue(xprt)) != NULL) | 927 | while ((dr = svc_deferred_dequeue(xprt)) != NULL) |
914 | kfree(dr); | 928 | kfree(dr); |
915 | 929 | ||
930 | call_xpt_users(xprt); | ||
916 | svc_xprt_put(xprt); | 931 | svc_xprt_put(xprt); |
917 | } | 932 | } |
918 | 933 | ||