Commit 3b445eea authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'fixes' of git://git.linux-nfs.org/pub/linux/nfs-2.6

* 'fixes' of git://git.linux-nfs.org/pub/linux/nfs-2.6:
  SUNRPC: Fix obvious refcounting bugs in rpc_pipefs.
  RPC: Ensure that we disconnect TCP socket when client requests error out
  NLM/lockd: remove b_done
  NFS: make 2 functions static
  NFS: Release dcache_lock in an error path of nfs_path
parents 12952784 5c3e985a
...@@ -638,9 +638,6 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data) ...@@ -638,9 +638,6 @@ static void nlmsvc_grant_callback(struct rpc_task *task, void *data)
if (task->tk_status < 0) { if (task->tk_status < 0) {
/* RPC error: Re-insert for retransmission */ /* RPC error: Re-insert for retransmission */
timeout = 10 * HZ; timeout = 10 * HZ;
} else if (block->b_done) {
/* Block already removed, kill it for real */
timeout = 0;
} else { } else {
/* Call was successful, now wait for client callback */ /* Call was successful, now wait for client callback */
timeout = 60 * HZ; timeout = 60 * HZ;
...@@ -709,12 +706,9 @@ nlmsvc_retry_blocked(void) ...@@ -709,12 +706,9 @@ nlmsvc_retry_blocked(void)
break; break;
if (time_after(block->b_when,jiffies)) if (time_after(block->b_when,jiffies))
break; break;
dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
block, block->b_when, block->b_done); block, block->b_when);
kref_get(&block->b_count); kref_get(&block->b_count);
if (block->b_done)
nlmsvc_unlink_block(block);
else
nlmsvc_grant_blocked(block); nlmsvc_grant_blocked(block);
nlmsvc_release_block(block); nlmsvc_release_block(block);
} }
......
...@@ -51,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry, ...@@ -51,7 +51,7 @@ char *nfs_path(const char *base, const struct dentry *dentry,
namelen = dentry->d_name.len; namelen = dentry->d_name.len;
buflen -= namelen + 1; buflen -= namelen + 1;
if (buflen < 0) if (buflen < 0)
goto Elong; goto Elong_unlock;
end -= namelen; end -= namelen;
memcpy(end, dentry->d_name.name, namelen); memcpy(end, dentry->d_name.name, namelen);
*--end = '/'; *--end = '/';
...@@ -68,6 +68,8 @@ char *nfs_path(const char *base, const struct dentry *dentry, ...@@ -68,6 +68,8 @@ char *nfs_path(const char *base, const struct dentry *dentry,
end -= namelen; end -= namelen;
memcpy(end, base, namelen); memcpy(end, base, namelen);
return end; return end;
Elong_unlock:
spin_unlock(&dcache_lock);
Elong: Elong:
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
} }
......
...@@ -63,7 +63,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) ...@@ -63,7 +63,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
return p; return p;
} }
void nfs_readdata_free(struct nfs_read_data *p) static void nfs_readdata_free(struct nfs_read_data *p)
{ {
if (p && (p->pagevec != &p->page_array[0])) if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec); kfree(p->pagevec);
......
...@@ -137,7 +137,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) ...@@ -137,7 +137,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
return p; return p;
} }
void nfs_writedata_free(struct nfs_write_data *p) static void nfs_writedata_free(struct nfs_write_data *p)
{ {
if (p && (p->pagevec != &p->page_array[0])) if (p && (p->pagevec != &p->page_array[0]))
kfree(p->pagevec); kfree(p->pagevec);
......
...@@ -123,7 +123,6 @@ struct nlm_block { ...@@ -123,7 +123,6 @@ struct nlm_block {
unsigned int b_id; /* block id */ unsigned int b_id; /* block id */
unsigned char b_queued; /* re-queued */ unsigned char b_queued; /* re-queued */
unsigned char b_granted; /* VFS granted lock */ unsigned char b_granted; /* VFS granted lock */
unsigned char b_done; /* callback complete */
struct nlm_file * b_file; /* file in question */ struct nlm_file * b_file; /* file in question */
}; };
......
...@@ -476,10 +476,9 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) ...@@ -476,10 +476,9 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page)
} }
/* /*
* Allocate and free nfs_write_data structures * Allocate nfs_write_data structures
*/ */
extern struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount); extern struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount);
extern void nfs_writedata_free(struct nfs_write_data *p);
/* /*
* linux/fs/nfs/read.c * linux/fs/nfs/read.c
...@@ -491,10 +490,9 @@ extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *); ...@@ -491,10 +490,9 @@ extern int nfs_readpage_result(struct rpc_task *, struct nfs_read_data *);
extern void nfs_readdata_release(void *data); extern void nfs_readdata_release(void *data);
/* /*
* Allocate and free nfs_read_data structures * Allocate nfs_read_data structures
*/ */
extern struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount); extern struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount);
extern void nfs_readdata_free(struct nfs_read_data *p);
/* /*
* linux/fs/nfs3proc.c * linux/fs/nfs3proc.c
......
...@@ -229,7 +229,7 @@ int xprt_reserve_xprt(struct rpc_task *task); ...@@ -229,7 +229,7 @@ int xprt_reserve_xprt(struct rpc_task *task);
int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_reserve_xprt_cong(struct rpc_task *task);
int xprt_prepare_transmit(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task);
void xprt_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task);
void xprt_abort_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task);
int xprt_adjust_timeout(struct rpc_rqst *req); int xprt_adjust_timeout(struct rpc_rqst *req);
void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
......
...@@ -921,26 +921,43 @@ call_transmit(struct rpc_task *task) ...@@ -921,26 +921,43 @@ call_transmit(struct rpc_task *task)
task->tk_status = xprt_prepare_transmit(task); task->tk_status = xprt_prepare_transmit(task);
if (task->tk_status != 0) if (task->tk_status != 0)
return; return;
task->tk_action = call_transmit_status;
/* Encode here so that rpcsec_gss can use correct sequence number. */ /* Encode here so that rpcsec_gss can use correct sequence number. */
if (rpc_task_need_encode(task)) { 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); call_encode(task);
/* Did the encode result in an error condition? */ /* Did the encode result in an error condition? */
if (task->tk_status != 0) if (task->tk_status != 0)
goto out_nosend; return;
} }
task->tk_action = call_transmit_status;
xprt_transmit(task); xprt_transmit(task);
if (task->tk_status < 0) if (task->tk_status < 0)
return; return;
if (!task->tk_msg.rpc_proc->p_decode) { /*
* 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; task->tk_action = rpc_exit_task;
rpc_wake_up_task(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; return;
out_nosend: xprt_end_transmit(task);
/* release socket write lock before attempting to handle error */
xprt_abort_transmit(task);
rpc_task_force_reencode(task); rpc_task_force_reencode(task);
} }
...@@ -992,18 +1009,7 @@ call_status(struct rpc_task *task) ...@@ -992,18 +1009,7 @@ call_status(struct rpc_task *task)
} }
/* /*
* 6a. Handle transmission errors. * 6a. Handle RPC timeout
*/
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
* We do not release the request slot, so we keep using the * We do not release the request slot, so we keep using the
* same XID for all retransmits. * same XID for all retransmits.
*/ */
......
...@@ -667,10 +667,11 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) ...@@ -667,10 +667,11 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client)
RPCAUTH_info, RPCAUTH_EOF); RPCAUTH_info, RPCAUTH_EOF);
if (error) if (error)
goto err_depopulate; goto err_depopulate;
dget(dentry);
out: out:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd); rpc_release_path(&nd);
return dget(dentry); return dentry;
err_depopulate: err_depopulate:
rpc_depopulate(dentry); rpc_depopulate(dentry);
__rpc_rmdir(dir, dentry); __rpc_rmdir(dir, dentry);
...@@ -731,10 +732,11 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags) ...@@ -731,10 +732,11 @@ rpc_mkpipe(char *path, void *private, struct rpc_pipe_ops *ops, int flags)
rpci->flags = flags; rpci->flags = flags;
rpci->ops = ops; rpci->ops = ops;
inode_dir_notify(dir, DN_CREATE); inode_dir_notify(dir, DN_CREATE);
dget(dentry);
out: out:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
rpc_release_path(&nd); rpc_release_path(&nd);
return dget(dentry); return dentry;
err_dput: err_dput:
dput(dentry); dput(dentry);
dentry = ERR_PTR(-ENOMEM); dentry = ERR_PTR(-ENOMEM);
......
...@@ -707,12 +707,9 @@ int xprt_prepare_transmit(struct rpc_task *task) ...@@ -707,12 +707,9 @@ int xprt_prepare_transmit(struct rpc_task *task)
return err; return err;
} }
void void xprt_end_transmit(struct rpc_task *task)
xprt_abort_transmit(struct rpc_task *task)
{ {
struct rpc_xprt *xprt = task->tk_xprt; xprt_release_write(task->tk_xprt, task);
xprt_release_write(xprt, task);
} }
/** /**
...@@ -761,8 +758,6 @@ void xprt_transmit(struct rpc_task *task) ...@@ -761,8 +758,6 @@ void xprt_transmit(struct rpc_task *task)
task->tk_status = -ENOTCONN; task->tk_status = -ENOTCONN;
else if (!req->rq_received) else if (!req->rq_received)
rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer); rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
xprt->ops->release_xprt(xprt, task);
spin_unlock_bh(&xprt->transport_lock); spin_unlock_bh(&xprt->transport_lock);
return; return;
} }
...@@ -772,18 +767,8 @@ void xprt_transmit(struct rpc_task *task) ...@@ -772,18 +767,8 @@ void xprt_transmit(struct rpc_task *task)
* schedq, and being picked up by a parallel run of rpciod(). * schedq, and being picked up by a parallel run of rpciod().
*/ */
task->tk_status = status; task->tk_status = status;
if (status == -ECONNREFUSED)
switch (status) {
case -ECONNREFUSED:
rpc_sleep_on(&xprt->sending, task, NULL, NULL); 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) static inline void do_xprt_reserve(struct rpc_task *task)
......
...@@ -413,6 +413,33 @@ static int xs_tcp_send_request(struct rpc_task *task) ...@@ -413,6 +413,33 @@ static int xs_tcp_send_request(struct rpc_task *task)
return status; return status;
} }
/**
* 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 * xs_close - close a socket
* @xprt: transport * @xprt: transport
...@@ -1250,7 +1277,7 @@ static struct rpc_xprt_ops xs_udp_ops = { ...@@ -1250,7 +1277,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
static struct rpc_xprt_ops xs_tcp_ops = { static struct rpc_xprt_ops xs_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt, .reserve_xprt = xprt_reserve_xprt,
.release_xprt = xprt_release_xprt, .release_xprt = xs_tcp_release_xprt,
.set_port = xs_set_port, .set_port = xs_set_port,
.connect = xs_connect, .connect = xs_connect,
.buf_alloc = rpc_malloc, .buf_alloc = rpc_malloc,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment