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>
This commit is contained in:
parent
c7662518c7
commit
edc7a89403
2 changed files with 40 additions and 0 deletions
|
@ -33,6 +33,16 @@ struct svc_xprt_class {
|
|||
u32 xcl_max_payload;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is embedded in an object that wants a callback before deleting
|
||||
* an xprt; intended for use by NFSv4.1, which needs to know when a
|
||||
* client's tcp connection (and hence possibly a backchannel) goes away.
|
||||
*/
|
||||
struct svc_xpt_user {
|
||||
struct list_head list;
|
||||
void (*callback)(struct svc_xpt_user *);
|
||||
};
|
||||
|
||||
struct svc_xprt {
|
||||
struct svc_xprt_class *xpt_class;
|
||||
struct svc_xprt_ops *xpt_ops;
|
||||
|
@ -67,10 +77,25 @@ struct svc_xprt {
|
|||
struct sockaddr_storage xpt_remote; /* remote peer's address */
|
||||
size_t xpt_remotelen; /* length of address */
|
||||
struct rpc_wait_queue xpt_bc_pending; /* backchannel wait queue */
|
||||
struct list_head xpt_users; /* callbacks on free */
|
||||
|
||||
struct net *xpt_net;
|
||||
};
|
||||
|
||||
static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
|
||||
{
|
||||
spin_lock(&xpt->xpt_lock);
|
||||
list_add(&u->list, &xpt->xpt_users);
|
||||
spin_unlock(&xpt->xpt_lock);
|
||||
}
|
||||
|
||||
static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
|
||||
{
|
||||
spin_lock(&xpt->xpt_lock);
|
||||
list_del_init(&u->list);
|
||||
spin_unlock(&xpt->xpt_lock);
|
||||
}
|
||||
|
||||
int svc_reg_xprt_class(struct svc_xprt_class *);
|
||||
void svc_unreg_xprt_class(struct svc_xprt_class *);
|
||||
void svc_xprt_init(struct svc_xprt_class *, struct svc_xprt *,
|
||||
|
|
|
@ -156,6 +156,7 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
|
|||
INIT_LIST_HEAD(&xprt->xpt_list);
|
||||
INIT_LIST_HEAD(&xprt->xpt_ready);
|
||||
INIT_LIST_HEAD(&xprt->xpt_deferred);
|
||||
INIT_LIST_HEAD(&xprt->xpt_users);
|
||||
mutex_init(&xprt->xpt_mutex);
|
||||
spin_lock_init(&xprt->xpt_lock);
|
||||
set_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
|
@ -881,6 +882,19 @@ static void svc_age_temp_xprts(unsigned long closure)
|
|||
mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
|
||||
}
|
||||
|
||||
static void call_xpt_users(struct svc_xprt *xprt)
|
||||
{
|
||||
struct svc_xpt_user *u;
|
||||
|
||||
spin_lock(&xprt->xpt_lock);
|
||||
while (!list_empty(&xprt->xpt_users)) {
|
||||
u = list_first_entry(&xprt->xpt_users, struct svc_xpt_user, list);
|
||||
list_del(&u->list);
|
||||
u->callback(u);
|
||||
}
|
||||
spin_unlock(&xprt->xpt_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a dead transport
|
||||
*/
|
||||
|
@ -913,6 +927,7 @@ void svc_delete_xprt(struct svc_xprt *xprt)
|
|||
while ((dr = svc_deferred_dequeue(xprt)) != NULL)
|
||||
kfree(dr);
|
||||
|
||||
call_xpt_users(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue