aboutsummaryrefslogtreecommitdiff
path: root/net/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c12
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c3
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c3
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c3
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_token.c3
-rw-r--r--net/sunrpc/cache.c6
-rw-r--r--net/sunrpc/clnt.c85
-rw-r--r--net/sunrpc/rpc_pipe.c69
-rw-r--r--net/sunrpc/stats.c7
-rw-r--r--net/sunrpc/svc.c6
-rw-r--r--net/sunrpc/svcsock.c3
-rw-r--r--net/sunrpc/xdr.c3
-rw-r--r--net/sunrpc/xprt.c24
-rw-r--r--net/sunrpc/xprtsock.c35
14 files changed, 130 insertions, 132 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 519ebc17c02..ef1cf5b476c 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -225,9 +225,8 @@ gss_alloc_context(void)
{
struct gss_cl_ctx *ctx;
- ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
- memset(ctx, 0, sizeof(*ctx));
ctx->gc_proc = RPC_GSS_PROC_DATA;
ctx->gc_seq = 1; /* NetApp 6.4R1 doesn't accept seq. no. 0 */
spin_lock_init(&ctx->gc_seq_lock);
@@ -391,9 +390,8 @@ gss_alloc_msg(struct gss_auth *gss_auth, uid_t uid)
{
struct gss_upcall_msg *gss_msg;
- gss_msg = kmalloc(sizeof(*gss_msg), GFP_KERNEL);
+ gss_msg = kzalloc(sizeof(*gss_msg), GFP_KERNEL);
if (gss_msg != NULL) {
- memset(gss_msg, 0, sizeof(*gss_msg));
INIT_LIST_HEAD(&gss_msg->list);
rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
init_waitqueue_head(&gss_msg->waitqueue);
@@ -720,8 +718,7 @@ gss_destroy(struct rpc_auth *auth)
auth, auth->au_flavor);
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
- rpc_unlink(gss_auth->path);
- dput(gss_auth->dentry);
+ rpc_unlink(gss_auth->dentry);
gss_auth->dentry = NULL;
gss_mech_put(gss_auth->mech);
@@ -776,10 +773,9 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
acred->uid, auth->au_flavor);
- if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
+ if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL)))
goto out_err;
- memset(cred, 0, sizeof(*cred));
atomic_set(&cred->gc_count, 1);
cred->gc_uid = acred->uid;
/*
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index b8714a87b34..70e1e53a632 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -129,9 +129,8 @@ gss_import_sec_context_kerberos(const void *p,
const void *end = (const void *)((const char *)p + len);
struct krb5_ctx *ctx;
- if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
- memset(ctx, 0, sizeof(*ctx));
p = simple_get_bytes(p, end, &ctx->initiate, sizeof(ctx->initiate));
if (IS_ERR(p))
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index d88468d21c3..3db745379d0 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -237,9 +237,8 @@ gss_import_sec_context(const void *input_token, size_t bufsize,
struct gss_api_mech *mech,
struct gss_ctx **ctx_id)
{
- if (!(*ctx_id = kmalloc(sizeof(**ctx_id), GFP_KERNEL)))
+ if (!(*ctx_id = kzalloc(sizeof(**ctx_id), GFP_KERNEL)))
return GSS_S_FAILURE;
- memset(*ctx_id, 0, sizeof(**ctx_id));
(*ctx_id)->mech_type = gss_mech_get(mech);
return mech->gm_ops
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 3d0432aa45c..88dcb52d171 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -152,9 +152,8 @@ gss_import_sec_context_spkm3(const void *p, size_t len,
const void *end = (const void *)((const char *)p + len);
struct spkm3_ctx *ctx;
- if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
+ if (!(ctx = kzalloc(sizeof(*ctx), GFP_KERNEL)))
goto out_err;
- memset(ctx, 0, sizeof(*ctx));
p = simple_get_netobj(p, end, &ctx->ctx_id);
if (IS_ERR(p))
diff --git a/net/sunrpc/auth_gss/gss_spkm3_token.c b/net/sunrpc/auth_gss/gss_spkm3_token.c
index af0d7ce7468..854a983ccf2 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_token.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_token.c
@@ -90,10 +90,9 @@ asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
int
decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
{
- if (!(out->data = kmalloc(explen,GFP_KERNEL)))
+ if (!(out->data = kzalloc(explen,GFP_KERNEL)))
return 0;
out->len = explen;
- memset(out->data, 0, explen);
memcpy(out->data, in, enclen);
return 1;
}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 7026b0866b7..00cb388ece0 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -71,7 +71,12 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
new = detail->alloc();
if (!new)
return NULL;
+ /* must fully initialise 'new', else
+ * we might get lose if we need to
+ * cache_put it soon.
+ */
cache_init(new);
+ detail->init(new, key);
write_lock(&detail->hash_lock);
@@ -85,7 +90,6 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
return tmp;
}
}
- detail->init(new, key);
new->next = *head;
*head = new;
detail->entries++;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index aa8965e9d30..3e19d321067 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -125,10 +125,9 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
goto out_err;
err = -ENOMEM;
- clnt = kmalloc(sizeof(*clnt), GFP_KERNEL);
+ clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
if (!clnt)
goto out_err;
- memset(clnt, 0, sizeof(*clnt));
atomic_set(&clnt->cl_users, 0);
atomic_set(&clnt->cl_count, 1);
clnt->cl_parent = clnt;
@@ -184,8 +183,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
out_no_auth:
if (!IS_ERR(clnt->cl_dentry)) {
- rpc_rmdir(clnt->cl_pathname);
- dput(clnt->cl_dentry);
+ rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
out_no_path:
@@ -252,10 +250,8 @@ rpc_clone_client(struct rpc_clnt *clnt)
new->cl_autobind = 0;
new->cl_oneshot = 0;
new->cl_dead = 0;
- if (!IS_ERR(new->cl_dentry)) {
+ if (!IS_ERR(new->cl_dentry))
dget(new->cl_dentry);
- rpc_get_mount();
- }
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
@@ -318,11 +314,15 @@ rpc_destroy_client(struct rpc_clnt *clnt)
clnt->cl_auth = NULL;
}
if (clnt->cl_parent != clnt) {
+ if (!IS_ERR(clnt->cl_dentry))
+ dput(clnt->cl_dentry);
rpc_destroy_client(clnt->cl_parent);
goto out_free;
}
- if (clnt->cl_pathname[0])
- rpc_rmdir(clnt->cl_pathname);
+ if (!IS_ERR(clnt->cl_dentry)) {
+ rpc_rmdir(clnt->cl_dentry);
+ rpc_put_mount();
+ }
if (clnt->cl_xprt) {
xprt_destroy(clnt->cl_xprt);
clnt->cl_xprt = NULL;
@@ -332,10 +332,6 @@ rpc_destroy_client(struct rpc_clnt *clnt)
out_free:
rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL;
- if (!IS_ERR(clnt->cl_dentry)) {
- dput(clnt->cl_dentry);
- rpc_put_mount();
- }
kfree(clnt);
return 0;
}
@@ -922,26 +918,43 @@ call_transmit(struct rpc_task *task)
task->tk_status = xprt_prepare_transmit(task);
if (task->tk_status != 0)
return;
+ task->tk_action = call_transmit_status;
/* Encode here so that rpcsec_gss can use correct sequence number. */
if (rpc_task_need_encode(task)) {
- task->tk_rqstp->rq_bytes_sent = 0;
+ BUG_ON(task->tk_rqstp->rq_bytes_sent != 0);
call_encode(task);
/* Did the encode result in an error condition? */
if (task->tk_status != 0)
- goto out_nosend;
+ return;
}
- task->tk_action = call_transmit_status;
xprt_transmit(task);
if (task->tk_status < 0)
return;
- if (!task->tk_msg.rpc_proc->p_decode) {
- task->tk_action = rpc_exit_task;
- rpc_wake_up_task(task);
- }
- return;
-out_nosend:
- /* release socket write lock before attempting to handle error */
- xprt_abort_transmit(task);
+ /*
+ * On success, ensure that we call xprt_end_transmit() before sleeping
+ * in order to allow access to the socket to other RPC requests.
+ */
+ call_transmit_status(task);
+ if (task->tk_msg.rpc_proc->p_decode != NULL)
+ return;
+ task->tk_action = rpc_exit_task;
+ rpc_wake_up_task(task);
+}
+
+/*
+ * 5a. Handle cleanup after a transmission
+ */
+static void
+call_transmit_status(struct rpc_task *task)
+{
+ task->tk_action = call_status;
+ /*
+ * Special case: if we've been waiting on the socket's write_space()
+ * callback, then don't call xprt_end_transmit().
+ */
+ if (task->tk_status == -EAGAIN)
+ return;
+ xprt_end_transmit(task);
rpc_task_force_reencode(task);
}
@@ -993,18 +1006,7 @@ call_status(struct rpc_task *task)
}
/*
- * 6a. Handle transmission errors.
- */
-static void
-call_transmit_status(struct rpc_task *task)
-{
- if (task->tk_status != -EAGAIN)
- rpc_task_force_reencode(task);
- call_status(task);
-}
-
-/*
- * 6b. Handle RPC timeout
+ * 6a. Handle RPC timeout
* We do not release the request slot, so we keep using the
* same XID for all retransmits.
*/
@@ -1179,6 +1181,17 @@ call_verify(struct rpc_task *task)
u32 *p = iov->iov_base, n;
int error = -EACCES;
+ if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
+ /* RFC-1014 says that the representation of XDR data must be a
+ * multiple of four bytes
+ * - if it isn't pointer subtraction in the NFS client may give
+ * undefined results
+ */
+ printk(KERN_WARNING
+ "call_verify: XDR representation not a multiple of"
+ " 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len);
+ goto out_eio;
+ }
if ((len -= 3) < 0)
goto out_overflow;
p += 1; /* skip XID */
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 6db6006616c..0b1a1ac8a4b 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -515,7 +515,7 @@ rpc_depopulate(struct dentry *parent)
struct dentry *dentry, *dvec[10];
int n = 0;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD);
repeat:
spin_lock(&dcache_lock);
list_for_each_safe(pos, next, &parent->d_subdirs) {
@@ -539,6 +539,7 @@ repeat:
rpc_close_pipes(dentry->d_inode);
simple_unlink(dir, dentry);
}
+ inode_dir_notify(dir, DN_DELETE);
dput(dentry);
} while (n);
goto repeat;
@@ -610,8 +611,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
int error;
shrink_dcache_parent(dentry);
- if (dentry->d_inode)
- rpc_close_pipes(dentry->d_inode);
+ if (d_unhashed(dentry))
+ return 0;
if ((error = simple_rmdir(dir, dentry)) != 0)
return error;
if (!error) {
@@ -631,7 +632,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
if ((error = rpc_lookup_parent(path, nd)) != 0)
return ERR_PTR(error);
dir = nd->dentry->d_inode;
- mutex_lock(&dir->i_mutex);
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
if (IS_ERR(dentry))
goto out_err;
@@ -667,10 +668,11 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
RPCAUTH_info, RPCAUTH_EOF);
if (error)
goto err_depopulate;
+ dget(dentry);
out:
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
- return dget(dentry);
+ return dentry;
err_depopulate:
rpc_depopulate(dentry);
__rpc_rmdir(dir, dentry);
@@ -683,28 +685,20 @@ err_dput:
}
int
-rpc_rmdir(char *path)
+rpc_rmdir(struct dentry *dentry)
{
- struct nameidata nd;
- struct dentry *dentry;
+ struct dentry *parent;
struct inode *dir;
int error;
- if ((error = rpc_lookup_parent(path, &nd)) != 0)
- return error;
- dir = nd.dentry->d_inode;
- mutex_lock(&dir->i_mutex);
- dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
- if (IS_ERR(dentry)) {
- error = PTR_ERR(dentry);
- goto out_release;
- }
+ parent = dget_parent(dentry);
+ dir = parent->d_inode;
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
rpc_depopulate(dentry);
error = __rpc_rmdir(dir, dentry);
dput(dentry);
-out_release:
mutex_unlock(&dir->i_mutex);
- rpc_release_path(&nd);
+ dput(parent);
return error;
}
@@ -731,10 +725,11 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
rpci->flags = flags;
rpci->ops = ops;
inode_dir_notify(dir, DN_CREATE);
+ dget(dentry);
out:
mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd);
- return dget(dentry);
+ return dentry;
err_dput:
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
@@ -744,32 +739,26 @@ err_dput:
}
int
-rpc_unlink(char *path)
+rpc_unlink(struct dentry *dentry)
{
- struct nameidata nd;
- struct dentry *dentry;
+ struct dentry *parent;
struct inode *dir;
- int error;
+ int error = 0;
- if ((error = rpc_lookup_parent(path, &nd)) != 0)
- return error;
- dir = nd.dentry->d_inode;
- mutex_lock(&dir->i_mutex);
- dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
- if (IS_ERR(dentry)) {
- error = PTR_ERR(dentry);
- goto out_release;
- }
- d_drop(dentry);
- if (dentry->d_inode) {
- rpc_close_pipes(dentry->d_inode);
- error = simple_unlink(dir, dentry);
+ parent = dget_parent(dentry);
+ dir = parent->d_inode;
+ mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
+ if (!d_unhashed(dentry)) {
+ d_drop(dentry);
+ if (dentry->d_inode) {
+ rpc_close_pipes(dentry->d_inode);
+ error = simple_unlink(dir, dentry);
+ }
+ inode_dir_notify(dir, DN_DELETE);
}
dput(dentry);
- inode_dir_notify(dir, DN_DELETE);
-out_release:
mutex_unlock(&dir->i_mutex);
- rpc_release_path(&nd);
+ dput(parent);
return error;
}
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 15c2db26767..bd98124c3a6 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -114,13 +114,8 @@ void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
*/
struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
{
- unsigned int ops = clnt->cl_maxproc;
- size_t size = ops * sizeof(struct rpc_iostats);
struct rpc_iostats *new;
-
- new = kmalloc(size, GFP_KERNEL);
- if (new)
- memset(new, 0 , size);
+ new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
return new;
}
EXPORT_SYMBOL(rpc_alloc_iostats);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 01ba60a4957..b76a227dd3a 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -32,9 +32,8 @@ svc_create(struct svc_program *prog, unsigned int bufsize)
int vers;
unsigned int xdrsize;
- if (!(serv = kmalloc(sizeof(*serv), GFP_KERNEL)))
+ if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
- memset(serv, 0, sizeof(*serv));
serv->sv_name = prog->pg_name;
serv->sv_program = prog;
serv->sv_nrthreads = 1;
@@ -159,11 +158,10 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
struct svc_rqst *rqstp;
int error = -ENOMEM;
- rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL);
+ rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
if (!rqstp)
goto out;
- memset(rqstp, 0, sizeof(*rqstp));
init_waitqueue_head(&rqstp->rq_wait);
if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index a27905a0ad2..d9a95732df4 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1322,11 +1322,10 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
struct sock *inet;
dprintk("svc: svc_setup_socket %p\n", sock);
- if (!(svsk = kmalloc(sizeof(*svsk), GFP_KERNEL))) {
+ if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
*errp = -ENOMEM;
return NULL;
}
- memset(svsk, 0, sizeof(*svsk));
inet = sock->sk;
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 49174f0d0a3..6ac45103a27 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -191,7 +191,6 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
do {
/* Are any pointers crossing a page boundary? */
if (pgto_base == 0) {
- flush_dcache_page(*pgto);
pgto_base = PAGE_CACHE_SIZE;
pgto--;
}
@@ -211,11 +210,11 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
vto = kmap_atomic(*pgto, KM_USER0);
vfrom = kmap_atomic(*pgfrom, KM_USER1);
memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
+ flush_dcache_page(*pgto);
kunmap_atomic(vfrom, KM_USER1);
kunmap_atomic(vto, KM_USER0);
} while ((len -= copy) != 0);
- flush_dcache_page(*pgto);
}
/*
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 02060d0e7be..e8c2bc4977f 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -707,12 +707,9 @@ out_unlock:
return err;
}
-void
-xprt_abort_transmit(struct rpc_task *task)
+void xprt_end_transmit(struct rpc_task *task)
{
- struct rpc_xprt *xprt = task->tk_xprt;
-
- xprt_release_write(xprt, task);
+ xprt_release_write(task->tk_xprt, task);
}
/**
@@ -761,8 +758,6 @@ void xprt_transmit(struct rpc_task *task)
task->tk_status = -ENOTCONN;
else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
-
- xprt->ops->release_xprt(xprt, task);
spin_unlock_bh(&xprt->transport_lock);
return;
}
@@ -772,18 +767,8 @@ void xprt_transmit(struct rpc_task *task)
* schedq, and being picked up by a parallel run of rpciod().
*/
task->tk_status = status;
-
- switch (status) {
- case -ECONNREFUSED:
+ if (status == -ECONNREFUSED)
rpc_sleep_on(&xprt->sending, task, NULL, NULL);
- case -EAGAIN:
- case -ENOTCONN:
- return;
- default:
- break;
- }
- xprt_release_write(xprt, task);
- return;
}
static inline void do_xprt_reserve(struct rpc_task *task)
@@ -908,9 +893,8 @@ static struct rpc_xprt *xprt_setup(int proto, struct sockaddr_in *ap, struct rpc
struct rpc_xprt *xprt;
struct rpc_rqst *req;
- if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
+ if ((xprt = kzalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
return ERR_PTR(-ENOMEM);
- memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
xprt->addr = *ap;
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 21006b10910..441bd53f5ec 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -414,6 +414,33 @@ static int xs_tcp_send_request(struct rpc_task *task)
}
/**
+ * xs_tcp_release_xprt - clean up after a tcp transmission
+ * @xprt: transport
+ * @task: rpc task
+ *
+ * This cleans up if an error causes us to abort the transmission of a request.
+ * In this case, the socket may need to be reset in order to avoid confusing
+ * the server.
+ */
+static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
+{
+ struct rpc_rqst *req;
+
+ if (task != xprt->snd_task)
+ return;
+ if (task == NULL)
+ goto out_release;
+ req = task->tk_rqstp;
+ if (req->rq_bytes_sent == 0)
+ goto out_release;
+ if (req->rq_bytes_sent == req->rq_snd_buf.len)
+ goto out_release;
+ set_bit(XPRT_CLOSE_WAIT, &task->tk_xprt->state);
+out_release:
+ xprt_release_xprt(xprt, task);
+}
+
+/**
* xs_close - close a socket
* @xprt: transport
*
@@ -1250,7 +1277,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
static struct rpc_xprt_ops xs_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
- .release_xprt = xprt_release_xprt,
+ .release_xprt = xs_tcp_release_xprt,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
@@ -1276,10 +1303,9 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
xprt->max_reqs = xprt_udp_slot_table_entries;
slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
- xprt->slot = kmalloc(slot_table_size, GFP_KERNEL);
+ xprt->slot = kzalloc(slot_table_size, GFP_KERNEL);
if (xprt->slot == NULL)
return -ENOMEM;
- memset(xprt->slot, 0, slot_table_size);
xprt->prot = IPPROTO_UDP;
xprt->port = xs_get_random_port();
@@ -1318,10 +1344,9 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
xprt->max_reqs = xprt_tcp_slot_table_entries;
slot_table_size = xprt->max_reqs * sizeof(xprt->slot[0]);
- xprt->slot = kmalloc(slot_table_size, GFP_KERNEL);
+ xprt->slot = kzalloc(slot_table_size, GFP_KERNEL);
if (xprt->slot == NULL)
return -ENOMEM;
- memset(xprt->slot, 0, slot_table_size);
xprt->prot = IPPROTO_TCP;
xprt->port = xs_get_random_port();