2005-08-12 00:25:23 +04:00
/*
* linux / net / sunrpc / xprtsock . c
*
* Client - side transport implementation for sockets .
*
2008-10-14 06:01:08 +04:00
* TCP callback races fixes ( C ) 1998 Red Hat
* TCP send fixes ( C ) 1998 Red Hat
2005-08-12 00:25:23 +04:00
* TCP NFS related read + write fixes
* ( C ) 1999 Dave Airlie , University of Limerick , Ireland < airlied @ linux . ie >
*
* Rewrite of larges part of the code in order to stabilize TCP stuff .
* Fix behaviour when socket buffer is full .
* ( C ) 1999 Trond Myklebust < trond . myklebust @ fys . uio . no >
2005-08-12 00:25:47 +04:00
*
* IP socket transport implementation , ( C ) 2005 Chuck Lever < cel @ netapp . com >
2007-08-06 19:57:53 +04:00
*
* IPv6 support contributed by Gilles Quillard , Bull Open Source , 2005.
* < gilles . quillard @ bull . net >
2005-08-12 00:25:23 +04:00
*/
# include <linux/types.h>
# include <linux/slab.h>
2007-09-10 21:46:39 +04:00
# include <linux/module.h>
2005-08-12 00:25:23 +04:00
# include <linux/capability.h>
# include <linux/pagemap.h>
# include <linux/errno.h>
# include <linux/socket.h>
# include <linux/in.h>
# include <linux/net.h>
# include <linux/mm.h>
# include <linux/udp.h>
# include <linux/tcp.h>
# include <linux/sunrpc/clnt.h>
2006-01-03 11:55:49 +03:00
# include <linux/sunrpc/sched.h>
2007-09-10 21:47:31 +04:00
# include <linux/sunrpc/xprtsock.h>
2005-08-12 00:25:23 +04:00
# include <linux/file.h>
# include <net/sock.h>
# include <net/checksum.h>
# include <net/udp.h>
# include <net/tcp.h>
2005-11-01 20:24:48 +03:00
/*
* xprtsock tunables
*/
unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE ;
unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE ;
unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT ;
unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT ;
2009-03-11 21:38:03 +03:00
# define XS_TCP_LINGER_TO (15U * HZ)
2009-03-11 21:38:03 +03:00
static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO ;
2009-03-11 21:38:03 +03:00
2006-12-06 00:35:54 +03:00
/*
* We can register our own files under / proc / sys / sunrpc by
* calling register_sysctl_table ( ) again . The files in that
* directory become the union of all files registered there .
*
* We simply need to make sure that we don ' t collide with
* someone else ' s file names !
*/
# ifdef RPC_DEBUG
static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE ;
static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE ;
static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT ;
static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT ;
static struct ctl_table_header * sunrpc_table_header ;
/*
* FIXME : changing the UDP slot table size should also resize the UDP
* socket buffers for existing UDP transports
*/
static ctl_table xs_tunables_table [ ] = {
{
. ctl_name = CTL_SLOTTABLE_UDP ,
. procname = " udp_slot_table_entries " ,
. data = & xprt_udp_slot_table_entries ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec_minmax ,
. strategy = & sysctl_intvec ,
. extra1 = & min_slot_table_size ,
. extra2 = & max_slot_table_size
} ,
{
. ctl_name = CTL_SLOTTABLE_TCP ,
. procname = " tcp_slot_table_entries " ,
. data = & xprt_tcp_slot_table_entries ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec_minmax ,
. strategy = & sysctl_intvec ,
. extra1 = & min_slot_table_size ,
. extra2 = & max_slot_table_size
} ,
{
. ctl_name = CTL_MIN_RESVPORT ,
. procname = " min_resvport " ,
. data = & xprt_min_resvport ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec_minmax ,
. strategy = & sysctl_intvec ,
. extra1 = & xprt_min_resvport_limit ,
. extra2 = & xprt_max_resvport_limit
} ,
{
. ctl_name = CTL_MAX_RESVPORT ,
. procname = " max_resvport " ,
. data = & xprt_max_resvport ,
. maxlen = sizeof ( unsigned int ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec_minmax ,
. strategy = & sysctl_intvec ,
. extra1 = & xprt_min_resvport_limit ,
. extra2 = & xprt_max_resvport_limit
} ,
2009-03-11 21:38:03 +03:00
{
. procname = " tcp_fin_timeout " ,
. data = & xs_tcp_fin_timeout ,
. maxlen = sizeof ( xs_tcp_fin_timeout ) ,
. mode = 0644 ,
. proc_handler = & proc_dointvec_jiffies ,
. strategy = sysctl_jiffies
} ,
2006-12-06 00:35:54 +03:00
{
. ctl_name = 0 ,
} ,
} ;
static ctl_table sunrpc_table [ ] = {
{
. ctl_name = CTL_SUNRPC ,
. procname = " sunrpc " ,
. mode = 0555 ,
. child = xs_tunables_table
} ,
{
. ctl_name = 0 ,
} ,
} ;
# endif
2005-08-26 03:25:55 +04:00
/*
* Time out for an RPC UDP socket connect . UDP socket connects are
* synchronous , but we set a timeout anyway in case of resource
* exhaustion on the local host .
*/
# define XS_UDP_CONN_TO (5U * HZ)
/*
* Wait duration for an RPC TCP connection to be established . Solaris
* NFS over TCP uses 60 seconds , for example , which is in line with how
* long a server takes to reboot .
*/
# define XS_TCP_CONN_TO (60U * HZ)
/*
* Wait duration for a reply from the RPC portmapper .
*/
# define XS_BIND_TO (60U * HZ)
/*
* Delay if a UDP socket connect error occurs . This is most likely some
* kind of resource problem on the local host .
*/
# define XS_UDP_REEST_TO (2U * HZ)
/*
* The reestablish timeout allows clients to delay for a bit before attempting
* to reconnect to a server that just dropped our connection .
*
* We implement an exponential backoff when trying to reestablish a TCP
* transport connection with the server . Some servers like to drop a TCP
* connection when they are overworked , so we start with a short timeout and
* increase over time if the server is down or not responding .
*/
# define XS_TCP_INIT_REEST_TO (3U * HZ)
# define XS_TCP_MAX_REEST_TO (5U * 60 * HZ)
/*
* TCP idle timeout ; client drops the transport socket if it is idle
* for this long . Note that we also timeout UDP sockets to prevent
* holding port numbers when there is no RPC traffic .
*/
# define XS_IDLE_DISC_TO (5U * 60 * HZ)
2005-08-12 00:25:23 +04:00
# ifdef RPC_DEBUG
# undef RPC_DEBUG_DATA
2005-08-12 00:25:26 +04:00
# define RPCDBG_FACILITY RPCDBG_TRANS
2005-08-12 00:25:23 +04:00
# endif
# ifdef RPC_DEBUG_DATA
2005-08-12 00:25:26 +04:00
static void xs_pktdump ( char * msg , u32 * packet , unsigned int count )
2005-08-12 00:25:23 +04:00
{
2005-08-12 00:25:26 +04:00
u8 * buf = ( u8 * ) packet ;
int j ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %s \n " , msg ) ;
2005-08-12 00:25:23 +04:00
for ( j = 0 ; j < count & & j < 128 ; j + = 4 ) {
if ( ! ( j & 31 ) ) {
if ( j )
dprintk ( " \n " ) ;
dprintk ( " 0x%04x " , j ) ;
}
dprintk ( " %02x%02x%02x%02x " ,
buf [ j ] , buf [ j + 1 ] , buf [ j + 2 ] , buf [ j + 3 ] ) ;
}
dprintk ( " \n " ) ;
}
# else
2005-08-12 00:25:26 +04:00
static inline void xs_pktdump ( char * msg , u32 * packet , unsigned int count )
2005-08-12 00:25:23 +04:00
{
/* NOP */
}
# endif
2006-12-06 00:35:11 +03:00
struct sock_xprt {
struct rpc_xprt xprt ;
2006-12-06 00:35:15 +03:00
/*
* Network layer
*/
struct socket * sock ;
struct sock * inet ;
2006-12-06 00:35:19 +03:00
/*
* State of TCP reply receive
*/
__be32 tcp_fraghdr ,
tcp_xid ;
u32 tcp_offset ,
tcp_reclen ;
unsigned long tcp_copied ,
tcp_flags ;
2006-12-06 00:35:26 +03:00
/*
* Connection of transports
*/
2006-12-07 23:48:15 +03:00
struct delayed_work connect_worker ;
2007-07-10 00:23:35 +04:00
struct sockaddr_storage addr ;
2006-12-06 00:35:26 +03:00
unsigned short port ;
2006-12-06 00:35:30 +03:00
/*
* UDP socket buffer size parameters
*/
size_t rcvsize ,
sndsize ;
2006-12-06 00:35:34 +03:00
/*
* Saved socket callback addresses
*/
void ( * old_data_ready ) ( struct sock * , int ) ;
void ( * old_state_change ) ( struct sock * ) ;
void ( * old_write_space ) ( struct sock * ) ;
2008-10-28 22:21:39 +03:00
void ( * old_error_report ) ( struct sock * ) ;
2006-12-06 00:35:11 +03:00
} ;
2006-12-06 00:35:23 +03:00
/*
* TCP receive state flags
*/
# define TCP_RCV_LAST_FRAG (1UL << 0)
# define TCP_RCV_COPY_FRAGHDR (1UL << 1)
# define TCP_RCV_COPY_XID (1UL << 2)
# define TCP_RCV_COPY_DATA (1UL << 3)
2007-08-06 19:57:58 +04:00
static inline struct sockaddr * xs_addr ( struct rpc_xprt * xprt )
{
return ( struct sockaddr * ) & xprt - > addr ;
}
static inline struct sockaddr_in * xs_addr_in ( struct rpc_xprt * xprt )
2006-08-23 04:06:18 +04:00
{
2007-08-06 19:57:58 +04:00
return ( struct sockaddr_in * ) & xprt - > addr ;
}
static inline struct sockaddr_in6 * xs_addr_in6 ( struct rpc_xprt * xprt )
{
return ( struct sockaddr_in6 * ) & xprt - > addr ;
}
2008-01-08 02:34:48 +03:00
static void xs_format_ipv4_peer_addresses ( struct rpc_xprt * xprt ,
const char * protocol ,
const char * netid )
2006-08-23 04:06:18 +04:00
{
2007-08-06 19:57:58 +04:00
struct sockaddr_in * addr = xs_addr_in ( xprt ) ;
2006-08-23 04:06:18 +04:00
char * buf ;
buf = kzalloc ( 20 , GFP_KERNEL ) ;
if ( buf ) {
2008-11-03 10:57:06 +03:00
snprintf ( buf , 20 , " %pI4 " , & addr - > sin_addr . s_addr ) ;
2006-08-23 04:06:18 +04:00
}
xprt - > address_strings [ RPC_DISPLAY_ADDR ] = buf ;
buf = kzalloc ( 8 , GFP_KERNEL ) ;
if ( buf ) {
snprintf ( buf , 8 , " %u " ,
ntohs ( addr - > sin_port ) ) ;
}
xprt - > address_strings [ RPC_DISPLAY_PORT ] = buf ;
2008-01-08 02:34:48 +03:00
xprt - > address_strings [ RPC_DISPLAY_PROTO ] = protocol ;
2006-08-23 04:06:18 +04:00
buf = kzalloc ( 48 , GFP_KERNEL ) ;
if ( buf ) {
2008-10-31 10:54:56 +03:00
snprintf ( buf , 48 , " addr=%pI4 port=%u proto=%s " ,
& addr - > sin_addr . s_addr ,
2006-08-23 04:06:18 +04:00
ntohs ( addr - > sin_port ) ,
2008-01-08 02:34:48 +03:00
protocol ) ;
2006-08-23 04:06:18 +04:00
}
xprt - > address_strings [ RPC_DISPLAY_ALL ] = buf ;
2007-08-06 19:57:02 +04:00
buf = kzalloc ( 10 , GFP_KERNEL ) ;
if ( buf ) {
snprintf ( buf , 10 , " %02x%02x%02x%02x " ,
NIPQUAD ( addr - > sin_addr . s_addr ) ) ;
}
xprt - > address_strings [ RPC_DISPLAY_HEX_ADDR ] = buf ;
buf = kzalloc ( 8 , GFP_KERNEL ) ;
if ( buf ) {
snprintf ( buf , 8 , " %4hx " ,
ntohs ( addr - > sin_port ) ) ;
}
xprt - > address_strings [ RPC_DISPLAY_HEX_PORT ] = buf ;
2007-08-17 00:03:26 +04:00
buf = kzalloc ( 30 , GFP_KERNEL ) ;
if ( buf ) {
2008-10-31 10:54:56 +03:00
snprintf ( buf , 30 , " %pI4.%u.%u " ,
& addr - > sin_addr . s_addr ,
2007-08-17 00:03:26 +04:00
ntohs ( addr - > sin_port ) > > 8 ,
ntohs ( addr - > sin_port ) & 0xff ) ;
}
xprt - > address_strings [ RPC_DISPLAY_UNIVERSAL_ADDR ] = buf ;
2007-09-10 21:43:05 +04:00
2008-01-08 02:34:48 +03:00
xprt - > address_strings [ RPC_DISPLAY_NETID ] = netid ;
2006-08-23 04:06:18 +04:00
}
2008-01-08 02:34:48 +03:00
static void xs_format_ipv6_peer_addresses ( struct rpc_xprt * xprt ,
const char * protocol ,
const char * netid )
2007-08-06 19:57:12 +04:00
{
2007-08-06 19:57:58 +04:00
struct sockaddr_in6 * addr = xs_addr_in6 ( xprt ) ;
2007-08-06 19:57:12 +04:00
char * buf ;
buf = kzalloc ( 40 , GFP_KERNEL ) ;
if ( buf ) {
2008-10-29 22:52:50 +03:00
snprintf ( buf , 40 , " %pI6 " , & addr - > sin6_addr ) ;
2007-08-06 19:57:12 +04:00
}
xprt - > address_strings [ RPC_DISPLAY_ADDR ] = buf ;
buf = kzalloc ( 8 , GFP_KERNEL ) ;
if ( buf ) {
snprintf ( buf , 8 , " %u " ,
ntohs ( addr - > sin6_port ) ) ;
}
xprt - > address_strings [ RPC_DISPLAY_PORT ] = buf ;
2008-01-08 02:34:48 +03:00
xprt - > address_strings [ RPC_DISPLAY_PROTO ] = protocol ;
2007-08-06 19:57:12 +04:00
buf = kzalloc ( 64 , GFP_KERNEL ) ;
if ( buf ) {
2008-10-29 22:52:50 +03:00
snprintf ( buf , 64 , " addr=%pI6 port=%u proto=%s " ,
2008-10-29 02:10:17 +03:00
& addr - > sin6_addr ,
2007-08-06 19:57:12 +04:00
ntohs ( addr - > sin6_port ) ,
2008-01-08 02:34:48 +03:00
protocol ) ;
2007-08-06 19:57:12 +04:00
}
xprt - > address_strings [ RPC_DISPLAY_ALL ] = buf ;
buf = kzalloc ( 36 , GFP_KERNEL ) ;
2008-10-29 02:05:40 +03:00
if ( buf )
2008-10-29 22:50:24 +03:00
snprintf ( buf , 36 , " %pi6 " , & addr - > sin6_addr ) ;
2008-10-29 02:05:40 +03:00
2007-08-06 19:57:12 +04:00
xprt - > address_strings [ RPC_DISPLAY_HEX_ADDR ] = buf ;
buf = kzalloc ( 8 , GFP_KERNEL ) ;
if ( buf ) {
snprintf ( buf , 8 , " %4hx " ,
ntohs ( addr - > sin6_port ) ) ;
}
xprt - > address_strings [ RPC_DISPLAY_HEX_PORT ] = buf ;
2007-08-17 00:03:26 +04:00
buf = kzalloc ( 50 , GFP_KERNEL ) ;
if ( buf ) {
2008-10-29 22:52:50 +03:00
snprintf ( buf , 50 , " %pI6.%u.%u " ,
2008-10-29 02:10:17 +03:00
& addr - > sin6_addr ,
ntohs ( addr - > sin6_port ) > > 8 ,
ntohs ( addr - > sin6_port ) & 0xff ) ;
2007-08-17 00:03:26 +04:00
}
xprt - > address_strings [ RPC_DISPLAY_UNIVERSAL_ADDR ] = buf ;
2007-09-10 21:43:05 +04:00
2008-01-08 02:34:48 +03:00
xprt - > address_strings [ RPC_DISPLAY_NETID ] = netid ;
2006-08-23 04:06:18 +04:00
}
static void xs_free_peer_addresses ( struct rpc_xprt * xprt )
{
2008-01-14 20:32:20 +03:00
unsigned int i ;
for ( i = 0 ; i < RPC_DISPLAY_MAX ; i + + )
switch ( i ) {
case RPC_DISPLAY_PROTO :
case RPC_DISPLAY_NETID :
continue ;
default :
kfree ( xprt - > address_strings [ i ] ) ;
}
2006-08-23 04:06:18 +04:00
}
2005-08-12 00:25:29 +04:00
# define XS_SENDMSG_FLAGS (MSG_DONTWAIT | MSG_NOSIGNAL)
2006-10-17 23:06:22 +04:00
static int xs_send_kvec ( struct socket * sock , struct sockaddr * addr , int addrlen , struct kvec * vec , unsigned int base , int more )
2005-08-12 00:25:29 +04:00
{
struct msghdr msg = {
. msg_name = addr ,
. msg_namelen = addrlen ,
2006-10-17 23:06:22 +04:00
. msg_flags = XS_SENDMSG_FLAGS | ( more ? MSG_MORE : 0 ) ,
} ;
struct kvec iov = {
. iov_base = vec - > iov_base + base ,
. iov_len = vec - > iov_len - base ,
2005-08-12 00:25:29 +04:00
} ;
2006-10-17 23:06:22 +04:00
if ( iov . iov_len ! = 0 )
2005-08-12 00:25:29 +04:00
return kernel_sendmsg ( sock , & msg , & iov , 1 , iov . iov_len ) ;
return kernel_sendmsg ( sock , & msg , NULL , 0 , 0 ) ;
}
2006-10-17 23:06:22 +04:00
static int xs_send_pagedata ( struct socket * sock , struct xdr_buf * xdr , unsigned int base , int more )
2005-08-12 00:25:29 +04:00
{
2006-10-17 23:06:22 +04:00
struct page * * ppage ;
unsigned int remainder ;
int err , sent = 0 ;
remainder = xdr - > page_len - base ;
base + = xdr - > page_base ;
ppage = xdr - > pages + ( base > > PAGE_SHIFT ) ;
base & = ~ PAGE_MASK ;
for ( ; ; ) {
unsigned int len = min_t ( unsigned int , PAGE_SIZE - base , remainder ) ;
int flags = XS_SENDMSG_FLAGS ;
2005-08-12 00:25:29 +04:00
2006-10-17 23:06:22 +04:00
remainder - = len ;
if ( remainder ! = 0 | | more )
flags | = MSG_MORE ;
err = sock - > ops - > sendpage ( sock , * ppage , base , len , flags ) ;
if ( remainder = = 0 | | err ! = len )
break ;
sent + = err ;
ppage + + ;
base = 0 ;
}
if ( sent = = 0 )
return err ;
if ( err > 0 )
sent + = err ;
return sent ;
2005-08-12 00:25:29 +04:00
}
2005-08-12 00:25:26 +04:00
/**
* xs_sendpages - write pages directly to a socket
* @ sock : socket to send on
* @ addr : UDP only - - address of destination
* @ addrlen : UDP only - - length of destination address
* @ xdr : buffer containing this request
* @ base : starting position in the buffer
*
2005-08-12 00:25:23 +04:00
*/
2006-10-17 23:06:22 +04:00
static int xs_sendpages ( struct socket * sock , struct sockaddr * addr , int addrlen , struct xdr_buf * xdr , unsigned int base )
2005-08-12 00:25:23 +04:00
{
2006-10-17 23:06:22 +04:00
unsigned int remainder = xdr - > len - base ;
int err , sent = 0 ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
if ( unlikely ( ! sock ) )
2009-03-11 21:06:41 +03:00
return - ENOTSOCK ;
2005-08-12 00:25:56 +04:00
clear_bit ( SOCK_ASYNC_NOSPACE , & sock - > flags ) ;
2006-10-17 23:06:22 +04:00
if ( base ! = 0 ) {
addr = NULL ;
addrlen = 0 ;
}
2005-08-12 00:25:56 +04:00
2006-10-17 23:06:22 +04:00
if ( base < xdr - > head [ 0 ] . iov_len | | addr ! = NULL ) {
unsigned int len = xdr - > head [ 0 ] . iov_len - base ;
remainder - = len ;
err = xs_send_kvec ( sock , addr , addrlen , & xdr - > head [ 0 ] , base , remainder ! = 0 ) ;
if ( remainder = = 0 | | err ! = len )
2005-08-12 00:25:23 +04:00
goto out ;
2006-10-17 23:06:22 +04:00
sent + = err ;
2005-08-12 00:25:23 +04:00
base = 0 ;
} else
2006-10-17 23:06:22 +04:00
base - = xdr - > head [ 0 ] . iov_len ;
2005-08-12 00:25:23 +04:00
2006-10-17 23:06:22 +04:00
if ( base < xdr - > page_len ) {
unsigned int len = xdr - > page_len - base ;
remainder - = len ;
err = xs_send_pagedata ( sock , xdr , base , remainder ! = 0 ) ;
if ( remainder = = 0 | | err ! = len )
2005-08-12 00:25:23 +04:00
goto out ;
2006-10-17 23:06:22 +04:00
sent + = err ;
2005-08-12 00:25:23 +04:00
base = 0 ;
2006-10-17 23:06:22 +04:00
} else
base - = xdr - > page_len ;
if ( base > = xdr - > tail [ 0 ] . iov_len )
return sent ;
err = xs_send_kvec ( sock , NULL , 0 , & xdr - > tail [ 0 ] , base , 0 ) ;
2005-08-12 00:25:23 +04:00
out :
2006-10-17 23:06:22 +04:00
if ( sent = = 0 )
return err ;
if ( err > 0 )
sent + = err ;
return sent ;
2005-08-12 00:25:23 +04:00
}
2008-04-18 02:52:19 +04:00
static void xs_nospace_callback ( struct rpc_task * task )
{
struct sock_xprt * transport = container_of ( task - > tk_rqstp - > rq_xprt , struct sock_xprt , xprt ) ;
transport - > inet - > sk_write_pending - - ;
clear_bit ( SOCK_ASYNC_NOSPACE , & transport - > sock - > flags ) ;
}
2005-08-12 00:25:26 +04:00
/**
2005-08-12 00:25:56 +04:00
* xs_nospace - place task on wait queue if transmit was incomplete
* @ task : task to put to sleep
2005-08-12 00:25:26 +04:00
*
2005-08-12 00:25:23 +04:00
*/
2009-03-11 21:38:01 +03:00
static int xs_nospace ( struct rpc_task * task )
2005-08-12 00:25:23 +04:00
{
2005-08-12 00:25:56 +04:00
struct rpc_rqst * req = task - > tk_rqstp ;
struct rpc_xprt * xprt = req - > rq_xprt ;
2006-12-06 00:35:15 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2009-03-11 21:38:01 +03:00
int ret = 0 ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u xmit incomplete (%u left of %u) \n " ,
2005-08-12 00:25:56 +04:00
task - > tk_pid , req - > rq_slen - req - > rq_bytes_sent ,
req - > rq_slen ) ;
2008-04-18 02:52:19 +04:00
/* Protect against races with write_space */
spin_lock_bh ( & xprt - > transport_lock ) ;
/* Don't race with disconnect */
if ( xprt_connected ( xprt ) ) {
if ( test_bit ( SOCK_ASYNC_NOSPACE , & transport - > sock - > flags ) ) {
2009-03-11 21:38:01 +03:00
ret = - EAGAIN ;
2008-04-18 02:52:19 +04:00
/*
* Notify TCP that we ' re limited by the application
* window size
*/
set_bit ( SOCK_NOSPACE , & transport - > sock - > flags ) ;
transport - > inet - > sk_write_pending + + ;
/* ...and wait for more buffer space */
xprt_wait_for_buffer_space ( task , xs_nospace_callback ) ;
}
} else {
clear_bit ( SOCK_ASYNC_NOSPACE , & transport - > sock - > flags ) ;
2009-03-11 21:38:01 +03:00
ret = - ENOTCONN ;
2008-04-18 02:52:19 +04:00
}
2005-08-12 00:25:56 +04:00
2008-04-18 02:52:19 +04:00
spin_unlock_bh ( & xprt - > transport_lock ) ;
2009-03-11 21:38:01 +03:00
return ret ;
2005-08-12 00:25:56 +04:00
}
/**
* xs_udp_send_request - write an RPC request to a UDP socket
* @ task : address of RPC task that manages the state of an RPC request
*
* Return values :
* 0 : The request has been sent
* EAGAIN : The socket was blocked , please call again later to
* complete the request
* ENOTCONN : Caller needs to invoke connect logic then call again
* other : Some other error occured , the request was not sent
*/
static int xs_udp_send_request ( struct rpc_task * task )
{
struct rpc_rqst * req = task - > tk_rqstp ;
struct rpc_xprt * xprt = req - > rq_xprt ;
2006-12-06 00:35:15 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:56 +04:00
struct xdr_buf * xdr = & req - > rq_snd_buf ;
int status ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:26 +04:00
xs_pktdump ( " packet data: " ,
2005-08-12 00:25:23 +04:00
req - > rq_svec - > iov_base ,
req - > rq_svec - > iov_len ) ;
2009-03-11 21:09:39 +03:00
if ( ! xprt_bound ( xprt ) )
return - ENOTCONN ;
2006-12-06 00:35:15 +03:00
status = xs_sendpages ( transport - > sock ,
2007-08-06 19:57:58 +04:00
xs_addr ( xprt ) ,
2006-12-06 00:35:15 +03:00
xprt - > addrlen , xdr ,
req - > rq_bytes_sent ) ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_udp_send_request(%u) = %d \n " ,
2005-08-12 00:25:56 +04:00
xdr - > len - req - > rq_bytes_sent , status ) ;
2005-08-12 00:25:23 +04:00
2007-10-01 19:43:37 +04:00
if ( status > = 0 ) {
task - > tk_bytes_sent + = status ;
if ( status > = req - > rq_slen )
return 0 ;
/* Still some bytes left; set up for a retry later. */
2005-08-12 00:25:56 +04:00
status = - EAGAIN ;
2007-10-01 19:43:37 +04:00
}
2009-03-11 21:37:59 +03:00
if ( ! transport - > sock )
goto out ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
switch ( status ) {
2009-03-11 21:06:41 +03:00
case - ENOTSOCK :
status = - ENOTCONN ;
/* Should we call xs_close() here? */
break ;
2008-04-18 02:52:19 +04:00
case - EAGAIN :
2009-03-11 21:38:01 +03:00
status = xs_nospace ( task ) ;
2008-04-18 02:52:19 +04:00
break ;
2009-03-11 21:37:59 +03:00
default :
dprintk ( " RPC: sendmsg returned unrecognized error %d \n " ,
- status ) ;
2005-08-12 00:25:56 +04:00
case - ENETUNREACH :
case - EPIPE :
2005-08-12 00:25:23 +04:00
case - ECONNREFUSED :
/* When the server has died, an ICMP port unreachable message
2005-08-12 00:25:26 +04:00
* prompts ECONNREFUSED . */
2008-04-18 02:52:19 +04:00
clear_bit ( SOCK_ASYNC_NOSPACE , & transport - > sock - > flags ) ;
2005-08-12 00:25:23 +04:00
}
2009-03-11 21:37:59 +03:00
out :
2005-08-12 00:25:56 +04:00
return status ;
2005-08-12 00:25:23 +04:00
}
2007-11-05 23:44:12 +03:00
/**
* xs_tcp_shutdown - gracefully shut down a TCP socket
* @ xprt : transport
*
* Initiates a graceful shutdown of the TCP socket by calling the
* equivalent of shutdown ( SHUT_WR ) ;
*/
static void xs_tcp_shutdown ( struct rpc_xprt * xprt )
{
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
struct socket * sock = transport - > sock ;
if ( sock ! = NULL )
kernel_sock_shutdown ( sock , SHUT_WR ) ;
}
2005-08-26 03:25:49 +04:00
static inline void xs_encode_tcp_record_marker ( struct xdr_buf * buf )
{
u32 reclen = buf - > len - sizeof ( rpc_fraghdr ) ;
rpc_fraghdr * base = buf - > head [ 0 ] . iov_base ;
* base = htonl ( RPC_LAST_STREAM_FRAGMENT | reclen ) ;
}
2005-08-12 00:25:26 +04:00
/**
2005-08-12 00:25:56 +04:00
* xs_tcp_send_request - write an RPC request to a TCP socket
2005-08-12 00:25:26 +04:00
* @ task : address of RPC task that manages the state of an RPC request
*
* Return values :
2005-08-12 00:25:56 +04:00
* 0 : The request has been sent
* EAGAIN : The socket was blocked , please call again later to
* complete the request
* ENOTCONN : Caller needs to invoke connect logic then call again
* other : Some other error occured , the request was not sent
2005-08-12 00:25:26 +04:00
*
* XXX : In the case of soft timeouts , should we eventually give up
2005-08-12 00:25:56 +04:00
* if sendmsg is not able to make progress ?
2005-08-12 00:25:26 +04:00
*/
2005-08-12 00:25:56 +04:00
static int xs_tcp_send_request ( struct rpc_task * task )
2005-08-12 00:25:23 +04:00
{
struct rpc_rqst * req = task - > tk_rqstp ;
struct rpc_xprt * xprt = req - > rq_xprt ;
2006-12-06 00:35:15 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:56 +04:00
struct xdr_buf * xdr = & req - > rq_snd_buf ;
2007-08-06 19:56:42 +04:00
int status ;
2005-08-12 00:25:23 +04:00
2005-08-26 03:25:49 +04:00
xs_encode_tcp_record_marker ( & req - > rq_snd_buf ) ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
xs_pktdump ( " packet data: " ,
req - > rq_svec - > iov_base ,
req - > rq_svec - > iov_len ) ;
2005-08-12 00:25:23 +04:00
/* Continue transmitting the packet/record. We must be careful
* to cope with writespace callbacks arriving _after_ we have
2005-08-12 00:25:56 +04:00
* called sendmsg ( ) . */
2005-08-12 00:25:23 +04:00
while ( 1 ) {
2006-12-06 00:35:15 +03:00
status = xs_sendpages ( transport - > sock ,
NULL , 0 , xdr , req - > rq_bytes_sent ) ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_tcp_send_request(%u) = %d \n " ,
2005-08-12 00:25:56 +04:00
xdr - > len - req - > rq_bytes_sent , status ) ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
if ( unlikely ( status < 0 ) )
2005-08-12 00:25:23 +04:00
break ;
2005-08-12 00:25:56 +04:00
/* If we've sent the entire packet, immediately
* reset the count of bytes sent . */
req - > rq_bytes_sent + = status ;
2006-03-20 21:44:17 +03:00
task - > tk_bytes_sent + = status ;
2005-08-12 00:25:56 +04:00
if ( likely ( req - > rq_bytes_sent > = req - > rq_slen ) ) {
req - > rq_bytes_sent = 0 ;
return 0 ;
}
2005-08-12 00:25:23 +04:00
2008-04-17 00:51:38 +04:00
if ( status ! = 0 )
continue ;
2005-08-12 00:25:23 +04:00
status = - EAGAIN ;
2008-04-17 00:51:38 +04:00
break ;
2005-08-12 00:25:23 +04:00
}
2009-03-11 21:37:59 +03:00
if ( ! transport - > sock )
goto out ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
switch ( status ) {
2009-03-11 21:06:41 +03:00
case - ENOTSOCK :
status = - ENOTCONN ;
/* Should we call xs_close() here? */
break ;
2005-08-12 00:25:56 +04:00
case - EAGAIN :
2009-03-11 21:38:01 +03:00
status = xs_nospace ( task ) ;
2005-08-12 00:25:56 +04:00
break ;
2009-03-11 21:37:59 +03:00
default :
dprintk ( " RPC: sendmsg returned unrecognized error %d \n " ,
- status ) ;
2005-08-12 00:25:56 +04:00
case - ECONNRESET :
2009-03-11 22:29:24 +03:00
case - EPIPE :
2008-10-28 22:21:39 +03:00
xs_tcp_shutdown ( xprt ) ;
case - ECONNREFUSED :
2005-08-12 00:25:56 +04:00
case - ENOTCONN :
2008-04-18 02:52:19 +04:00
clear_bit ( SOCK_ASYNC_NOSPACE , & transport - > sock - > flags ) ;
2005-08-12 00:25:23 +04:00
}
2009-03-11 21:37:59 +03:00
out :
2005-08-12 00:25:23 +04:00
return status ;
}
2006-07-28 01:22:50 +04:00
/**
* 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 ) ;
}
2008-10-28 22:21:39 +03:00
static void xs_save_old_callbacks ( struct sock_xprt * transport , struct sock * sk )
{
transport - > old_data_ready = sk - > sk_data_ready ;
transport - > old_state_change = sk - > sk_state_change ;
transport - > old_write_space = sk - > sk_write_space ;
transport - > old_error_report = sk - > sk_error_report ;
}
static void xs_restore_old_callbacks ( struct sock_xprt * transport , struct sock * sk )
{
sk - > sk_data_ready = transport - > old_data_ready ;
sk - > sk_state_change = transport - > old_state_change ;
sk - > sk_write_space = transport - > old_write_space ;
sk - > sk_error_report = transport - > old_error_report ;
}
2009-03-11 21:10:21 +03:00
static void xs_reset_transport ( struct sock_xprt * transport )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:15 +03:00
struct socket * sock = transport - > sock ;
struct sock * sk = transport - > inet ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:10:21 +03:00
if ( sk = = NULL )
return ;
2005-08-12 00:25:26 +04:00
2005-08-12 00:25:23 +04:00
write_lock_bh ( & sk - > sk_callback_lock ) ;
2006-12-06 00:35:15 +03:00
transport - > inet = NULL ;
transport - > sock = NULL ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:26 +04:00
sk - > sk_user_data = NULL ;
2008-10-28 22:21:39 +03:00
xs_restore_old_callbacks ( transport , sk ) ;
2005-08-12 00:25:23 +04:00
write_unlock_bh ( & sk - > sk_callback_lock ) ;
2005-08-12 00:25:26 +04:00
sk - > sk_no_check = 0 ;
2005-08-12 00:25:23 +04:00
sock_release ( sock ) ;
2009-03-11 21:10:21 +03:00
}
/**
* xs_close - close a socket
* @ xprt : transport
*
* This is used when all requests are complete ; ie , no DRC state remains
* on the server we want to save .
2009-04-22 01:18:20 +04:00
*
* The caller _must_ be holding XPRT_LOCKED in order to avoid issues with
* xs_reset_transport ( ) zeroing the socket from underneath a writer .
2009-03-11 21:10:21 +03:00
*/
static void xs_close ( struct rpc_xprt * xprt )
{
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
dprintk ( " RPC: xs_close xprt %p \n " , xprt ) ;
xs_reset_transport ( transport ) ;
2006-01-03 11:55:55 +03:00
smp_mb__before_clear_bit ( ) ;
2009-03-11 21:38:03 +03:00
clear_bit ( XPRT_CONNECTION_ABORT , & xprt - > state ) ;
2006-01-03 11:55:55 +03:00
clear_bit ( XPRT_CLOSE_WAIT , & xprt - > state ) ;
2007-11-06 01:42:39 +03:00
clear_bit ( XPRT_CLOSING , & xprt - > state ) ;
2006-01-03 11:55:55 +03:00
smp_mb__after_clear_bit ( ) ;
2007-11-07 02:44:20 +03:00
xprt_disconnect_done ( xprt ) ;
2005-08-12 00:25:23 +04:00
}
2009-04-22 01:18:20 +04:00
static void xs_tcp_close ( struct rpc_xprt * xprt )
{
if ( test_and_clear_bit ( XPRT_CONNECTION_CLOSE , & xprt - > state ) )
xs_close ( xprt ) ;
else
xs_tcp_shutdown ( xprt ) ;
}
2005-08-12 00:25:26 +04:00
/**
* xs_destroy - prepare to shutdown a transport
* @ xprt : doomed transport
*
*/
static void xs_destroy ( struct rpc_xprt * xprt )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:26 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_destroy xprt %p \n " , xprt ) ;
2005-08-12 00:25:26 +04:00
2007-06-15 02:00:42 +04:00
cancel_rearming_delayed_work ( & transport - > connect_worker ) ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:26 +04:00
xs_close ( xprt ) ;
2006-08-23 04:06:18 +04:00
xs_free_peer_addresses ( xprt ) ;
2005-08-12 00:25:23 +04:00
kfree ( xprt - > slot ) ;
2006-10-17 22:44:27 +04:00
kfree ( xprt ) ;
2007-09-10 21:46:39 +04:00
module_put ( THIS_MODULE ) ;
2005-08-12 00:25:23 +04:00
}
2005-08-12 00:25:26 +04:00
static inline struct rpc_xprt * xprt_from_sock ( struct sock * sk )
{
return ( struct rpc_xprt * ) sk - > sk_user_data ;
}
/**
* xs_udp_data_ready - " data ready " callback for UDP sockets
* @ sk : socket with data to read
* @ len : how much data to read
*
2005-08-12 00:25:23 +04:00
*/
2005-08-12 00:25:26 +04:00
static void xs_udp_data_ready ( struct sock * sk , int len )
2005-08-12 00:25:23 +04:00
{
2005-08-12 00:25:26 +04:00
struct rpc_task * task ;
struct rpc_xprt * xprt ;
2005-08-12 00:25:23 +04:00
struct rpc_rqst * rovr ;
2005-08-12 00:25:26 +04:00
struct sk_buff * skb ;
2005-08-12 00:25:23 +04:00
int err , repsize , copied ;
2006-09-27 09:29:38 +04:00
u32 _xid ;
__be32 * xp ;
2005-08-12 00:25:23 +04:00
read_lock ( & sk - > sk_callback_lock ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_udp_data_ready... \n " ) ;
2005-08-12 00:25:26 +04:00
if ( ! ( xprt = xprt_from_sock ( sk ) ) )
2005-08-12 00:25:23 +04:00
goto out ;
if ( ( skb = skb_recv_datagram ( sk , 0 , 1 , & err ) ) = = NULL )
goto out ;
if ( xprt - > shutdown )
goto dropit ;
repsize = skb - > len - sizeof ( struct udphdr ) ;
if ( repsize < 4 ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: impossible RPC reply size %d! \n " , repsize ) ;
2005-08-12 00:25:23 +04:00
goto dropit ;
}
/* Copy the XID from the skb... */
xp = skb_header_pointer ( skb , sizeof ( struct udphdr ) ,
sizeof ( _xid ) , & _xid ) ;
if ( xp = = NULL )
goto dropit ;
/* Look up and lock the request corresponding to the given XID */
2005-08-12 00:25:32 +04:00
spin_lock ( & xprt - > transport_lock ) ;
2005-08-12 00:25:23 +04:00
rovr = xprt_lookup_rqst ( xprt , * xp ) ;
if ( ! rovr )
goto out_unlock ;
task = rovr - > rq_task ;
if ( ( copied = rovr - > rq_private_buf . buflen ) > repsize )
copied = repsize ;
/* Suck it into the iovec, verify checksum if not done by hw. */
2007-12-11 22:30:32 +03:00
if ( csum_partial_copy_to_xdr ( & rovr - > rq_private_buf , skb ) ) {
UDPX_INC_STATS_BH ( sk , UDP_MIB_INERRORS ) ;
2005-08-12 00:25:23 +04:00
goto out_unlock ;
2007-12-11 22:30:32 +03:00
}
UDPX_INC_STATS_BH ( sk , UDP_MIB_INDATAGRAMS ) ;
2005-08-12 00:25:23 +04:00
/* Something worked... */
dst_confirm ( skb - > dst ) ;
2005-08-26 03:25:52 +04:00
xprt_adjust_cwnd ( task , copied ) ;
xprt_update_rtt ( task ) ;
xprt_complete_rqst ( task , copied ) ;
2005-08-12 00:25:23 +04:00
out_unlock :
2005-08-12 00:25:32 +04:00
spin_unlock ( & xprt - > transport_lock ) ;
2005-08-12 00:25:23 +04:00
dropit :
skb_free_datagram ( sk , skb ) ;
out :
read_unlock ( & sk - > sk_callback_lock ) ;
}
2006-12-06 00:35:44 +03:00
static inline void xs_tcp_read_fraghdr ( struct rpc_xprt * xprt , struct xdr_skb_reader * desc )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:19 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
size_t len , used ;
char * p ;
2006-12-06 00:35:19 +03:00
p = ( ( char * ) & transport - > tcp_fraghdr ) + transport - > tcp_offset ;
len = sizeof ( transport - > tcp_fraghdr ) - transport - > tcp_offset ;
2006-12-06 00:35:41 +03:00
used = xdr_skb_read_bits ( desc , p , len ) ;
2006-12-06 00:35:19 +03:00
transport - > tcp_offset + = used ;
2005-08-12 00:25:23 +04:00
if ( used ! = len )
return ;
2005-08-26 03:25:49 +04:00
2006-12-06 00:35:19 +03:00
transport - > tcp_reclen = ntohl ( transport - > tcp_fraghdr ) ;
if ( transport - > tcp_reclen & RPC_LAST_STREAM_FRAGMENT )
2006-12-06 00:35:23 +03:00
transport - > tcp_flags | = TCP_RCV_LAST_FRAG ;
2005-08-12 00:25:23 +04:00
else
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_LAST_FRAG ;
2006-12-06 00:35:19 +03:00
transport - > tcp_reclen & = RPC_FRAGMENT_SIZE_MASK ;
2005-08-26 03:25:49 +04:00
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_COPY_FRAGHDR ;
2006-12-06 00:35:19 +03:00
transport - > tcp_offset = 0 ;
2005-08-26 03:25:49 +04:00
2005-08-12 00:25:23 +04:00
/* Sanity check of the record length */
2006-12-06 00:35:19 +03:00
if ( unlikely ( transport - > tcp_reclen < 4 ) ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: invalid TCP record fragment length \n " ) ;
2007-11-07 02:40:12 +03:00
xprt_force_disconnect ( xprt ) ;
2005-08-12 00:25:26 +04:00
return ;
2005-08-12 00:25:23 +04:00
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: reading TCP record fragment of length %d \n " ,
2006-12-06 00:35:19 +03:00
transport - > tcp_reclen ) ;
2005-08-12 00:25:23 +04:00
}
2006-12-06 00:35:19 +03:00
static void xs_tcp_check_fraghdr ( struct sock_xprt * transport )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:19 +03:00
if ( transport - > tcp_offset = = transport - > tcp_reclen ) {
2006-12-06 00:35:23 +03:00
transport - > tcp_flags | = TCP_RCV_COPY_FRAGHDR ;
2006-12-06 00:35:19 +03:00
transport - > tcp_offset = 0 ;
2006-12-06 00:35:23 +03:00
if ( transport - > tcp_flags & TCP_RCV_LAST_FRAG ) {
transport - > tcp_flags & = ~ TCP_RCV_COPY_DATA ;
transport - > tcp_flags | = TCP_RCV_COPY_XID ;
2006-12-06 00:35:19 +03:00
transport - > tcp_copied = 0 ;
2005-08-12 00:25:23 +04:00
}
}
}
2006-12-06 00:35:44 +03:00
static inline void xs_tcp_read_xid ( struct sock_xprt * transport , struct xdr_skb_reader * desc )
2005-08-12 00:25:23 +04:00
{
size_t len , used ;
char * p ;
2006-12-06 00:35:19 +03:00
len = sizeof ( transport - > tcp_xid ) - transport - > tcp_offset ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: reading XID (%Zu bytes) \n " , len ) ;
2006-12-06 00:35:19 +03:00
p = ( ( char * ) & transport - > tcp_xid ) + transport - > tcp_offset ;
2006-12-06 00:35:41 +03:00
used = xdr_skb_read_bits ( desc , p , len ) ;
2006-12-06 00:35:19 +03:00
transport - > tcp_offset + = used ;
2005-08-12 00:25:23 +04:00
if ( used ! = len )
return ;
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_COPY_XID ;
transport - > tcp_flags | = TCP_RCV_COPY_DATA ;
2006-12-06 00:35:19 +03:00
transport - > tcp_copied = 4 ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: reading reply for XID %08x \n " ,
2006-12-06 00:35:19 +03:00
ntohl ( transport - > tcp_xid ) ) ;
xs_tcp_check_fraghdr ( transport ) ;
2005-08-12 00:25:23 +04:00
}
2006-12-06 00:35:44 +03:00
static inline void xs_tcp_read_request ( struct rpc_xprt * xprt , struct xdr_skb_reader * desc )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:19 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
struct rpc_rqst * req ;
struct xdr_buf * rcvbuf ;
size_t len ;
ssize_t r ;
/* Find and lock the request corresponding to this xid */
2005-08-12 00:25:32 +04:00
spin_lock ( & xprt - > transport_lock ) ;
2006-12-06 00:35:19 +03:00
req = xprt_lookup_rqst ( xprt , transport - > tcp_xid ) ;
2005-08-12 00:25:23 +04:00
if ( ! req ) {
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_COPY_DATA ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: XID %08x request not found! \n " ,
2006-12-06 00:35:19 +03:00
ntohl ( transport - > tcp_xid ) ) ;
2005-08-12 00:25:32 +04:00
spin_unlock ( & xprt - > transport_lock ) ;
2005-08-12 00:25:23 +04:00
return ;
}
rcvbuf = & req - > rq_private_buf ;
len = desc - > count ;
2006-12-06 00:35:19 +03:00
if ( len > transport - > tcp_reclen - transport - > tcp_offset ) {
2006-12-06 00:35:44 +03:00
struct xdr_skb_reader my_desc ;
2005-08-12 00:25:23 +04:00
2006-12-06 00:35:19 +03:00
len = transport - > tcp_reclen - transport - > tcp_offset ;
2005-08-12 00:25:23 +04:00
memcpy ( & my_desc , desc , sizeof ( my_desc ) ) ;
my_desc . count = len ;
2006-12-06 00:35:19 +03:00
r = xdr_partial_copy_from_skb ( rcvbuf , transport - > tcp_copied ,
2006-12-06 00:35:41 +03:00
& my_desc , xdr_skb_read_bits ) ;
2005-08-12 00:25:23 +04:00
desc - > count - = r ;
desc - > offset + = r ;
} else
2006-12-06 00:35:19 +03:00
r = xdr_partial_copy_from_skb ( rcvbuf , transport - > tcp_copied ,
2006-12-06 00:35:41 +03:00
desc , xdr_skb_read_bits ) ;
2005-08-12 00:25:23 +04:00
if ( r > 0 ) {
2006-12-06 00:35:19 +03:00
transport - > tcp_copied + = r ;
transport - > tcp_offset + = r ;
2005-08-12 00:25:23 +04:00
}
if ( r ! = len ) {
/* Error when copying to the receive buffer,
* usually because we weren ' t able to allocate
* additional buffer pages . All we can do now
2006-12-06 00:35:23 +03:00
* is turn off TCP_RCV_COPY_DATA , so the request
2005-08-12 00:25:23 +04:00
* will not receive any additional updates ,
* and time out .
* Any remaining data from this record will
* be discarded .
*/
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_COPY_DATA ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: XID %08x truncated request \n " ,
2006-12-06 00:35:19 +03:00
ntohl ( transport - > tcp_xid ) ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xprt = %p, tcp_copied = %lu, "
" tcp_offset = %u, tcp_reclen = %u \n " ,
xprt , transport - > tcp_copied ,
transport - > tcp_offset , transport - > tcp_reclen ) ;
2005-08-12 00:25:23 +04:00
goto out ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: XID %08x read %Zd bytes \n " ,
2006-12-06 00:35:19 +03:00
ntohl ( transport - > tcp_xid ) , r ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, "
" tcp_reclen = %u \n " , xprt , transport - > tcp_copied ,
transport - > tcp_offset , transport - > tcp_reclen ) ;
2006-12-06 00:35:19 +03:00
if ( transport - > tcp_copied = = req - > rq_private_buf . buflen )
2006-12-06 00:35:23 +03:00
transport - > tcp_flags & = ~ TCP_RCV_COPY_DATA ;
2006-12-06 00:35:19 +03:00
else if ( transport - > tcp_offset = = transport - > tcp_reclen ) {
2006-12-06 00:35:23 +03:00
if ( transport - > tcp_flags & TCP_RCV_LAST_FRAG )
transport - > tcp_flags & = ~ TCP_RCV_COPY_DATA ;
2005-08-12 00:25:23 +04:00
}
out :
2006-12-06 00:35:23 +03:00
if ( ! ( transport - > tcp_flags & TCP_RCV_COPY_DATA ) )
2006-12-06 00:35:19 +03:00
xprt_complete_rqst ( req - > rq_task , transport - > tcp_copied ) ;
2005-08-12 00:25:32 +04:00
spin_unlock ( & xprt - > transport_lock ) ;
2006-12-06 00:35:19 +03:00
xs_tcp_check_fraghdr ( transport ) ;
2005-08-12 00:25:23 +04:00
}
2006-12-06 00:35:44 +03:00
static inline void xs_tcp_read_discard ( struct sock_xprt * transport , struct xdr_skb_reader * desc )
2005-08-12 00:25:23 +04:00
{
size_t len ;
2006-12-06 00:35:19 +03:00
len = transport - > tcp_reclen - transport - > tcp_offset ;
2005-08-12 00:25:23 +04:00
if ( len > desc - > count )
len = desc - > count ;
desc - > count - = len ;
desc - > offset + = len ;
2006-12-06 00:35:19 +03:00
transport - > tcp_offset + = len ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: discarded %Zu bytes \n " , len ) ;
2006-12-06 00:35:19 +03:00
xs_tcp_check_fraghdr ( transport ) ;
2005-08-12 00:25:23 +04:00
}
2005-08-12 00:25:26 +04:00
static int xs_tcp_data_recv ( read_descriptor_t * rd_desc , struct sk_buff * skb , unsigned int offset , size_t len )
2005-08-12 00:25:23 +04:00
{
struct rpc_xprt * xprt = rd_desc - > arg . data ;
2006-12-06 00:35:19 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2006-12-06 00:35:44 +03:00
struct xdr_skb_reader desc = {
2005-08-12 00:25:23 +04:00
. skb = skb ,
. offset = offset ,
. count = len ,
2005-08-12 00:25:26 +04:00
} ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_tcp_data_recv started \n " ) ;
2005-08-12 00:25:23 +04:00
do {
/* Read in a new fragment marker if necessary */
/* Can we ever really expect to get completely empty fragments? */
2006-12-06 00:35:23 +03:00
if ( transport - > tcp_flags & TCP_RCV_COPY_FRAGHDR ) {
2005-08-12 00:25:26 +04:00
xs_tcp_read_fraghdr ( xprt , & desc ) ;
2005-08-12 00:25:23 +04:00
continue ;
}
/* Read in the xid if necessary */
2006-12-06 00:35:23 +03:00
if ( transport - > tcp_flags & TCP_RCV_COPY_XID ) {
2006-12-06 00:35:19 +03:00
xs_tcp_read_xid ( transport , & desc ) ;
2005-08-12 00:25:23 +04:00
continue ;
}
/* Read in the request data */
2006-12-06 00:35:23 +03:00
if ( transport - > tcp_flags & TCP_RCV_COPY_DATA ) {
2005-08-12 00:25:26 +04:00
xs_tcp_read_request ( xprt , & desc ) ;
2005-08-12 00:25:23 +04:00
continue ;
}
/* Skip over any trailing bytes on short reads */
2006-12-06 00:35:19 +03:00
xs_tcp_read_discard ( transport , & desc ) ;
2005-08-12 00:25:23 +04:00
} while ( desc . count ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_tcp_data_recv done \n " ) ;
2005-08-12 00:25:23 +04:00
return len - desc . count ;
}
2005-08-12 00:25:26 +04:00
/**
* xs_tcp_data_ready - " data ready " callback for TCP sockets
* @ sk : socket with data to read
* @ bytes : how much data to read
*
*/
static void xs_tcp_data_ready ( struct sock * sk , int bytes )
2005-08-12 00:25:23 +04:00
{
struct rpc_xprt * xprt ;
read_descriptor_t rd_desc ;
2008-02-26 08:40:51 +03:00
int read ;
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_tcp_data_ready... \n " ) ;
2005-08-12 00:25:23 +04:00
read_lock ( & sk - > sk_callback_lock ) ;
2005-08-12 00:25:26 +04:00
if ( ! ( xprt = xprt_from_sock ( sk ) ) )
2005-08-12 00:25:23 +04:00
goto out ;
if ( xprt - > shutdown )
goto out ;
2005-08-12 00:25:26 +04:00
/* We use rd_desc to pass struct xprt to xs_tcp_data_recv */
2005-08-12 00:25:23 +04:00
rd_desc . arg . data = xprt ;
2008-02-26 08:40:51 +03:00
do {
rd_desc . count = 65536 ;
read = tcp_read_sock ( sk , & rd_desc , xs_tcp_data_recv ) ;
} while ( read > 0 ) ;
2005-08-12 00:25:23 +04:00
out :
read_unlock ( & sk - > sk_callback_lock ) ;
}
2009-03-11 21:38:03 +03:00
/*
* Do the equivalent of linger / linger2 handling for dealing with
* broken servers that don ' t close the socket in a timely
* fashion
*/
static void xs_tcp_schedule_linger_timeout ( struct rpc_xprt * xprt ,
unsigned long timeout )
{
struct sock_xprt * transport ;
if ( xprt_test_and_set_connecting ( xprt ) )
return ;
set_bit ( XPRT_CONNECTION_ABORT , & xprt - > state ) ;
transport = container_of ( xprt , struct sock_xprt , xprt ) ;
queue_delayed_work ( rpciod_workqueue , & transport - > connect_worker ,
timeout ) ;
}
static void xs_tcp_cancel_linger_timeout ( struct rpc_xprt * xprt )
{
struct sock_xprt * transport ;
transport = container_of ( xprt , struct sock_xprt , xprt ) ;
if ( ! test_bit ( XPRT_CONNECTION_ABORT , & xprt - > state ) | |
! cancel_delayed_work ( & transport - > connect_worker ) )
return ;
clear_bit ( XPRT_CONNECTION_ABORT , & xprt - > state ) ;
xprt_clear_connecting ( xprt ) ;
}
static void xs_sock_mark_closed ( struct rpc_xprt * xprt )
{
smp_mb__before_clear_bit ( ) ;
clear_bit ( XPRT_CLOSE_WAIT , & xprt - > state ) ;
clear_bit ( XPRT_CLOSING , & xprt - > state ) ;
smp_mb__after_clear_bit ( ) ;
/* Mark transport as closed and wake up all pending tasks */
xprt_disconnect_done ( xprt ) ;
}
2005-08-12 00:25:26 +04:00
/**
* xs_tcp_state_change - callback to handle TCP socket state changes
* @ sk : socket whose state has changed
*
*/
static void xs_tcp_state_change ( struct sock * sk )
2005-08-12 00:25:23 +04:00
{
2005-08-12 00:25:26 +04:00
struct rpc_xprt * xprt ;
2005-08-12 00:25:23 +04:00
read_lock ( & sk - > sk_callback_lock ) ;
if ( ! ( xprt = xprt_from_sock ( sk ) ) )
goto out ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_tcp_state_change client %p... \n " , xprt ) ;
dprintk ( " RPC: state %x conn %d dead %d zapped %d \n " ,
sk - > sk_state , xprt_connected ( xprt ) ,
sock_flag ( sk , SOCK_DEAD ) ,
sock_flag ( sk , SOCK_ZAPPED ) ) ;
2005-08-12 00:25:23 +04:00
switch ( sk - > sk_state ) {
case TCP_ESTABLISHED :
2005-08-12 00:25:32 +04:00
spin_lock_bh ( & xprt - > transport_lock ) ;
2005-08-12 00:25:23 +04:00
if ( ! xprt_test_and_set_connected ( xprt ) ) {
2006-12-06 00:35:19 +03:00
struct sock_xprt * transport = container_of ( xprt ,
struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
/* Reset TCP record info */
2006-12-06 00:35:19 +03:00
transport - > tcp_offset = 0 ;
transport - > tcp_reclen = 0 ;
transport - > tcp_copied = 0 ;
2006-12-06 00:35:23 +03:00
transport - > tcp_flags =
TCP_RCV_COPY_FRAGHDR | TCP_RCV_COPY_XID ;
2006-12-06 00:35:19 +03:00
2009-03-11 21:38:00 +03:00
xprt_wake_pending_tasks ( xprt , - EAGAIN ) ;
2005-08-12 00:25:23 +04:00
}
2005-08-12 00:25:32 +04:00
spin_unlock_bh ( & xprt - > transport_lock ) ;
2005-08-12 00:25:23 +04:00
break ;
2007-11-06 01:42:39 +03:00
case TCP_FIN_WAIT1 :
/* The client initiated a shutdown of the socket */
2008-04-18 00:52:57 +04:00
xprt - > connect_cookie + + ;
2008-01-02 02:42:12 +03:00
xprt - > reestablish_timeout = 0 ;
2007-11-06 01:42:39 +03:00
set_bit ( XPRT_CLOSING , & xprt - > state ) ;
smp_mb__before_clear_bit ( ) ;
clear_bit ( XPRT_CONNECTED , & xprt - > state ) ;
2008-01-01 00:19:17 +03:00
clear_bit ( XPRT_CLOSE_WAIT , & xprt - > state ) ;
2007-11-06 01:42:39 +03:00
smp_mb__after_clear_bit ( ) ;
2009-03-11 21:38:03 +03:00
xs_tcp_schedule_linger_timeout ( xprt , xs_tcp_fin_timeout ) ;
2005-08-12 00:25:23 +04:00
break ;
2006-01-03 11:55:55 +03:00
case TCP_CLOSE_WAIT :
2007-11-06 01:42:39 +03:00
/* The server initiated a shutdown of the socket */
2007-11-06 18:18:36 +03:00
xprt_force_disconnect ( xprt ) ;
2008-01-02 02:42:12 +03:00
case TCP_SYN_SENT :
2008-04-18 00:52:57 +04:00
xprt - > connect_cookie + + ;
2008-01-02 02:42:12 +03:00
case TCP_CLOSING :
/*
* If the server closed down the connection , make sure that
* we back off before reconnecting
*/
if ( xprt - > reestablish_timeout < XS_TCP_INIT_REEST_TO )
xprt - > reestablish_timeout = XS_TCP_INIT_REEST_TO ;
2007-11-06 01:42:39 +03:00
break ;
case TCP_LAST_ACK :
2009-03-11 21:37:58 +03:00
set_bit ( XPRT_CLOSING , & xprt - > state ) ;
2009-03-11 21:38:03 +03:00
xs_tcp_schedule_linger_timeout ( xprt , xs_tcp_fin_timeout ) ;
2007-11-06 01:42:39 +03:00
smp_mb__before_clear_bit ( ) ;
clear_bit ( XPRT_CONNECTED , & xprt - > state ) ;
smp_mb__after_clear_bit ( ) ;
break ;
case TCP_CLOSE :
2009-03-11 21:38:03 +03:00
xs_tcp_cancel_linger_timeout ( xprt ) ;
xs_sock_mark_closed ( xprt ) ;
2005-08-12 00:25:23 +04:00
}
out :
read_unlock ( & sk - > sk_callback_lock ) ;
}
2008-10-28 22:21:39 +03:00
/**
2009-03-11 21:38:00 +03:00
* xs_error_report - callback mainly for catching socket errors
2008-10-28 22:21:39 +03:00
* @ sk : socket
*/
2009-03-11 21:38:00 +03:00
static void xs_error_report ( struct sock * sk )
2008-10-28 22:21:39 +03:00
{
struct rpc_xprt * xprt ;
read_lock ( & sk - > sk_callback_lock ) ;
if ( ! ( xprt = xprt_from_sock ( sk ) ) )
goto out ;
dprintk ( " RPC: %s client %p... \n "
" RPC: error %d \n " ,
__func__ , xprt , sk - > sk_err ) ;
2009-03-11 21:38:00 +03:00
xprt_wake_pending_tasks ( xprt , - EAGAIN ) ;
2008-10-28 22:21:39 +03:00
out :
read_unlock ( & sk - > sk_callback_lock ) ;
}
net/sunrpc/xprtsock.c: some common code found
$ diff-funcs xs_udp_write_space net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c xs_tcp_write_space
--- net/sunrpc/xprtsock.c:xs_udp_write_space()
+++ net/sunrpc/xprtsock.c:xs_tcp_write_space()
@@ -1,4 +1,4 @@
- * xs_udp_write_space - callback invoked when socket buffer space
+ * xs_tcp_write_space - callback invoked when socket buffer space
* becomes available
* @sk: socket whose state has changed
*
@@ -7,12 +7,12 @@
* progress, otherwise we'll waste resources thrashing kernel_sendmsg
* with a bunch of small requests.
*/
-static void xs_udp_write_space(struct sock *sk)
+static void xs_tcp_write_space(struct sock *sk)
{
read_lock(&sk->sk_callback_lock);
- /* from net/core/sock.c:sock_def_write_space */
- if (sock_writeable(sk)) {
+ /* from net/core/stream.c:sk_stream_write_space */
+ if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
struct socket *sock;
struct rpc_xprt *xprt;
$ codiff net/sunrpc/xprtsock.o net/sunrpc/xprtsock.o.new
net/sunrpc/xprtsock.c:
xs_tcp_write_space | -163
xs_udp_write_space | -163
2 functions changed, 326 bytes removed
net/sunrpc/xprtsock.c:
xs_write_space | +179
1 function changed, 179 bytes added
net/sunrpc/xprtsock.o.new:
3 functions changed, 179 bytes added, 326 bytes removed, diff: -147
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-02-07 10:48:33 +03:00
static void xs_write_space ( struct sock * sk )
{
struct socket * sock ;
struct rpc_xprt * xprt ;
if ( unlikely ( ! ( sock = sk - > sk_socket ) ) )
return ;
clear_bit ( SOCK_NOSPACE , & sock - > flags ) ;
if ( unlikely ( ! ( xprt = xprt_from_sock ( sk ) ) ) )
return ;
if ( test_and_clear_bit ( SOCK_ASYNC_NOSPACE , & sock - > flags ) = = 0 )
return ;
xprt_write_space ( xprt ) ;
}
2005-08-12 00:25:26 +04:00
/**
2005-08-12 00:25:50 +04:00
* xs_udp_write_space - callback invoked when socket buffer space
* becomes available
2005-08-12 00:25:26 +04:00
* @ sk : socket whose state has changed
*
2005-08-12 00:25:23 +04:00
* Called when more output buffer space is available for this socket .
* We try not to wake our writers until they can make " significant "
2005-08-12 00:25:50 +04:00
* progress , otherwise we ' ll waste resources thrashing kernel_sendmsg
2005-08-12 00:25:23 +04:00
* with a bunch of small requests .
*/
2005-08-12 00:25:50 +04:00
static void xs_udp_write_space ( struct sock * sk )
2005-08-12 00:25:23 +04:00
{
read_lock ( & sk - > sk_callback_lock ) ;
2005-08-12 00:25:50 +04:00
/* from net/core/sock.c:sock_def_write_space */
net/sunrpc/xprtsock.c: some common code found
$ diff-funcs xs_udp_write_space net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c xs_tcp_write_space
--- net/sunrpc/xprtsock.c:xs_udp_write_space()
+++ net/sunrpc/xprtsock.c:xs_tcp_write_space()
@@ -1,4 +1,4 @@
- * xs_udp_write_space - callback invoked when socket buffer space
+ * xs_tcp_write_space - callback invoked when socket buffer space
* becomes available
* @sk: socket whose state has changed
*
@@ -7,12 +7,12 @@
* progress, otherwise we'll waste resources thrashing kernel_sendmsg
* with a bunch of small requests.
*/
-static void xs_udp_write_space(struct sock *sk)
+static void xs_tcp_write_space(struct sock *sk)
{
read_lock(&sk->sk_callback_lock);
- /* from net/core/sock.c:sock_def_write_space */
- if (sock_writeable(sk)) {
+ /* from net/core/stream.c:sk_stream_write_space */
+ if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
struct socket *sock;
struct rpc_xprt *xprt;
$ codiff net/sunrpc/xprtsock.o net/sunrpc/xprtsock.o.new
net/sunrpc/xprtsock.c:
xs_tcp_write_space | -163
xs_udp_write_space | -163
2 functions changed, 326 bytes removed
net/sunrpc/xprtsock.c:
xs_write_space | +179
1 function changed, 179 bytes added
net/sunrpc/xprtsock.o.new:
3 functions changed, 179 bytes added, 326 bytes removed, diff: -147
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-02-07 10:48:33 +03:00
if ( sock_writeable ( sk ) )
xs_write_space ( sk ) ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:50 +04:00
read_unlock ( & sk - > sk_callback_lock ) ;
}
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:50 +04:00
/**
* xs_tcp_write_space - callback invoked when socket buffer space
* becomes available
* @ sk : socket whose state has changed
*
* Called when more output buffer space is available for this socket .
* We try not to wake our writers until they can make " significant "
* progress , otherwise we ' ll waste resources thrashing kernel_sendmsg
* with a bunch of small requests .
*/
static void xs_tcp_write_space ( struct sock * sk )
{
read_lock ( & sk - > sk_callback_lock ) ;
/* from net/core/stream.c:sk_stream_write_space */
net/sunrpc/xprtsock.c: some common code found
$ diff-funcs xs_udp_write_space net/sunrpc/xprtsock.c
net/sunrpc/xprtsock.c xs_tcp_write_space
--- net/sunrpc/xprtsock.c:xs_udp_write_space()
+++ net/sunrpc/xprtsock.c:xs_tcp_write_space()
@@ -1,4 +1,4 @@
- * xs_udp_write_space - callback invoked when socket buffer space
+ * xs_tcp_write_space - callback invoked when socket buffer space
* becomes available
* @sk: socket whose state has changed
*
@@ -7,12 +7,12 @@
* progress, otherwise we'll waste resources thrashing kernel_sendmsg
* with a bunch of small requests.
*/
-static void xs_udp_write_space(struct sock *sk)
+static void xs_tcp_write_space(struct sock *sk)
{
read_lock(&sk->sk_callback_lock);
- /* from net/core/sock.c:sock_def_write_space */
- if (sock_writeable(sk)) {
+ /* from net/core/stream.c:sk_stream_write_space */
+ if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
struct socket *sock;
struct rpc_xprt *xprt;
$ codiff net/sunrpc/xprtsock.o net/sunrpc/xprtsock.o.new
net/sunrpc/xprtsock.c:
xs_tcp_write_space | -163
xs_udp_write_space | -163
2 functions changed, 326 bytes removed
net/sunrpc/xprtsock.c:
xs_write_space | +179
1 function changed, 179 bytes added
net/sunrpc/xprtsock.o.new:
3 functions changed, 179 bytes added, 326 bytes removed, diff: -147
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
2009-02-07 10:48:33 +03:00
if ( sk_stream_wspace ( sk ) > = sk_stream_min_wspace ( sk ) )
xs_write_space ( sk ) ;
2008-04-18 02:52:19 +04:00
2005-08-12 00:25:23 +04:00
read_unlock ( & sk - > sk_callback_lock ) ;
}
2005-08-26 03:25:56 +04:00
static void xs_udp_do_set_buffer_size ( struct rpc_xprt * xprt )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:15 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
struct sock * sk = transport - > inet ;
2005-08-12 00:25:23 +04:00
2006-12-06 00:35:30 +03:00
if ( transport - > rcvsize ) {
2005-08-12 00:25:23 +04:00
sk - > sk_userlocks | = SOCK_RCVBUF_LOCK ;
2006-12-06 00:35:30 +03:00
sk - > sk_rcvbuf = transport - > rcvsize * xprt - > max_reqs * 2 ;
2005-08-12 00:25:23 +04:00
}
2006-12-06 00:35:30 +03:00
if ( transport - > sndsize ) {
2005-08-12 00:25:23 +04:00
sk - > sk_userlocks | = SOCK_SNDBUF_LOCK ;
2006-12-06 00:35:30 +03:00
sk - > sk_sndbuf = transport - > sndsize * xprt - > max_reqs * 2 ;
2005-08-12 00:25:23 +04:00
sk - > sk_write_space ( sk ) ;
}
}
2005-08-26 03:25:49 +04:00
/**
2005-08-26 03:25:56 +04:00
* xs_udp_set_buffer_size - set send and receive limits
2005-08-26 03:25:49 +04:00
* @ xprt : generic transport
2005-08-26 03:25:56 +04:00
* @ sndsize : requested size of send buffer , in bytes
* @ rcvsize : requested size of receive buffer , in bytes
2005-08-26 03:25:49 +04:00
*
2005-08-26 03:25:56 +04:00
* Set socket send and receive buffer size limits .
2005-08-26 03:25:49 +04:00
*/
2005-08-26 03:25:56 +04:00
static void xs_udp_set_buffer_size ( struct rpc_xprt * xprt , size_t sndsize , size_t rcvsize )
2005-08-26 03:25:49 +04:00
{
2006-12-06 00:35:30 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
transport - > sndsize = 0 ;
2005-08-26 03:25:56 +04:00
if ( sndsize )
2006-12-06 00:35:30 +03:00
transport - > sndsize = sndsize + 1024 ;
transport - > rcvsize = 0 ;
2005-08-26 03:25:56 +04:00
if ( rcvsize )
2006-12-06 00:35:30 +03:00
transport - > rcvsize = rcvsize + 1024 ;
2005-08-26 03:25:56 +04:00
xs_udp_do_set_buffer_size ( xprt ) ;
2005-08-26 03:25:49 +04:00
}
2005-08-26 03:25:52 +04:00
/**
* xs_udp_timer - called when a retransmit timeout occurs on a UDP transport
* @ task : task that timed out
*
* Adjust the congestion window after a retransmit timeout has occurred .
*/
static void xs_udp_timer ( struct rpc_task * task )
{
xprt_adjust_cwnd ( task , - ETIMEDOUT ) ;
}
2006-05-25 09:40:49 +04:00
static unsigned short xs_get_random_port ( void )
{
unsigned short range = xprt_max_resvport - xprt_min_resvport ;
unsigned short rand = ( unsigned short ) net_random ( ) % range ;
return rand + xprt_min_resvport ;
}
2006-01-03 11:55:51 +03:00
/**
* xs_set_port - reset the port number in the remote endpoint address
* @ xprt : generic transport
* @ port : new port number
*
*/
static void xs_set_port ( struct rpc_xprt * xprt , unsigned short port )
{
2007-08-06 19:57:58 +04:00
struct sockaddr * addr = xs_addr ( xprt ) ;
2006-08-23 04:06:19 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: setting port for xprt %p to %u \n " , xprt , port ) ;
2006-08-23 04:06:19 +04:00
2007-08-06 19:57:23 +04:00
switch ( addr - > sa_family ) {
case AF_INET :
( ( struct sockaddr_in * ) addr ) - > sin_port = htons ( port ) ;
break ;
case AF_INET6 :
( ( struct sockaddr_in6 * ) addr ) - > sin6_port = htons ( port ) ;
break ;
default :
BUG ( ) ;
}
2006-01-03 11:55:51 +03:00
}
2007-11-06 01:40:58 +03:00
static unsigned short xs_get_srcport ( struct sock_xprt * transport , struct socket * sock )
{
unsigned short port = transport - > port ;
if ( port = = 0 & & transport - > xprt . resvport )
port = xs_get_random_port ( ) ;
return port ;
}
static unsigned short xs_next_srcport ( struct sock_xprt * transport , struct socket * sock , unsigned short port )
{
if ( transport - > port ! = 0 )
transport - > port = 0 ;
if ( ! transport - > xprt . resvport )
return 0 ;
if ( port < = xprt_min_resvport | | port > xprt_max_resvport )
return xprt_max_resvport ;
return - - port ;
}
2007-08-06 19:57:28 +04:00
static int xs_bind4 ( struct sock_xprt * transport , struct socket * sock )
2005-08-12 00:25:23 +04:00
{
struct sockaddr_in myaddr = {
. sin_family = AF_INET ,
} ;
2007-07-10 00:23:35 +04:00
struct sockaddr_in * sa ;
2007-11-06 01:40:58 +03:00
int err , nloop = 0 ;
unsigned short port = xs_get_srcport ( transport , sock ) ;
unsigned short last ;
2005-08-12 00:25:23 +04:00
2007-07-10 00:23:35 +04:00
sa = ( struct sockaddr_in * ) & transport - > addr ;
myaddr . sin_addr = sa - > sin_addr ;
2005-08-12 00:25:23 +04:00
do {
myaddr . sin_port = htons ( port ) ;
2006-08-08 07:58:01 +04:00
err = kernel_bind ( sock , ( struct sockaddr * ) & myaddr ,
2005-08-12 00:25:23 +04:00
sizeof ( myaddr ) ) ;
2007-11-06 01:40:58 +03:00
if ( port = = 0 )
2007-07-10 00:23:35 +04:00
break ;
2005-08-12 00:25:23 +04:00
if ( err = = 0 ) {
2006-12-06 00:35:26 +03:00
transport - > port = port ;
2007-07-10 00:23:35 +04:00
break ;
2005-08-12 00:25:23 +04:00
}
2007-11-06 01:40:58 +03:00
last = port ;
port = xs_next_srcport ( transport , sock , port ) ;
if ( port > last )
nloop + + ;
} while ( err = = - EADDRINUSE & & nloop ! = 2 ) ;
2008-10-31 10:54:56 +03:00
dprintk ( " RPC: %s %pI4:%u: %s (%d) \n " ,
__func__ , & myaddr . sin_addr ,
2007-08-06 19:57:28 +04:00
port , err ? " failed " : " ok " , err ) ;
2005-08-12 00:25:23 +04:00
return err ;
}
2007-08-06 19:57:33 +04:00
static int xs_bind6 ( struct sock_xprt * transport , struct socket * sock )
{
struct sockaddr_in6 myaddr = {
. sin6_family = AF_INET6 ,
} ;
struct sockaddr_in6 * sa ;
2007-11-06 01:40:58 +03:00
int err , nloop = 0 ;
unsigned short port = xs_get_srcport ( transport , sock ) ;
unsigned short last ;
2007-08-06 19:57:33 +04:00
sa = ( struct sockaddr_in6 * ) & transport - > addr ;
myaddr . sin6_addr = sa - > sin6_addr ;
do {
myaddr . sin6_port = htons ( port ) ;
err = kernel_bind ( sock , ( struct sockaddr * ) & myaddr ,
sizeof ( myaddr ) ) ;
2007-11-06 01:40:58 +03:00
if ( port = = 0 )
2007-08-06 19:57:33 +04:00
break ;
if ( err = = 0 ) {
transport - > port = port ;
break ;
}
2007-11-06 01:40:58 +03:00
last = port ;
port = xs_next_srcport ( transport , sock , port ) ;
if ( port > last )
nloop + + ;
} while ( err = = - EADDRINUSE & & nloop ! = 2 ) ;
2008-10-29 22:52:50 +03:00
dprintk ( " RPC: xs_bind6 %pI6:%u: %s (%d) \n " ,
2008-10-29 02:10:17 +03:00
& myaddr . sin6_addr , port , err ? " failed " : " ok " , err ) ;
2005-08-12 00:25:23 +04:00
return err ;
}
2006-12-07 07:35:24 +03:00
# ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key xs_key [ 2 ] ;
static struct lock_class_key xs_slock_key [ 2 ] ;
2007-08-06 19:58:04 +04:00
static inline void xs_reclassify_socket4 ( struct socket * sock )
2006-12-07 07:35:24 +03:00
{
struct sock * sk = sock - > sk ;
2007-08-06 19:58:04 +04:00
2007-09-12 12:42:12 +04:00
BUG_ON ( sock_owned_by_user ( sk ) ) ;
2007-08-06 19:58:04 +04:00
sock_lock_init_class_and_name ( sk , " slock-AF_INET-RPC " ,
& xs_slock_key [ 0 ] , " sk_lock-AF_INET-RPC " , & xs_key [ 0 ] ) ;
}
2006-12-07 07:35:24 +03:00
2007-08-06 19:58:04 +04:00
static inline void xs_reclassify_socket6 ( struct socket * sock )
{
struct sock * sk = sock - > sk ;
2006-12-07 07:35:24 +03:00
2007-10-15 21:46:05 +04:00
BUG_ON ( sock_owned_by_user ( sk ) ) ;
2007-08-06 19:58:04 +04:00
sock_lock_init_class_and_name ( sk , " slock-AF_INET6-RPC " ,
& xs_slock_key [ 1 ] , " sk_lock-AF_INET6-RPC " , & xs_key [ 1 ] ) ;
2006-12-07 07:35:24 +03:00
}
# else
2007-08-06 19:58:04 +04:00
static inline void xs_reclassify_socket4 ( struct socket * sock )
{
}
static inline void xs_reclassify_socket6 ( struct socket * sock )
2006-12-07 07:35:24 +03:00
{
}
# endif
2007-08-06 19:57:38 +04:00
static void xs_udp_finish_connecting ( struct rpc_xprt * xprt , struct socket * sock )
{
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
if ( ! transport - > inet ) {
struct sock * sk = sock - > sk ;
write_lock_bh ( & sk - > sk_callback_lock ) ;
2008-10-28 22:21:39 +03:00
xs_save_old_callbacks ( transport , sk ) ;
2007-08-06 19:57:38 +04:00
sk - > sk_user_data = xprt ;
sk - > sk_data_ready = xs_udp_data_ready ;
sk - > sk_write_space = xs_udp_write_space ;
2009-03-11 21:38:00 +03:00
sk - > sk_error_report = xs_error_report ;
2007-08-06 19:57:38 +04:00
sk - > sk_no_check = UDP_CSUM_NORCV ;
sk - > sk_allocation = GFP_ATOMIC ;
xprt_set_connected ( xprt ) ;
/* Reset to new socket */
transport - > sock = sock ;
transport - > inet = sk ;
write_unlock_bh ( & sk - > sk_callback_lock ) ;
}
xs_udp_do_set_buffer_size ( xprt ) ;
}
2005-08-12 00:25:53 +04:00
/**
2007-08-06 19:57:43 +04:00
* xs_udp_connect_worker4 - set up a UDP socket
2006-11-22 17:55:48 +03:00
* @ work : RPC transport to connect
2005-08-12 00:25:53 +04:00
*
* Invoked by a work queue tasklet .
*/
2007-08-06 19:57:43 +04:00
static void xs_udp_connect_worker4 ( struct work_struct * work )
2005-08-12 00:25:23 +04:00
{
2006-12-07 23:48:15 +03:00
struct sock_xprt * transport =
container_of ( work , struct sock_xprt , connect_worker . work ) ;
2006-12-06 00:35:26 +03:00
struct rpc_xprt * xprt = & transport - > xprt ;
2006-12-06 00:35:15 +03:00
struct socket * sock = transport - > sock ;
2005-08-12 00:25:53 +04:00
int err , status = - EIO ;
2005-08-12 00:25:26 +04:00
2009-03-11 21:09:39 +03:00
if ( xprt - > shutdown )
2005-08-12 00:25:53 +04:00
goto out ;
2005-08-12 00:25:26 +04:00
2005-08-12 00:25:53 +04:00
/* Start by resetting any existing state */
2009-03-11 21:10:21 +03:00
xs_reset_transport ( transport ) ;
2005-08-12 00:25:26 +04:00
2009-03-11 21:10:21 +03:00
err = sock_create_kern ( PF_INET , SOCK_DGRAM , IPPROTO_UDP , & sock ) ;
if ( err < 0 ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: can't create UDP transport socket (%d). \n " , - err ) ;
2005-08-12 00:25:53 +04:00
goto out ;
}
2007-08-06 19:58:04 +04:00
xs_reclassify_socket4 ( sock ) ;
2005-08-12 00:25:26 +04:00
2007-08-06 19:57:28 +04:00
if ( xs_bind4 ( transport , sock ) ) {
2005-08-12 00:25:53 +04:00
sock_release ( sock ) ;
goto out ;
}
2005-08-12 00:25:26 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: worker connecting xprt %p to address: %s \n " ,
2006-12-06 00:35:37 +03:00
xprt , xprt - > address_strings [ RPC_DISPLAY_ALL ] ) ;
2006-08-23 04:06:18 +04:00
2007-08-06 19:57:38 +04:00
xs_udp_finish_connecting ( xprt , sock ) ;
2005-08-12 00:25:53 +04:00
status = 0 ;
out :
xprt_clear_connecting ( xprt ) ;
2009-03-11 21:38:03 +03:00
xprt_wake_pending_tasks ( xprt , status ) ;
2005-08-12 00:25:23 +04:00
}
2007-08-06 19:57:48 +04:00
/**
* xs_udp_connect_worker6 - set up a UDP socket
* @ work : RPC transport to connect
*
* Invoked by a work queue tasklet .
*/
static void xs_udp_connect_worker6 ( struct work_struct * work )
{
struct sock_xprt * transport =
container_of ( work , struct sock_xprt , connect_worker . work ) ;
struct rpc_xprt * xprt = & transport - > xprt ;
struct socket * sock = transport - > sock ;
int err , status = - EIO ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:09:39 +03:00
if ( xprt - > shutdown )
2007-08-06 19:57:48 +04:00
goto out ;
2005-08-12 00:25:53 +04:00
2007-08-06 19:57:48 +04:00
/* Start by resetting any existing state */
2009-03-11 21:10:21 +03:00
xs_reset_transport ( transport ) ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:10:21 +03:00
err = sock_create_kern ( PF_INET6 , SOCK_DGRAM , IPPROTO_UDP , & sock ) ;
if ( err < 0 ) {
2007-08-06 19:57:48 +04:00
dprintk ( " RPC: can't create UDP transport socket (%d). \n " , - err ) ;
goto out ;
}
2007-08-06 19:58:04 +04:00
xs_reclassify_socket6 ( sock ) ;
2005-08-12 00:25:23 +04:00
2007-08-06 19:57:48 +04:00
if ( xs_bind6 ( transport , sock ) < 0 ) {
sock_release ( sock ) ;
goto out ;
2005-08-12 00:25:53 +04:00
}
2007-08-06 19:57:48 +04:00
dprintk ( " RPC: worker connecting xprt %p to address: %s \n " ,
xprt , xprt - > address_strings [ RPC_DISPLAY_ALL ] ) ;
xs_udp_finish_connecting ( xprt , sock ) ;
2005-08-12 00:25:53 +04:00
status = 0 ;
out :
xprt_clear_connecting ( xprt ) ;
2009-03-11 21:38:03 +03:00
xprt_wake_pending_tasks ( xprt , status ) ;
2005-08-12 00:25:23 +04:00
}
2005-08-26 03:25:55 +04:00
/*
* We need to preserve the port number so the reply cache on the server can
* find our cached RPC replies when we get around to reconnecting .
*/
2009-03-11 21:37:58 +03:00
static void xs_abort_connection ( struct rpc_xprt * xprt , struct sock_xprt * transport )
2005-08-26 03:25:55 +04:00
{
int result ;
struct sockaddr any ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: disconnecting xprt %p to reuse port \n " , xprt ) ;
2005-08-26 03:25:55 +04:00
/*
* Disconnect the transport socket by doing a connect operation
* with AF_UNSPEC . This should return immediately . . .
*/
memset ( & any , 0 , sizeof ( any ) ) ;
any . sa_family = AF_UNSPEC ;
2006-12-06 00:35:15 +03:00
result = kernel_connect ( transport - > sock , & any , sizeof ( any ) , 0 ) ;
2009-03-11 21:38:03 +03:00
if ( ! result )
xs_sock_mark_closed ( xprt ) ;
else
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: AF_UNSPEC connect return code %d \n " ,
2005-08-26 03:25:55 +04:00
result ) ;
}
2009-03-11 21:37:58 +03:00
static void xs_tcp_reuse_connection ( struct rpc_xprt * xprt , struct sock_xprt * transport )
{
unsigned int state = transport - > inet - > sk_state ;
if ( state = = TCP_CLOSE & & transport - > sock - > state = = SS_UNCONNECTED )
return ;
if ( ( 1 < < state ) & ( TCPF_ESTABLISHED | TCPF_SYN_SENT ) )
return ;
xs_abort_connection ( xprt , transport ) ;
}
2007-08-06 19:57:38 +04:00
static int xs_tcp_finish_connecting ( struct rpc_xprt * xprt , struct socket * sock )
2005-08-12 00:25:23 +04:00
{
2007-08-06 19:57:38 +04:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2006-08-23 04:06:18 +04:00
2006-12-06 00:35:15 +03:00
if ( ! transport - > inet ) {
2005-08-12 00:25:53 +04:00
struct sock * sk = sock - > sk ;
write_lock_bh ( & sk - > sk_callback_lock ) ;
2008-10-28 22:21:39 +03:00
xs_save_old_callbacks ( transport , sk ) ;
2005-08-12 00:25:53 +04:00
sk - > sk_user_data = xprt ;
sk - > sk_data_ready = xs_tcp_data_ready ;
sk - > sk_state_change = xs_tcp_state_change ;
sk - > sk_write_space = xs_tcp_write_space ;
2009-03-11 21:38:00 +03:00
sk - > sk_error_report = xs_error_report ;
2005-12-14 00:13:52 +03:00
sk - > sk_allocation = GFP_ATOMIC ;
2005-08-26 03:25:55 +04:00
/* socket options */
sk - > sk_userlocks | = SOCK_BINDPORT_LOCK ;
sock_reset_flag ( sk , SOCK_LINGER ) ;
tcp_sk ( sk ) - > linger2 = 0 ;
tcp_sk ( sk ) - > nonagle | = TCP_NAGLE_OFF ;
2005-08-12 00:25:53 +04:00
xprt_clear_connected ( xprt ) ;
/* Reset to new socket */
2006-12-06 00:35:15 +03:00
transport - > sock = sock ;
transport - > inet = sk ;
2005-08-12 00:25:53 +04:00
write_unlock_bh ( & sk - > sk_callback_lock ) ;
}
2009-03-11 21:09:39 +03:00
if ( ! xprt_bound ( xprt ) )
return - ENOTCONN ;
2005-08-12 00:25:53 +04:00
/* Tell the socket layer to start connecting... */
2006-03-20 21:44:16 +03:00
xprt - > stat . connect_count + + ;
xprt - > stat . connect_start = jiffies ;
2007-08-06 19:57:58 +04:00
return kernel_connect ( sock , xs_addr ( xprt ) , xprt - > addrlen , O_NONBLOCK ) ;
2007-08-06 19:57:38 +04:00
}
2005-08-12 00:25:26 +04:00
/**
2009-03-11 21:38:04 +03:00
* xs_tcp_setup_socket - create a TCP socket and connect to a remote endpoint
* @ xprt : RPC transport to connect
* @ transport : socket transport to connect
* @ create_sock : function to create a socket of the correct type
2005-08-12 00:25:26 +04:00
*
* Invoked by a work queue tasklet .
2005-08-12 00:25:23 +04:00
*/
2009-03-11 21:38:04 +03:00
static void xs_tcp_setup_socket ( struct rpc_xprt * xprt ,
struct sock_xprt * transport ,
struct socket * ( * create_sock ) ( struct rpc_xprt * ,
struct sock_xprt * ) )
2005-08-12 00:25:23 +04:00
{
2006-12-06 00:35:15 +03:00
struct socket * sock = transport - > sock ;
2009-03-11 21:38:04 +03:00
int status = - EIO ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:09:39 +03:00
if ( xprt - > shutdown )
2005-08-12 00:25:23 +04:00
goto out ;
2006-12-06 00:35:15 +03:00
if ( ! sock ) {
2009-03-11 21:38:03 +03:00
clear_bit ( XPRT_CONNECTION_ABORT , & xprt - > state ) ;
2009-03-11 21:38:04 +03:00
sock = create_sock ( xprt , transport ) ;
if ( IS_ERR ( sock ) ) {
status = PTR_ERR ( sock ) ;
2005-08-26 03:25:55 +04:00
goto out ;
}
2009-03-11 21:38:03 +03:00
} else {
int abort_and_exit ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:38:03 +03:00
abort_and_exit = test_and_clear_bit ( XPRT_CONNECTION_ABORT ,
& xprt - > state ) ;
2005-08-26 03:25:55 +04:00
/* "close" the socket, preserving the local port */
2009-03-11 21:37:58 +03:00
xs_tcp_reuse_connection ( xprt , transport ) ;
2005-08-12 00:25:23 +04:00
2009-03-11 21:38:03 +03:00
if ( abort_and_exit )
goto out_eagain ;
}
2005-08-12 00:25:23 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: worker connecting xprt %p to address: %s \n " ,
2006-12-06 00:35:37 +03:00
xprt , xprt - > address_strings [ RPC_DISPLAY_ALL ] ) ;
2006-08-23 04:06:18 +04:00
2007-08-06 19:57:38 +04:00
status = xs_tcp_finish_connecting ( xprt , sock ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %p connect status %d connected %d sock state %d \n " ,
xprt , - status , xprt_connected ( xprt ) ,
sock - > sk - > sk_state ) ;
2009-03-11 21:38:00 +03:00
switch ( status ) {
2009-04-22 01:18:20 +04:00
default :
printk ( " %s: connect returned unhandled error %d \n " ,
__func__ , status ) ;
case - EADDRNOTAVAIL :
/* We're probably in TIME_WAIT. Get rid of existing socket,
* and retry
*/
set_bit ( XPRT_CONNECTION_CLOSE , & xprt - > state ) ;
xprt_force_disconnect ( xprt ) ;
2009-03-11 21:38:01 +03:00
case - ECONNREFUSED :
case - ECONNRESET :
case - ENETUNREACH :
/* retry with existing socket, after a delay */
2009-03-11 21:38:00 +03:00
case 0 :
case - EINPROGRESS :
case - EALREADY :
2009-03-11 21:38:03 +03:00
xprt_clear_connecting ( xprt ) ;
return ;
2005-08-12 00:25:23 +04:00
}
2009-03-11 21:38:03 +03:00
out_eagain :
2009-03-11 21:38:00 +03:00
status = - EAGAIN ;
2005-08-12 00:25:23 +04:00
out :
2007-08-06 19:57:48 +04:00
xprt_clear_connecting ( xprt ) ;
2009-03-11 21:38:03 +03:00
xprt_wake_pending_tasks ( xprt , status ) ;
2007-08-06 19:57:48 +04:00
}
2005-08-12 00:25:53 +04:00
2009-03-11 21:38:04 +03:00
static struct socket * xs_create_tcp_sock4 ( struct rpc_xprt * xprt ,
struct sock_xprt * transport )
{
struct socket * sock ;
int err ;
/* start from scratch */
err = sock_create_kern ( PF_INET , SOCK_STREAM , IPPROTO_TCP , & sock ) ;
if ( err < 0 ) {
dprintk ( " RPC: can't create TCP transport socket (%d). \n " ,
- err ) ;
goto out_err ;
}
xs_reclassify_socket4 ( sock ) ;
if ( xs_bind4 ( transport , sock ) < 0 ) {
sock_release ( sock ) ;
goto out_err ;
}
return sock ;
out_err :
return ERR_PTR ( - EIO ) ;
2007-08-06 19:57:48 +04:00
}
2005-08-12 00:25:53 +04:00
2007-08-06 19:57:48 +04:00
/**
2009-03-11 21:38:04 +03:00
* xs_tcp_connect_worker4 - connect a TCP socket to a remote endpoint
2007-08-06 19:57:48 +04:00
* @ work : RPC transport to connect
*
* Invoked by a work queue tasklet .
*/
2009-03-11 21:38:04 +03:00
static void xs_tcp_connect_worker4 ( struct work_struct * work )
2007-08-06 19:57:48 +04:00
{
struct sock_xprt * transport =
container_of ( work , struct sock_xprt , connect_worker . work ) ;
struct rpc_xprt * xprt = & transport - > xprt ;
2005-08-26 03:25:55 +04:00
2009-03-11 21:38:04 +03:00
xs_tcp_setup_socket ( xprt , transport , xs_create_tcp_sock4 ) ;
}
2005-08-12 00:25:53 +04:00
2009-03-11 21:38:04 +03:00
static struct socket * xs_create_tcp_sock6 ( struct rpc_xprt * xprt ,
struct sock_xprt * transport )
{
struct socket * sock ;
int err ;
2009-03-11 21:38:03 +03:00
2009-03-11 21:38:04 +03:00
/* start from scratch */
err = sock_create_kern ( PF_INET6 , SOCK_STREAM , IPPROTO_TCP , & sock ) ;
if ( err < 0 ) {
dprintk ( " RPC: can't create TCP transport socket (%d). \n " ,
- err ) ;
goto out_err ;
}
xs_reclassify_socket6 ( sock ) ;
2005-08-12 00:25:53 +04:00
2009-03-11 21:38:04 +03:00
if ( xs_bind6 ( transport , sock ) < 0 ) {
sock_release ( sock ) ;
goto out_err ;
2009-03-11 21:38:03 +03:00
}
2009-03-11 21:38:04 +03:00
return sock ;
out_err :
return ERR_PTR ( - EIO ) ;
}
2005-08-12 00:25:53 +04:00
2009-03-11 21:38:04 +03:00
/**
* xs_tcp_connect_worker6 - connect a TCP socket to a remote endpoint
* @ work : RPC transport to connect
*
* Invoked by a work queue tasklet .
*/
static void xs_tcp_connect_worker6 ( struct work_struct * work )
{
struct sock_xprt * transport =
container_of ( work , struct sock_xprt , connect_worker . work ) ;
struct rpc_xprt * xprt = & transport - > xprt ;
2005-08-12 00:25:53 +04:00
2009-03-11 21:38:04 +03:00
xs_tcp_setup_socket ( xprt , transport , xs_create_tcp_sock6 ) ;
2005-08-12 00:25:23 +04:00
}
2005-08-12 00:25:26 +04:00
/**
* xs_connect - connect a socket to a remote endpoint
* @ task : address of RPC task that manages state of connect request
*
* TCP : If the remote end dropped the connection , delay reconnecting .
2005-08-26 03:25:55 +04:00
*
* UDP socket connects are synchronous , but we use a work queue anyway
* to guarantee that even unprivileged user processes can set up a
* socket on a privileged port .
*
* If a UDP socket connect fails , the delay behavior here prevents
* retry floods ( hard mounts ) .
2005-08-12 00:25:26 +04:00
*/
static void xs_connect ( struct rpc_task * task )
2005-08-12 00:25:23 +04:00
{
struct rpc_xprt * xprt = task - > tk_xprt ;
2006-12-06 00:35:15 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:53 +04:00
if ( xprt_test_and_set_connecting ( xprt ) )
return ;
2006-12-06 00:35:15 +03:00
if ( transport - > sock ! = NULL ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_connect delayed xprt %p for %lu "
" seconds \n " ,
2005-08-26 03:25:55 +04:00
xprt , xprt - > reestablish_timeout / HZ ) ;
2007-06-15 02:00:42 +04:00
queue_delayed_work ( rpciod_workqueue ,
& transport - > connect_worker ,
xprt - > reestablish_timeout ) ;
2005-08-26 03:25:55 +04:00
xprt - > reestablish_timeout < < = 1 ;
if ( xprt - > reestablish_timeout > XS_TCP_MAX_REEST_TO )
xprt - > reestablish_timeout = XS_TCP_MAX_REEST_TO ;
2005-08-12 00:25:53 +04:00
} else {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_connect scheduled xprt %p \n " , xprt ) ;
2007-06-15 02:00:42 +04:00
queue_delayed_work ( rpciod_workqueue ,
& transport - > connect_worker , 0 ) ;
2005-08-12 00:25:23 +04:00
}
}
2007-11-05 23:44:12 +03:00
static void xs_tcp_connect ( struct rpc_task * task )
{
struct rpc_xprt * xprt = task - > tk_xprt ;
/* Exit if we need to wait for socket shutdown to complete */
if ( test_bit ( XPRT_CLOSING , & xprt - > state ) )
return ;
xs_connect ( task ) ;
}
2006-03-20 21:44:16 +03:00
/**
* xs_udp_print_stats - display UDP socket - specifc stats
* @ xprt : rpc_xprt struct containing statistics
* @ seq : output file
*
*/
static void xs_udp_print_stats ( struct rpc_xprt * xprt , struct seq_file * seq )
{
2006-12-06 00:35:26 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2006-03-20 21:44:16 +03:00
seq_printf ( seq , " \t xprt: \t udp %u %lu %lu %lu %lu %Lu %Lu \n " ,
2006-12-06 00:35:26 +03:00
transport - > port ,
2006-03-20 21:44:16 +03:00
xprt - > stat . bind_count ,
xprt - > stat . sends ,
xprt - > stat . recvs ,
xprt - > stat . bad_xids ,
xprt - > stat . req_u ,
xprt - > stat . bklog_u ) ;
}
/**
* xs_tcp_print_stats - display TCP socket - specifc stats
* @ xprt : rpc_xprt struct containing statistics
* @ seq : output file
*
*/
static void xs_tcp_print_stats ( struct rpc_xprt * xprt , struct seq_file * seq )
{
2006-12-06 00:35:26 +03:00
struct sock_xprt * transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2006-03-20 21:44:16 +03:00
long idle_time = 0 ;
if ( xprt_connected ( xprt ) )
idle_time = ( long ) ( jiffies - xprt - > last_used ) / HZ ;
seq_printf ( seq , " \t xprt: \t tcp %u %lu %lu %lu %ld %lu %lu %lu %Lu %Lu \n " ,
2006-12-06 00:35:26 +03:00
transport - > port ,
2006-03-20 21:44:16 +03:00
xprt - > stat . bind_count ,
xprt - > stat . connect_count ,
xprt - > stat . connect_time ,
idle_time ,
xprt - > stat . sends ,
xprt - > stat . recvs ,
xprt - > stat . bad_xids ,
xprt - > stat . req_u ,
xprt - > stat . bklog_u ) ;
}
2005-08-12 00:25:56 +04:00
static struct rpc_xprt_ops xs_udp_ops = {
2005-08-26 03:25:49 +04:00
. set_buffer_size = xs_udp_set_buffer_size ,
2005-08-26 03:25:51 +04:00
. reserve_xprt = xprt_reserve_xprt_cong ,
2005-08-26 03:25:51 +04:00
. release_xprt = xprt_release_xprt_cong ,
2007-07-01 20:13:17 +04:00
. rpcbind = rpcb_getport_async ,
2006-01-03 11:55:51 +03:00
. set_port = xs_set_port ,
2005-08-12 00:25:56 +04:00
. connect = xs_connect ,
2006-01-03 11:55:49 +03:00
. buf_alloc = rpc_malloc ,
. buf_free = rpc_free ,
2005-08-12 00:25:56 +04:00
. send_request = xs_udp_send_request ,
2005-08-26 03:25:50 +04:00
. set_retrans_timeout = xprt_set_retrans_timeout_rtt ,
2005-08-26 03:25:52 +04:00
. timer = xs_udp_timer ,
2005-08-26 03:25:53 +04:00
. release_request = xprt_release_rqst_cong ,
2005-08-12 00:25:56 +04:00
. close = xs_close ,
. destroy = xs_destroy ,
2006-03-20 21:44:16 +03:00
. print_stats = xs_udp_print_stats ,
2005-08-12 00:25:56 +04:00
} ;
static struct rpc_xprt_ops xs_tcp_ops = {
2005-08-26 03:25:51 +04:00
. reserve_xprt = xprt_reserve_xprt ,
2006-07-28 01:22:50 +04:00
. release_xprt = xs_tcp_release_xprt ,
2007-07-01 20:13:17 +04:00
. rpcbind = rpcb_getport_async ,
2006-01-03 11:55:51 +03:00
. set_port = xs_set_port ,
2007-11-05 23:44:12 +03:00
. connect = xs_tcp_connect ,
2006-01-03 11:55:49 +03:00
. buf_alloc = rpc_malloc ,
. buf_free = rpc_free ,
2005-08-12 00:25:56 +04:00
. send_request = xs_tcp_send_request ,
2005-08-26 03:25:50 +04:00
. set_retrans_timeout = xprt_set_retrans_timeout_def ,
2009-04-22 01:18:20 +04:00
. close = xs_tcp_close ,
2005-08-12 00:25:26 +04:00
. destroy = xs_destroy ,
2006-03-20 21:44:16 +03:00
. print_stats = xs_tcp_print_stats ,
2005-08-12 00:25:23 +04:00
} ;
2007-09-10 21:47:07 +04:00
static struct rpc_xprt * xs_setup_xprt ( struct xprt_create * args ,
2007-09-10 21:46:39 +04:00
unsigned int slot_table_size )
2006-10-17 22:44:27 +04:00
{
struct rpc_xprt * xprt ;
2006-12-06 00:35:11 +03:00
struct sock_xprt * new ;
2006-10-17 22:44:27 +04:00
2007-07-08 15:08:54 +04:00
if ( args - > addrlen > sizeof ( xprt - > addr ) ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_setup_xprt: address too large \n " ) ;
2006-10-17 22:44:27 +04:00
return ERR_PTR ( - EBADF ) ;
}
2006-12-06 00:35:11 +03:00
new = kzalloc ( sizeof ( * new ) , GFP_KERNEL ) ;
if ( new = = NULL ) {
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_setup_xprt: couldn't allocate "
" rpc_xprt \n " ) ;
2006-10-17 22:44:27 +04:00
return ERR_PTR ( - ENOMEM ) ;
}
2006-12-06 00:35:11 +03:00
xprt = & new - > xprt ;
2006-10-17 22:44:27 +04:00
xprt - > max_reqs = slot_table_size ;
xprt - > slot = kcalloc ( xprt - > max_reqs , sizeof ( struct rpc_rqst ) , GFP_KERNEL ) ;
if ( xprt - > slot = = NULL ) {
kfree ( xprt ) ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: xs_setup_xprt: couldn't allocate slot "
" table \n " ) ;
2006-10-17 22:44:27 +04:00
return ERR_PTR ( - ENOMEM ) ;
}
2007-07-08 15:08:54 +04:00
memcpy ( & xprt - > addr , args - > dstaddr , args - > addrlen ) ;
xprt - > addrlen = args - > addrlen ;
2007-07-10 00:23:35 +04:00
if ( args - > srcaddr )
memcpy ( & new - > addr , args - > srcaddr , args - > addrlen ) ;
2006-10-17 22:44:27 +04:00
return xprt ;
}
2007-12-21 00:03:54 +03:00
static const struct rpc_timeout xs_udp_default_timeout = {
. to_initval = 5 * HZ ,
. to_maxval = 30 * HZ ,
. to_increment = 5 * HZ ,
. to_retries = 5 ,
} ;
2005-08-12 00:25:26 +04:00
/**
* xs_setup_udp - Set up transport to use a UDP socket
2007-07-08 15:08:54 +04:00
* @ args : rpc transport creation arguments
2005-08-12 00:25:26 +04:00
*
*/
2007-10-24 20:24:02 +04:00
static struct rpc_xprt * xs_setup_udp ( struct xprt_create * args )
2005-08-12 00:25:23 +04:00
{
2007-08-06 19:57:53 +04:00
struct sockaddr * addr = args - > dstaddr ;
2006-10-17 22:44:27 +04:00
struct rpc_xprt * xprt ;
2006-12-06 00:35:26 +03:00
struct sock_xprt * transport ;
2005-08-12 00:25:23 +04:00
2007-07-08 15:08:54 +04:00
xprt = xs_setup_xprt ( args , xprt_udp_slot_table_entries ) ;
2006-10-17 22:44:27 +04:00
if ( IS_ERR ( xprt ) )
return xprt ;
2006-12-06 00:35:26 +03:00
transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
2006-08-23 04:06:15 +04:00
xprt - > prot = IPPROTO_UDP ;
2005-08-26 03:25:49 +04:00
xprt - > tsh_size = 0 ;
2005-08-12 00:25:23 +04:00
/* XXX: header size can vary due to auth type, IPv6, etc. */
xprt - > max_payload = ( 1U < < 16 ) - ( MAX_HEADER < < 3 ) ;
2005-08-26 03:25:55 +04:00
xprt - > bind_timeout = XS_BIND_TO ;
xprt - > connect_timeout = XS_UDP_CONN_TO ;
xprt - > reestablish_timeout = XS_UDP_REEST_TO ;
xprt - > idle_timeout = XS_IDLE_DISC_TO ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
xprt - > ops = & xs_udp_ops ;
2005-08-12 00:25:23 +04:00
2007-12-21 00:03:55 +03:00
xprt - > timeout = & xs_udp_default_timeout ;
2005-08-12 00:25:23 +04:00
2007-08-06 19:57:53 +04:00
switch ( addr - > sa_family ) {
case AF_INET :
if ( ( ( struct sockaddr_in * ) addr ) - > sin_port ! = htons ( 0 ) )
xprt_set_bound ( xprt ) ;
INIT_DELAYED_WORK ( & transport - > connect_worker ,
xs_udp_connect_worker4 ) ;
2008-01-08 02:34:48 +03:00
xs_format_ipv4_peer_addresses ( xprt , " udp " , RPCBIND_NETID_UDP ) ;
2007-08-06 19:57:53 +04:00
break ;
case AF_INET6 :
if ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ! = htons ( 0 ) )
xprt_set_bound ( xprt ) ;
INIT_DELAYED_WORK ( & transport - > connect_worker ,
xs_udp_connect_worker6 ) ;
2008-01-08 02:34:48 +03:00
xs_format_ipv6_peer_addresses ( xprt , " udp " , RPCBIND_NETID_UDP6 ) ;
2007-08-06 19:57:53 +04:00
break ;
default :
kfree ( xprt ) ;
return ERR_PTR ( - EAFNOSUPPORT ) ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: set up transport to address %s \n " ,
2006-12-06 00:35:37 +03:00
xprt - > address_strings [ RPC_DISPLAY_ALL ] ) ;
2006-08-23 04:06:18 +04:00
2007-09-10 21:46:39 +04:00
if ( try_module_get ( THIS_MODULE ) )
return xprt ;
kfree ( xprt - > slot ) ;
kfree ( xprt ) ;
return ERR_PTR ( - EINVAL ) ;
2005-08-12 00:25:23 +04:00
}
2007-12-21 00:03:54 +03:00
static const struct rpc_timeout xs_tcp_default_timeout = {
. to_initval = 60 * HZ ,
. to_maxval = 60 * HZ ,
. to_retries = 2 ,
} ;
2005-08-12 00:25:26 +04:00
/**
* xs_setup_tcp - Set up transport to use a TCP socket
2007-07-08 15:08:54 +04:00
* @ args : rpc transport creation arguments
2005-08-12 00:25:26 +04:00
*
*/
2007-10-24 20:24:02 +04:00
static struct rpc_xprt * xs_setup_tcp ( struct xprt_create * args )
2005-08-12 00:25:23 +04:00
{
2007-08-06 19:57:53 +04:00
struct sockaddr * addr = args - > dstaddr ;
2006-10-17 22:44:27 +04:00
struct rpc_xprt * xprt ;
2006-12-06 00:35:26 +03:00
struct sock_xprt * transport ;
2005-08-12 00:25:23 +04:00
2007-07-08 15:08:54 +04:00
xprt = xs_setup_xprt ( args , xprt_tcp_slot_table_entries ) ;
2006-10-17 22:44:27 +04:00
if ( IS_ERR ( xprt ) )
return xprt ;
2006-12-06 00:35:26 +03:00
transport = container_of ( xprt , struct sock_xprt , xprt ) ;
2005-08-12 00:25:23 +04:00
2006-08-23 04:06:15 +04:00
xprt - > prot = IPPROTO_TCP ;
2005-08-26 03:25:49 +04:00
xprt - > tsh_size = sizeof ( rpc_fraghdr ) / sizeof ( u32 ) ;
xprt - > max_payload = RPC_MAX_FRAGMENT_SIZE ;
2005-08-12 00:25:23 +04:00
2005-08-26 03:25:55 +04:00
xprt - > bind_timeout = XS_BIND_TO ;
xprt - > connect_timeout = XS_TCP_CONN_TO ;
xprt - > reestablish_timeout = XS_TCP_INIT_REEST_TO ;
xprt - > idle_timeout = XS_IDLE_DISC_TO ;
2005-08-12 00:25:23 +04:00
2005-08-12 00:25:56 +04:00
xprt - > ops = & xs_tcp_ops ;
2007-12-21 00:03:55 +03:00
xprt - > timeout = & xs_tcp_default_timeout ;
2005-08-12 00:25:23 +04:00
2007-08-06 19:57:53 +04:00
switch ( addr - > sa_family ) {
case AF_INET :
if ( ( ( struct sockaddr_in * ) addr ) - > sin_port ! = htons ( 0 ) )
xprt_set_bound ( xprt ) ;
INIT_DELAYED_WORK ( & transport - > connect_worker , xs_tcp_connect_worker4 ) ;
2008-01-08 02:34:48 +03:00
xs_format_ipv4_peer_addresses ( xprt , " tcp " , RPCBIND_NETID_TCP ) ;
2007-08-06 19:57:53 +04:00
break ;
case AF_INET6 :
if ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ! = htons ( 0 ) )
xprt_set_bound ( xprt ) ;
INIT_DELAYED_WORK ( & transport - > connect_worker , xs_tcp_connect_worker6 ) ;
2008-01-08 02:34:48 +03:00
xs_format_ipv6_peer_addresses ( xprt , " tcp " , RPCBIND_NETID_TCP6 ) ;
2007-08-06 19:57:53 +04:00
break ;
default :
kfree ( xprt ) ;
return ERR_PTR ( - EAFNOSUPPORT ) ;
}
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: set up transport to address %s \n " ,
2006-12-06 00:35:37 +03:00
xprt - > address_strings [ RPC_DISPLAY_ALL ] ) ;
2006-08-23 04:06:18 +04:00
2007-09-10 21:46:39 +04:00
if ( try_module_get ( THIS_MODULE ) )
return xprt ;
kfree ( xprt - > slot ) ;
kfree ( xprt ) ;
return ERR_PTR ( - EINVAL ) ;
2005-08-12 00:25:23 +04:00
}
2006-12-06 00:35:51 +03:00
2007-09-10 21:46:39 +04:00
static struct xprt_class xs_udp_transport = {
. list = LIST_HEAD_INIT ( xs_udp_transport . list ) ,
. name = " udp " ,
. owner = THIS_MODULE ,
2007-09-10 21:47:57 +04:00
. ident = IPPROTO_UDP ,
2007-09-10 21:46:39 +04:00
. setup = xs_setup_udp ,
} ;
static struct xprt_class xs_tcp_transport = {
. list = LIST_HEAD_INIT ( xs_tcp_transport . list ) ,
. name = " tcp " ,
. owner = THIS_MODULE ,
2007-09-10 21:47:57 +04:00
. ident = IPPROTO_TCP ,
2007-09-10 21:46:39 +04:00
. setup = xs_setup_tcp ,
} ;
2006-12-06 00:35:51 +03:00
/**
2007-09-10 21:46:39 +04:00
* init_socket_xprt - set up xprtsock ' s sysctls , register with RPC client
2006-12-06 00:35:51 +03:00
*
*/
int init_socket_xprt ( void )
{
2006-12-06 00:35:54 +03:00
# ifdef RPC_DEBUG
2007-02-14 11:33:24 +03:00
if ( ! sunrpc_table_header )
2007-02-14 11:34:09 +03:00
sunrpc_table_header = register_sysctl_table ( sunrpc_table ) ;
2006-12-06 00:35:54 +03:00
# endif
2007-09-10 21:46:39 +04:00
xprt_register_transport ( & xs_udp_transport ) ;
xprt_register_transport ( & xs_tcp_transport ) ;
2006-12-06 00:35:51 +03:00
return 0 ;
}
/**
2007-09-10 21:46:39 +04:00
* cleanup_socket_xprt - remove xprtsock ' s sysctls , unregister
2006-12-06 00:35:51 +03:00
*
*/
void cleanup_socket_xprt ( void )
{
2006-12-06 00:35:54 +03:00
# ifdef RPC_DEBUG
if ( sunrpc_table_header ) {
unregister_sysctl_table ( sunrpc_table_header ) ;
sunrpc_table_header = NULL ;
}
# endif
2007-09-10 21:46:39 +04:00
xprt_unregister_transport ( & xs_udp_transport ) ;
xprt_unregister_transport ( & xs_tcp_transport ) ;
2006-12-06 00:35:51 +03:00
}