Merge branch 'for-2.6.31' of git://fieldses.org/git/linux-nfsd
* 'for-2.6.31' of git://fieldses.org/git/linux-nfsd: (60 commits) SUNRPC: Fix the TCP server's send buffer accounting nfsd41: Backchannel: minorversion support for the back channel nfsd41: Backchannel: cleanup nfs4.0 callback encode routines nfsd41: Remove ip address collision detection case nfsd: optimise the starting of zero threads when none are running. nfsd: don't take nfsd_mutex twice when setting number of threads. nfsd41: sanity check client drc maxreqs nfsd41: move channel attributes from nfsd4_session to a nfsd4_channel_attr struct NFS: kill off complicated macro 'PROC' sunrpc: potential memory leak in function rdma_read_xdr nfsd: minor nfsd_vfs_write cleanup nfsd: Pull write-gathering code out of nfsd_vfs_write nfsd: track last inode only in use_wgather case sunrpc: align cache_clean work's timer nfsd: Use write gathering only with NFSv2 NFSv4: kill off complicated macro 'PROC' NFSv4: do exact check about attribute specified knfsd: remove unreported filehandle stats counters knfsd: fix reply cache memory corruption knfsd: reply cache cleanups ...
This commit is contained in:
@@ -488,7 +488,7 @@ static void do_cache_clean(struct work_struct *work)
|
||||
{
|
||||
int delay = 5;
|
||||
if (cache_clean() == -1)
|
||||
delay = 30*HZ;
|
||||
delay = round_jiffies_relative(30*HZ);
|
||||
|
||||
if (list_empty(&cache_list))
|
||||
delay = 0;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <net/sock.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/svc_xprt.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
||||
|
||||
@@ -1097,36 +1098,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_find_xprt);
|
||||
|
||||
/*
|
||||
* Format a buffer with a list of the active transports. A zero for
|
||||
* the buflen parameter disables target buffer overflow checking.
|
||||
static int svc_one_xprt_name(const struct svc_xprt *xprt,
|
||||
char *pos, int remaining)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = snprintf(pos, remaining, "%s %u\n",
|
||||
xprt->xpt_class->xcl_name,
|
||||
svc_xprt_local_port(xprt));
|
||||
if (len >= remaining)
|
||||
return -ENAMETOOLONG;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_xprt_names - format a buffer with a list of transport names
|
||||
* @serv: pointer to an RPC service
|
||||
* @buf: pointer to a buffer to be filled in
|
||||
* @buflen: length of buffer to be filled in
|
||||
*
|
||||
* Fills in @buf with a string containing a list of transport names,
|
||||
* each name terminated with '\n'.
|
||||
*
|
||||
* Returns positive length of the filled-in string on success; otherwise
|
||||
* a negative errno value is returned if an error occurs.
|
||||
*/
|
||||
int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
|
||||
int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
|
||||
{
|
||||
struct svc_xprt *xprt;
|
||||
char xprt_str[64];
|
||||
int totlen = 0;
|
||||
int len;
|
||||
int len, totlen;
|
||||
char *pos;
|
||||
|
||||
/* Sanity check args */
|
||||
if (!serv)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
|
||||
pos = buf;
|
||||
totlen = 0;
|
||||
list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
|
||||
len = snprintf(xprt_str, sizeof(xprt_str),
|
||||
"%s %d\n", xprt->xpt_class->xcl_name,
|
||||
svc_xprt_local_port(xprt));
|
||||
/* If the string was truncated, replace with error string */
|
||||
if (len >= sizeof(xprt_str))
|
||||
strcpy(xprt_str, "name-too-long\n");
|
||||
/* Don't overflow buffer */
|
||||
len = strlen(xprt_str);
|
||||
if (buflen && (len + totlen >= buflen))
|
||||
len = svc_one_xprt_name(xprt, pos, buflen - totlen);
|
||||
if (len < 0) {
|
||||
*buf = '\0';
|
||||
totlen = len;
|
||||
}
|
||||
if (len <= 0)
|
||||
break;
|
||||
strcpy(buf+totlen, xprt_str);
|
||||
|
||||
pos += len;
|
||||
totlen += len;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
return totlen;
|
||||
}
|
||||
|
||||
@@ -240,42 +240,76 @@ out:
|
||||
/*
|
||||
* Report socket names for nfsdfs
|
||||
*/
|
||||
static int one_sock_name(char *buf, struct svc_sock *svsk)
|
||||
static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining)
|
||||
{
|
||||
const struct sock *sk = svsk->sk_sk;
|
||||
const char *proto_name = sk->sk_protocol == IPPROTO_UDP ?
|
||||
"udp" : "tcp";
|
||||
int len;
|
||||
|
||||
switch(svsk->sk_sk->sk_family) {
|
||||
case AF_INET:
|
||||
len = sprintf(buf, "ipv4 %s %pI4 %d\n",
|
||||
svsk->sk_sk->sk_protocol == IPPROTO_UDP ?
|
||||
"udp" : "tcp",
|
||||
&inet_sk(svsk->sk_sk)->rcv_saddr,
|
||||
inet_sk(svsk->sk_sk)->num);
|
||||
switch (sk->sk_family) {
|
||||
case PF_INET:
|
||||
len = snprintf(buf, remaining, "ipv4 %s %pI4 %d\n",
|
||||
proto_name,
|
||||
&inet_sk(sk)->rcv_saddr,
|
||||
inet_sk(sk)->num);
|
||||
break;
|
||||
case PF_INET6:
|
||||
len = snprintf(buf, remaining, "ipv6 %s %pI6 %d\n",
|
||||
proto_name,
|
||||
&inet6_sk(sk)->rcv_saddr,
|
||||
inet_sk(sk)->num);
|
||||
break;
|
||||
default:
|
||||
len = sprintf(buf, "*unknown-%d*\n",
|
||||
svsk->sk_sk->sk_family);
|
||||
len = snprintf(buf, remaining, "*unknown-%d*\n",
|
||||
sk->sk_family);
|
||||
}
|
||||
|
||||
if (len >= remaining) {
|
||||
*buf = '\0';
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int
|
||||
svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
|
||||
/**
|
||||
* svc_sock_names - construct a list of listener names in a string
|
||||
* @serv: pointer to RPC service
|
||||
* @buf: pointer to a buffer to fill in with socket names
|
||||
* @buflen: size of the buffer to be filled
|
||||
* @toclose: pointer to '\0'-terminated C string containing the name
|
||||
* of a listener to be closed
|
||||
*
|
||||
* Fills in @buf with a '\n'-separated list of names of listener
|
||||
* sockets. If @toclose is not NULL, the socket named by @toclose
|
||||
* is closed, and is not included in the output list.
|
||||
*
|
||||
* Returns positive length of the socket name string, or a negative
|
||||
* errno value on error.
|
||||
*/
|
||||
int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
|
||||
const char *toclose)
|
||||
{
|
||||
struct svc_sock *svsk, *closesk = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (!serv)
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
list_for_each_entry(svsk, &serv->sv_permsocks, sk_xprt.xpt_list) {
|
||||
int onelen = one_sock_name(buf+len, svsk);
|
||||
if (toclose && strcmp(toclose, buf+len) == 0)
|
||||
int onelen = svc_one_sock_name(svsk, buf + len, buflen - len);
|
||||
if (onelen < 0) {
|
||||
len = onelen;
|
||||
break;
|
||||
}
|
||||
if (toclose && strcmp(toclose, buf + len) == 0)
|
||||
closesk = svsk;
|
||||
else
|
||||
len += onelen;
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
|
||||
if (closesk)
|
||||
/* Should unregister with portmap, but you cannot
|
||||
* unregister just one protocol...
|
||||
@@ -346,6 +380,7 @@ static void svc_sock_setbufsize(struct socket *sock, unsigned int snd,
|
||||
sock->sk->sk_sndbuf = snd * 2;
|
||||
sock->sk->sk_rcvbuf = rcv * 2;
|
||||
sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK;
|
||||
sock->sk->sk_write_space(sock->sk);
|
||||
release_sock(sock->sk);
|
||||
#endif
|
||||
}
|
||||
@@ -387,6 +422,15 @@ static void svc_write_space(struct sock *sk)
|
||||
}
|
||||
}
|
||||
|
||||
static void svc_tcp_write_space(struct sock *sk)
|
||||
{
|
||||
struct socket *sock = sk->sk_socket;
|
||||
|
||||
if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && sock)
|
||||
clear_bit(SOCK_NOSPACE, &sock->flags);
|
||||
svc_write_space(sk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the UDP datagram's destination address to the rqstp structure.
|
||||
* The 'destination' address in this case is the address to which the
|
||||
@@ -427,13 +471,14 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
||||
long all[SVC_PKTINFO_SPACE / sizeof(long)];
|
||||
} buffer;
|
||||
struct cmsghdr *cmh = &buffer.hdr;
|
||||
int err, len;
|
||||
struct msghdr msg = {
|
||||
.msg_name = svc_addr(rqstp),
|
||||
.msg_control = cmh,
|
||||
.msg_controllen = sizeof(buffer),
|
||||
.msg_flags = MSG_DONTWAIT,
|
||||
};
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
if (test_and_clear_bit(XPT_CHNGBUF, &svsk->sk_xprt.xpt_flags))
|
||||
/* udp sockets need large rcvbuf as all pending
|
||||
@@ -465,8 +510,8 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp)
|
||||
return -EAGAIN;
|
||||
}
|
||||
len = svc_addr_len(svc_addr(rqstp));
|
||||
if (len < 0)
|
||||
return len;
|
||||
if (len == 0)
|
||||
return -EAFNOSUPPORT;
|
||||
rqstp->rq_addrlen = len;
|
||||
if (skb->tstamp.tv64 == 0) {
|
||||
skb->tstamp = ktime_get_real();
|
||||
@@ -980,25 +1025,16 @@ static void svc_tcp_prep_reply_hdr(struct svc_rqst *rqstp)
|
||||
static int svc_tcp_has_wspace(struct svc_xprt *xprt)
|
||||
{
|
||||
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
||||
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
|
||||
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
|
||||
int required;
|
||||
int wspace;
|
||||
|
||||
/*
|
||||
* Set the SOCK_NOSPACE flag before checking the available
|
||||
* sock space.
|
||||
*/
|
||||
if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
|
||||
return 1;
|
||||
required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg;
|
||||
if (sk_stream_wspace(svsk->sk_sk) >= required)
|
||||
return 1;
|
||||
set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
|
||||
required = atomic_read(&svsk->sk_xprt.xpt_reserved) + serv->sv_max_mesg;
|
||||
wspace = sk_stream_wspace(svsk->sk_sk);
|
||||
|
||||
if (wspace < sk_stream_min_wspace(svsk->sk_sk))
|
||||
return 0;
|
||||
if (required * 2 > wspace)
|
||||
return 0;
|
||||
|
||||
clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
|
||||
@@ -1054,7 +1090,7 @@ static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
||||
dprintk("setting up TCP socket for reading\n");
|
||||
sk->sk_state_change = svc_tcp_state_change;
|
||||
sk->sk_data_ready = svc_tcp_data_ready;
|
||||
sk->sk_write_space = svc_write_space;
|
||||
sk->sk_write_space = svc_tcp_write_space;
|
||||
|
||||
svsk->sk_reclen = 0;
|
||||
svsk->sk_tcplen = 0;
|
||||
@@ -1148,9 +1184,19 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
|
||||
return svsk;
|
||||
}
|
||||
|
||||
int svc_addsock(struct svc_serv *serv,
|
||||
int fd,
|
||||
char *name_return)
|
||||
/**
|
||||
* svc_addsock - add a listener socket to an RPC service
|
||||
* @serv: pointer to RPC service to which to add a new listener
|
||||
* @fd: file descriptor of the new listener
|
||||
* @name_return: pointer to buffer to fill in with name of listener
|
||||
* @len: size of the buffer
|
||||
*
|
||||
* Fills in socket name and returns positive length of name if successful.
|
||||
* Name is terminated with '\n'. On error, returns a negative errno
|
||||
* value.
|
||||
*/
|
||||
int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
|
||||
const size_t len)
|
||||
{
|
||||
int err = 0;
|
||||
struct socket *so = sockfd_lookup(fd, &err);
|
||||
@@ -1190,7 +1236,7 @@ int svc_addsock(struct svc_serv *serv,
|
||||
sockfd_put(so);
|
||||
return err;
|
||||
}
|
||||
return one_sock_name(name_return, svsk);
|
||||
return svc_one_sock_name(svsk, name_return, len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_addsock);
|
||||
|
||||
|
||||
@@ -397,14 +397,14 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
|
||||
if (!ch)
|
||||
return 0;
|
||||
|
||||
/* Allocate temporary reply and chunk maps */
|
||||
rpl_map = svc_rdma_get_req_map();
|
||||
chl_map = svc_rdma_get_req_map();
|
||||
|
||||
svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
|
||||
if (ch_count > RPCSVC_MAXPAGES)
|
||||
return -EINVAL;
|
||||
|
||||
/* Allocate temporary reply and chunk maps */
|
||||
rpl_map = svc_rdma_get_req_map();
|
||||
chl_map = svc_rdma_get_req_map();
|
||||
|
||||
if (!xprt->sc_frmr_pg_list_len)
|
||||
sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
|
||||
rpl_map, chl_map, ch_count,
|
||||
|
||||
Reference in New Issue
Block a user