From 46e045034336a2cc90c1798cd7cc07af744ddfd6 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 19 Apr 2000 04:00:00 +0000 Subject: Merge with Linux 2.3.99-pre4. --- net/sunrpc/clnt.c | 16 +++++++----- net/sunrpc/sched.c | 67 ++++++++++++++++++++++++++++++++++++------------ net/sunrpc/sunrpc_syms.c | 4 ++- net/sunrpc/svcsock.c | 3 +-- net/sunrpc/xdr.c | 62 +++++++++++++++++++++++++++++++++++++++++--- net/sunrpc/xprt.c | 7 ++--- 6 files changed, 126 insertions(+), 33 deletions(-) (limited to 'net/sunrpc') 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 +#include + #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 #include #include +#include #include #include #include @@ -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,17 +85,22 @@ 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) { @@ -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 #include #include +#include #include #include #include @@ -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; -- cgit v1.2.3