summaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-04-19 04:00:00 +0000
commit46e045034336a2cc90c1798cd7cc07af744ddfd6 (patch)
tree3b9b51fc482e729f663d25333e77fbed9aaa939a /net/sunrpc
parent31dc59d503a02e84c4de98826452acaeb56dc15a (diff)
Merge with Linux 2.3.99-pre4.
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/clnt.c16
-rw-r--r--net/sunrpc/sched.c67
-rw-r--r--net/sunrpc/sunrpc_syms.c4
-rw-r--r--net/sunrpc/svcsock.c3
-rw-r--r--net/sunrpc/xdr.c62
-rw-r--r--net/sunrpc/xprt.c7
6 files changed, 126 insertions, 33 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 806e14bce..c41dfc1eb 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -32,6 +32,8 @@
#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+
#define RPC_SLACK_SPACE 1024 /* total overkill */
@@ -78,6 +80,7 @@ rpc_create_client(struct rpc_xprt *xprt, char *servname,
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
+ xdr_init();
if (!xprt)
goto out;
@@ -198,7 +201,6 @@ rpc_release_client(struct rpc_clnt *clnt)
static void
rpc_default_callback(struct rpc_task *task)
{
- rpc_release_task(task);
}
/*
@@ -263,9 +265,10 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
/* Set up the call info struct and execute the task */
if (task->tk_status == 0)
status = rpc_execute(task);
- else
+ else {
status = task->tk_status;
- rpc_release_task(task);
+ rpc_release_task(task);
+ }
rpc_clnt_sigunmask(clnt, &oldset);
@@ -344,10 +347,9 @@ rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
void
rpc_restart_call(struct rpc_task *task)
{
- if (task->tk_flags & RPC_TASK_KILLED) {
- rpc_release_task(task);
+ if (RPC_ASSASSINATED(task))
return;
- }
+
task->tk_action = call_reserve;
rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
}
@@ -715,7 +717,7 @@ call_decode(struct rpc_task *task)
* The following is an NFS-specific hack to cater for setuid
* processes whose uid is mapped to nobody on the server.
*/
- if (task->tk_client->cl_prog == 100003 &&
+ if (task->tk_client->cl_prog == NFS_PROGRAM &&
(ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index bfbfc1580..da46ab910 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -508,6 +508,7 @@ __rpc_execute(struct rpc_task *task)
return 0;
}
+ restarted:
while (1) {
/*
* Execute any pending callback.
@@ -586,10 +587,29 @@ __rpc_execute(struct rpc_task *task)
}
}
+ if (task->tk_exit) {
+ task->tk_exit(task);
+ /* If tk_action is non-null, the user wants us to restart */
+ if (task->tk_action) {
+ if (!RPC_ASSASSINATED(task)) {
+ /* Release RPC slot and buffer memory */
+ if (task->tk_rqstp)
+ xprt_release(task);
+ if (task->tk_buffer) {
+ rpc_free(task->tk_buffer);
+ task->tk_buffer = NULL;
+ }
+ goto restarted;
+ }
+ printk(KERN_ERR "RPC: dead task tries to walk away.\n");
+ }
+ }
+
dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
status = task->tk_status;
- if (task->tk_exit)
- task->tk_exit(task);
+
+ /* Release all resources associated with the task */
+ rpc_release_task(task);
return status;
}
@@ -599,22 +619,32 @@ __rpc_execute(struct rpc_task *task)
*
* This may be called recursively if e.g. an async NFS task updates
* the attributes and finds that dirty pages must be flushed.
+ * NOTE: Upon exit of this function the task is guaranteed to be
+ * released. In particular note that tk_release() will have
+ * been called, so your task memory may have been freed.
*/
int
rpc_execute(struct rpc_task *task)
{
+ int status = -EIO;
if (rpc_inhibit) {
printk(KERN_INFO "RPC: execution inhibited!\n");
- return -EIO;
+ goto out_release;
}
- task->tk_flags |= RPC_TASK_RUNNING;
+
+ status = -EWOULDBLOCK;
if (task->tk_active) {
printk(KERN_ERR "RPC: active task was run twice!\n");
- return -EWOULDBLOCK;
+ goto out_err;
}
+
task->tk_active = 1;
-
+ task->tk_flags |= RPC_TASK_RUNNING;
return __rpc_execute(task);
+ out_release:
+ rpc_release_task(task);
+ out_err:
+ return status;
}
/*
@@ -700,7 +730,7 @@ rpc_allocate(unsigned int flags, unsigned int size)
}
if (flags & RPC_TASK_ASYNC)
return NULL;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ>>4);
} while (!signalled());
@@ -758,6 +788,13 @@ rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
current->pid);
}
+static void
+rpc_default_free_task(struct rpc_task *task)
+{
+ dprintk("RPC: %4d freeing task\n", task->tk_pid);
+ rpc_free(task);
+}
+
/*
* Create a new task for the specified client. We have to
* clean up after an allocation failure, as the client may
@@ -774,6 +811,9 @@ rpc_new_task(struct rpc_clnt *clnt, rpc_action callback, int flags)
rpc_init_task(task, clnt, callback, flags);
+ /* Replace tk_release */
+ task->tk_release = rpc_default_free_task;
+
dprintk("RPC: %4d allocated task\n", task->tk_pid);
task->tk_flags |= RPC_TASK_DYNAMIC;
out:
@@ -849,12 +889,8 @@ rpc_release_task(struct rpc_task *task)
#ifdef RPC_DEBUG
task->tk_magic = 0;
#endif
-
- if (task->tk_flags & RPC_TASK_DYNAMIC) {
- dprintk("RPC: %4d freeing task\n", task->tk_pid);
- task->tk_flags &= ~RPC_TASK_DYNAMIC;
- rpc_free(task);
- }
+ if (task->tk_release)
+ task->tk_release(task);
}
/*
@@ -886,7 +922,6 @@ rpc_child_exit(struct rpc_task *child)
__rpc_wake_up(parent);
}
spin_unlock_bh(&rpc_queue_lock);
- rpc_release_task(child);
}
/*
@@ -1028,7 +1063,7 @@ rpciod_killall(void)
__rpc_schedule();
if (all_tasks) {
dprintk("rpciod_killall: waiting for tasks to exit\n");
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
}
@@ -1099,7 +1134,7 @@ rpciod_down(void)
* wait briefly before checking the process id.
*/
current->sigpending = 0;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
/*
* Display a message if we're going to wait longer.
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 92559fa65..36da3b619 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -27,7 +27,6 @@ EXPORT_SYMBOL(rpc_allocate);
EXPORT_SYMBOL(rpc_free);
EXPORT_SYMBOL(rpc_execute);
EXPORT_SYMBOL(rpc_init_task);
-EXPORT_SYMBOL(rpc_release_task);
EXPORT_SYMBOL(rpc_sleep_on);
EXPORT_SYMBOL(rpc_wake_up_next);
EXPORT_SYMBOL(rpc_wake_up_task);
@@ -89,12 +88,15 @@ EXPORT_SYMBOL(svc_proc_read);
#endif
/* Generic XDR */
+EXPORT_SYMBOL(xdr_encode_array);
EXPORT_SYMBOL(xdr_encode_string);
EXPORT_SYMBOL(xdr_decode_string);
EXPORT_SYMBOL(xdr_decode_netobj);
EXPORT_SYMBOL(xdr_encode_netobj);
EXPORT_SYMBOL(xdr_zero);
EXPORT_SYMBOL(xdr_one);
+EXPORT_SYMBOL(xdr_shift_iovec);
+EXPORT_SYMBOL(xdr_zero_iovec);
/* RPC errors */
EXPORT_SYMBOL(rpc_success);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 97e323d0c..d99033fa5 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -769,7 +769,7 @@ again:
* We have to be able to interrupt this wait
* to bring down the daemons ...
*/
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&rqstp->rq_wait, &wait);
spin_unlock_bh(&serv->sv_lock);
@@ -940,7 +940,6 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
if (protocol == IPPROTO_TCP) {
if ((error = sock->ops->listen(sock, 5)) < 0)
goto bummer;
- sock->flags |= SO_ACCEPTCON;
}
if ((svsk = svc_setup_socket(serv, sock, &error, 1)) != NULL)
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 6ebd94079..99b286af9 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -9,6 +9,7 @@
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/string.h>
+#include <linux/kernel.h>
#include <linux/in.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
@@ -56,8 +57,8 @@ xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
{
unsigned int quadlen = XDR_QUADLEN(obj->len);
+ p[quadlen] = 0; /* zero trailing bytes */
*p++ = htonl(obj->len);
- p[quadlen-1] = 0; /* zero trailing bytes */
memcpy(p, obj->data, obj->len);
return p + XDR_QUADLEN(obj->len);
}
@@ -84,18 +85,23 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
}
u32 *
-xdr_encode_string(u32 *p, const char *string)
+xdr_encode_array(u32 *p, const char *array, unsigned int len)
{
- int len = strlen(string);
int quadlen = XDR_QUADLEN(len);
p[quadlen] = 0;
*p++ = htonl(len);
- memcpy(p, string, len);
+ memcpy(p, array, len);
return p + quadlen;
}
u32 *
+xdr_encode_string(u32 *p, const char *string)
+{
+ return xdr_encode_array(p, string, strlen(string));
+}
+
+u32 *
xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
{
unsigned int len;
@@ -116,3 +122,51 @@ xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
return p + XDR_QUADLEN(len);
}
+/*
+ * Realign the iovec if the server missed out some reply elements
+ * (such as post-op attributes,...)
+ * Note: This is a simple implementation that assumes that
+ * len <= iov->iov_len !!!
+ * The RPC header (assumed to be the 1st element in the iov array)
+ * is not shifted.
+ */
+void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
+{
+ struct iovec *pvec;
+
+ for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
+ struct iovec *svec = pvec - 1;
+
+ if (len > pvec->iov_len) {
+ printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+ return;
+ }
+ memmove((char *)pvec->iov_base + len, pvec->iov_base,
+ pvec->iov_len - len);
+
+ if (len > svec->iov_len) {
+ printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+ return;
+ }
+ memcpy(pvec->iov_base,
+ (char *)svec->iov_base + svec->iov_len - len, len);
+ }
+}
+
+/*
+ * Zero the last n bytes in an iovec array of 'nr' elements
+ */
+void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+{
+ struct iovec *pvec;
+
+ for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
+ if (n < pvec->iov_len) {
+ memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
+ n = 0;
+ } else {
+ memset(pvec->iov_base, 0, pvec->iov_len);
+ n -= pvec->iov_len;
+ }
+ }
+}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 06d682223..b353aa37a 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -48,6 +48,7 @@
#include <linux/version.h>
#include <linux/types.h>
#include <linux/malloc.h>
+#include <linux/capability.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/socket.h>
@@ -227,7 +228,7 @@ xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
*/
break;
case -EAGAIN:
- if (sock->flags & SO_NOSPACE)
+ if (test_bit(SOCK_NOSPACE, &sock->flags))
result = -ENOMEM;
break;
case -ENOTCONN:
@@ -1569,8 +1570,8 @@ xprt_create_socket(int proto, struct rpc_timeout *to)
goto failed;
}
- /* If the caller has root privs, bind to a reserved port */
- if (!current->fsuid && xprt_bindresvport(sock) < 0)
+ /* If the caller has the capability, bind to a reserved port */
+ if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0)
goto failed;
return sock;