diff -u --recursive --new-file linux-2.2.18pre21/include/linux/sunrpc/sched.h linux-2.2.18-sunrpc/include/linux/sunrpc/sched.h --- linux-2.2.18pre21/include/linux/sunrpc/sched.h Mon Nov 13 17:25:24 2000 +++ linux-2.2.18-sunrpc/include/linux/sunrpc/sched.h Sun Nov 19 16:14:18 2000 @@ -45,7 +45,7 @@ struct rpc_task * tk_parent; /* parent task */ struct rpc_clnt * tk_client; /* RPC client */ struct rpc_rqst * tk_rqstp; /* RPC request */ - volatile int tk_status; /* result of last operation */ + int tk_status; /* result of last operation */ struct rpc_wait_queue * tk_rpcwait; /* RPC wait queue we're on */ /* @@ -81,8 +81,7 @@ unsigned int tk_lock; /* Task lock counter */ unsigned char tk_active : 1,/* Task has been activated */ tk_wakeup : 1;/* Task waiting to wake up */ - volatile unsigned char tk_running : 1,/* Task is running */ - tk_sleeping : 1;/* Task is truly asleep */ + unsigned int tk_runstate; /* Task run status */ #ifdef RPC_DEBUG unsigned int tk_pid; /* debugging aid */ #endif @@ -112,10 +111,20 @@ #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) -#define RPC_IS_RUNNING(t) ((t)->tk_running) -#define RPC_IS_SLEEPING(t) ((t)->tk_sleeping) #define RPC_IS_ACTIVATED(t) ((t)->tk_active) #define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) + +#define RPC_TASK_SLEEPING 0 +#define RPC_TASK_RUNNING 1 +#define RPC_IS_SLEEPING(t) (test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) +#define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) + +#define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) +#define rpc_clear_running(t) (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) + +#define rpc_set_sleeping(t) (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) + +#define rpc_clear_sleeping(t) (clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) /* * RPC synchronization objects diff -u --recursive --new-file linux-2.2.18pre21/include/linux/sunrpc/svcsock.h linux-2.2.18-sunrpc/include/linux/sunrpc/svcsock.h --- linux-2.2.18pre21/include/linux/sunrpc/svcsock.h Mon Nov 13 17:32:25 2000 +++ linux-2.2.18-sunrpc/include/linux/sunrpc/svcsock.h Sat Nov 18 21:56:37 2000 @@ -25,13 +25,13 @@ struct svc_serv * sk_server; /* service for this socket */ atomic_t sk_inuse; /* use count */ - volatile int sk_conn; /* conn pending */ - volatile int sk_data; /* data pending */ - volatile unsigned char sk_busy : 1, /* enqueued/receiving */ - sk_close: 1, /* dead or dying */ + atomic_t sk_conn; /* conn pending */ + atomic_t sk_data; /* data pending */ + int sk_state; /* socket status */ + unsigned char sk_busy : 1, /* enqueued/receiving */ sk_qued : 1, /* on serv->sk_sockets */ - sk_dead : 1; /* socket closed */ - unsigned char sk_temp : 1; /* temp socket */ + sk_dead : 1, /* dead or dying */ + sk_temp : 1; /* temp socket */ int (*sk_recvfrom)(struct svc_rqst *rqstp); int (*sk_sendto)(struct svc_rqst *rqstp); @@ -55,5 +55,9 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); + +#define SVSK_CLOSE 0 +#define svsk_is_closing(sk) (test_bit(SVSK_CLOSE, &(sk)->sk_state)) +#define svsk_set_close(sk) (set_bit(SVSK_CLOSE, &(sk)->sk_state)) #endif /* SUNRPC_SVCSOCK_H */ diff -u --recursive --new-file linux-2.2.18pre21/include/linux/sunrpc/xprt.h linux-2.2.18-sunrpc/include/linux/sunrpc/xprt.h --- linux-2.2.18pre21/include/linux/sunrpc/xprt.h Mon Nov 13 17:31:47 2000 +++ linux-2.2.18-sunrpc/include/linux/sunrpc/xprt.h Sun Nov 19 18:01:54 2000 @@ -98,7 +98,7 @@ struct rpc_task * rq_task; /* RPC task data */ __u32 rq_xid; /* request XID */ struct rpc_rqst * rq_next; /* free list */ - volatile unsigned char rq_received : 1;/* receive completed */ + unsigned char rq_received : 1;/* receive completed */ /* * For authentication (e.g. auth_des) @@ -140,8 +140,7 @@ struct rpc_wait_queue reconn; /* waiting for reconnect */ struct rpc_rqst * free; /* free slots */ struct rpc_rqst slot[RPC_MAXREQS]; - volatile unsigned char connected : 1,/* TCP: connected */ - write_space : 1;/* TCP: can send */ + unsigned int sockstate; /* Socket state */ unsigned char nocong : 1,/* no congestion control */ stream : 1,/* TCP */ shutdown : 1,/* being shut down */ @@ -209,23 +208,18 @@ __rpciod_tcp_dispatcher(); } -static inline -int xprt_connected(struct rpc_xprt *xprt) -{ - return xprt->connected; -} +#define XPRT_WSPACE 0 +#define XPRT_CONNECT 1 -static inline -void xprt_set_connected(struct rpc_xprt *xprt) -{ - xprt->connected = 1; -} +#define xprt_wspace(xp) (test_bit(XPRT_WSPACE, &(xp)->sockstate)) +#define xprt_test_and_set_wspace(xp) (test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate)) +#define xprt_clear_wspace(xp) (clear_bit(XPRT_WSPACE, &(xp)->sockstate)) + +#define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) +#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) -static inline -void xprt_clear_connected(struct rpc_xprt *xprt) -{ - xprt->connected = 0; -} #endif /* __KERNEL__*/ diff -u --recursive --new-file linux-2.2.18pre21/net/sunrpc/sched.c linux-2.2.18-sunrpc/net/sunrpc/sched.c --- linux-2.2.18pre21/net/sunrpc/sched.c Mon Nov 13 17:16:22 2000 +++ linux-2.2.18-sunrpc/net/sunrpc/sched.c Sat Nov 18 19:25:23 2000 @@ -259,7 +259,7 @@ printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n"); return; } - task->tk_running = 1; + rpc_set_running(task); if (RPC_IS_ASYNC(task)) { if (RPC_IS_SLEEPING(task)) { int status; @@ -267,12 +267,13 @@ if (status < 0) { printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); task->tk_status = status; - } else - task->tk_sleeping = 0; + return; + } + rpc_clear_sleeping(task); + wake_up(&rpciod_idle); } - wake_up(&rpciod_idle); } else { - task->tk_sleeping = 0; + rpc_clear_sleeping(task); wake_up(&task->tk_wait); } } @@ -287,7 +288,7 @@ if (RPC_IS_ACTIVATED(task)) return; task->tk_active = 1; - task->tk_sleeping = 1; + rpc_set_sleeping(task); __rpc_make_runnable(task); } @@ -327,7 +328,7 @@ /* Mark the task as being activated if so needed */ if (!RPC_IS_ACTIVATED(task)) { task->tk_active = 1; - task->tk_sleeping = 1; + rpc_set_sleeping(task); } status = __rpc_add_wait_queue(q, task); @@ -335,7 +336,7 @@ printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status); task->tk_status = status; } else { - task->tk_running = 0; + rpc_clear_running(task); task->tk_callback = action; __rpc_add_timer(task, timer); } @@ -609,21 +610,15 @@ /* * Check whether task is sleeping. - * Note that if the task goes to sleep in tk_action, - * and the RPC reply arrives before we get here, it will - * have state RUNNING, but will still be on schedq. - * 27/9/99: The above has been attempted fixed by - * introduction of task->tk_sleeping. */ spin_lock_irqsave(&rpc_queue_lock, oldflags); if (!RPC_IS_RUNNING(task)) { - task->tk_sleeping = 1; + rpc_set_sleeping(task); if (RPC_IS_ASYNC(task)) { spin_unlock_irqrestore(&rpc_queue_lock, oldflags); return 0; } - } else - task->tk_sleeping = 0; + } spin_unlock_irqrestore(&rpc_queue_lock, oldflags); while (RPC_IS_SLEEPING(task)) { @@ -689,18 +684,23 @@ 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_running = 1; if (task->tk_active) { printk(KERN_ERR "RPC: active task was run twice!\n"); - return -EWOULDBLOCK; + goto out_err; } task->tk_active = 1; + rpc_set_running(task); return __rpc_execute(task); + out_release: + rpc_release_task(task); + out_err: + return status; } /* diff -u --recursive --new-file linux-2.2.18pre21/net/sunrpc/svcsock.c linux-2.2.18-sunrpc/net/sunrpc/svcsock.c --- linux-2.2.18pre21/net/sunrpc/svcsock.c Mon Nov 13 17:16:22 2000 +++ linux-2.2.18-sunrpc/net/sunrpc/svcsock.c Sat Nov 18 21:48:37 2000 @@ -141,12 +141,9 @@ { struct svc_sock *svsk; - start_bh_atomic(); - if ((svsk = serv->sv_sockets) != NULL) + if ((svsk = serv->sv_sockets) != NULL) { rpc_remove_list(&serv->sv_sockets, svsk); - end_bh_atomic(); - if (svsk) { dprintk("svc: socket %p dequeued, inuse=%d\n", svsk->sk_sk, atomic_read(&svsk->sk_inuse)); svsk->sk_qued = 0; @@ -162,14 +159,12 @@ static inline void svc_sock_received(struct svc_sock *svsk, int count) { + if (count) + atomic_dec(&svsk->sk_data); start_bh_atomic(); - if ((svsk->sk_data -= count) < 0) { - printk(KERN_NOTICE "svc: sk_data negative!\n"); - svsk->sk_data = 0; - } svsk->sk_rqstp = NULL; /* XXX */ svsk->sk_busy = 0; - if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) { + if (atomic_read(&svsk->sk_conn) || atomic_read(&svsk->sk_data) || svsk_is_closing(svsk)) { dprintk("svc: socket %p re-enqueued after receive\n", svsk->sk_sk); svc_sock_enqueue(svsk); @@ -185,8 +180,8 @@ { start_bh_atomic(); svsk->sk_busy = 0; - svsk->sk_conn--; - if (svsk->sk_conn || svsk->sk_data || svsk->sk_close) { + atomic_dec(&svsk->sk_conn); + if (atomic_read(&svsk->sk_conn) || atomic_read(&svsk->sk_data) || svsk_is_closing(svsk)) { dprintk("svc: socket %p re-enqueued after accept\n", svsk->sk_sk); svc_sock_enqueue(svsk); @@ -344,7 +339,7 @@ return; dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n", svsk, sk, count, svsk->sk_busy); - svsk->sk_data++; + atomic_inc(&svsk->sk_data); svc_sock_enqueue(svsk); wake_up_interruptible(sk->sleep); } @@ -359,7 +354,7 @@ struct svc_serv *serv = svsk->sk_server; struct sk_buff *skb; u32 *data; - int err, len, recvd = svsk->sk_data; + int err, len; if ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) goto out_err; @@ -398,7 +393,7 @@ dprintk("svc: recvfrom returned error %d\n", -err); svc_sock_received(svsk, 0); } else - svc_sock_received(svsk, recvd); + svc_sock_received(svsk, 1); return -EAGAIN; } @@ -457,7 +452,7 @@ printk("svc: socket %p: no user data\n", sk); return; } - svsk->sk_conn++; + atomic_inc(&svsk->sk_conn); svc_sock_enqueue(svsk); wake_up_interruptible(sk->sleep); } @@ -477,7 +472,7 @@ printk("svc: socket %p: no user data\n", sk); return; } - svsk->sk_close = 1; + svsk_set_close(svsk); svc_sock_enqueue(svsk); wake_up_interruptible(sk->sleep); } @@ -497,7 +492,7 @@ sk, sk->user_data); if (!(svsk = (struct svc_sock *)(sk->user_data))) return; - svsk->sk_data++; + atomic_inc(&svsk->sk_data); svc_sock_enqueue(svsk); } @@ -573,9 +568,11 @@ /* Precharge. Data may have arrived on the socket before we * installed the data_ready callback. */ - newsvsk->sk_data = 1; newsvsk->sk_temp = 1; + atomic_inc(&newsvsk->sk_data); + start_bh_atomic(); svc_sock_enqueue(newsvsk); + end_bh_atomic(); if (serv->sv_stats) serv->sv_stats->nettcpconn++; @@ -599,20 +596,21 @@ int len, ready, used; dprintk("svc: tcp_recv %p data %d conn %d close %d\n", - svsk, svsk->sk_data, svsk->sk_conn, svsk->sk_close); + svsk, atomic_read(&svsk->sk_data), + atomic_read(&svsk->sk_conn), svsk_is_closing(svsk)); - if (svsk->sk_close) { + if (svsk_is_closing(svsk)) { svc_delete_socket(svsk); return 0; } - if (svsk->sk_conn) { + if (atomic_read(&svsk->sk_conn)) { svc_tcp_accept(svsk); svc_sock_accepted(svsk); return 0; } - ready = svsk->sk_data; + ready = atomic_read(&svsk->sk_data); /* Receive data. If we haven't got the record length yet, get * the next four bytes. Otherwise try to gobble up as much as @@ -648,14 +646,14 @@ if (len < svsk->sk_reclen) { dprintk("svc: incomplete TCP record (%d of %d)\n", len, svsk->sk_reclen); - svc_sock_received(svsk, ready); + svc_sock_received(svsk, 1); return -EAGAIN; /* record not complete */ } /* if we think there is only one more record to read, but * it is bigger than we expect, then two records must have arrived * together, so pretend we aren't using the record.. */ - if (len > svsk->sk_reclen && ready == 1){ + if (len > svsk->sk_reclen) { used = 0; dprintk("svc_recv: more data at hte socket len %d > svsk->sk_reclen %d", len, svsk->sk_reclen); @@ -688,7 +686,7 @@ svsk->sk_reclen = 0; svsk->sk_tcplen = 0; - svc_sock_received(svsk, used); + svc_sock_received(svsk, 1); if (serv->sv_stats) serv->sv_stats->nettcpcnt++; @@ -697,7 +695,7 @@ error: if (len == -EAGAIN) { dprintk("RPC: TCP recvfrom got EAGAIN\n"); - svc_sock_received(svsk, ready); /* Clear data ready */ + svc_sock_received(svsk, 1); /* Clear data ready */ } else { printk(KERN_NOTICE "%s: recvfrom returned errno %d\n", svsk->sk_server->sv_name, -len); diff -u --recursive --new-file linux-2.2.18pre21/net/sunrpc/xprt.c linux-2.2.18-sunrpc/net/sunrpc/xprt.c --- linux-2.2.18pre21/net/sunrpc/xprt.c Mon Nov 13 17:16:23 2000 +++ linux-2.2.18-sunrpc/net/sunrpc/xprt.c Sun Nov 19 17:57:20 2000 @@ -1010,7 +1010,8 @@ switch (sk->state) { case TCP_ESTABLISHED: - xprt_set_connected(xprt); + if (xprt_test_and_set_connected(xprt)) + break; if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); rpc_wake_up(&xprt->reconn); @@ -1045,16 +1046,14 @@ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; - spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (xprt->write_space) - goto out_unlock; - - xprt->write_space = 1; + if (xprt_test_and_set_wspace(xprt)) + goto out; + spin_lock_irqsave(&xprt_sock_lock, oldflags); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); - out_unlock: spin_unlock_irqrestore(&xprt_sock_lock, oldflags); + out: wake_up_interruptible(sk->sleep); } @@ -1073,16 +1072,14 @@ if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) return; - spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (xprt->write_space) - goto out_unlock; - - xprt->write_space = 1; + if (xprt_test_and_set_wspace(xprt)) + goto out; + spin_lock_irqsave(&xprt_sock_lock, oldflags); if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending) rpc_wake_up_task(xprt->snd_task); - out_unlock: spin_unlock_irqrestore(&xprt_sock_lock, oldflags); + out: wake_up_interruptible(sk->sleep); } @@ -1209,7 +1206,7 @@ if (!xprt->inet) break; - xprt->write_space = 0; + xprt_clear_wspace(xprt); status = -ENOMEM; if (sock_wspace(xprt->inet) < req->rq_slen + MIN_WRITE_SPACE) break; @@ -1256,7 +1253,7 @@ case -ENOMEM: /* Protect against (udp|tcp)_write_space */ spin_lock_irqsave(&xprt_sock_lock, oldflags); - if (!xprt->write_space) { + if (!xprt_wspace(xprt)) { task->tk_timeout = req->rq_timeout.to_current; rpc_sleep_on(&xprt->sending, task, NULL, NULL); } @@ -1297,7 +1294,7 @@ dprintk("RPC: %4d xprt_receive\n", task->tk_pid); - req->rq_received= 0; + req->rq_received = 0; task->tk_timeout = 0; rpc_sleep_locked(&xprt->pending, task, NULL, NULL); }