Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
This commit is contained in:
@@ -178,27 +178,24 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||
break;
|
||||
case 's':{
|
||||
char **sptr = va_arg(ap, char **);
|
||||
int16_t len;
|
||||
int size;
|
||||
uint16_t len;
|
||||
|
||||
errcode = p9pdu_readf(pdu, proto_version,
|
||||
"w", &len);
|
||||
if (errcode)
|
||||
break;
|
||||
|
||||
size = max_t(int16_t, len, 0);
|
||||
|
||||
*sptr = kmalloc(size + 1, GFP_KERNEL);
|
||||
*sptr = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (*sptr == NULL) {
|
||||
errcode = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (pdu_read(pdu, *sptr, size)) {
|
||||
if (pdu_read(pdu, *sptr, len)) {
|
||||
errcode = -EFAULT;
|
||||
kfree(*sptr);
|
||||
*sptr = NULL;
|
||||
} else
|
||||
(*sptr)[size] = 0;
|
||||
(*sptr)[len] = 0;
|
||||
}
|
||||
break;
|
||||
case 'Q':{
|
||||
@@ -234,14 +231,14 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||
}
|
||||
break;
|
||||
case 'D':{
|
||||
int32_t *count = va_arg(ap, int32_t *);
|
||||
uint32_t *count = va_arg(ap, uint32_t *);
|
||||
void **data = va_arg(ap, void **);
|
||||
|
||||
errcode =
|
||||
p9pdu_readf(pdu, proto_version, "d", count);
|
||||
if (!errcode) {
|
||||
*count =
|
||||
min_t(int32_t, *count,
|
||||
min_t(uint32_t, *count,
|
||||
pdu->size - pdu->offset);
|
||||
*data = &pdu->sdata[pdu->offset];
|
||||
}
|
||||
@@ -404,9 +401,10 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||
break;
|
||||
case 's':{
|
||||
const char *sptr = va_arg(ap, const char *);
|
||||
int16_t len = 0;
|
||||
uint16_t len = 0;
|
||||
if (sptr)
|
||||
len = min_t(int16_t, strlen(sptr), USHRT_MAX);
|
||||
len = min_t(uint16_t, strlen(sptr),
|
||||
USHRT_MAX);
|
||||
|
||||
errcode = p9pdu_writef(pdu, proto_version,
|
||||
"w", len);
|
||||
@@ -438,7 +436,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||
stbuf->n_gid, stbuf->n_muid);
|
||||
} break;
|
||||
case 'D':{
|
||||
int32_t count = va_arg(ap, int32_t);
|
||||
uint32_t count = va_arg(ap, uint32_t);
|
||||
const void *data = va_arg(ap, const void *);
|
||||
|
||||
errcode = p9pdu_writef(pdu, proto_version, "d",
|
||||
|
@@ -253,7 +253,9 @@ config NET_TCPPROBE
|
||||
what was just said, you don't need it: say N.
|
||||
|
||||
Documentation on how to use TCP connection probing can be found
|
||||
at http://linux-net.osdl.org/index.php/TcpProbe
|
||||
at:
|
||||
|
||||
http://www.linuxfoundation.org/collaborate/workgroups/networking/tcpprobe
|
||||
|
||||
To compile this code as a module, choose M here: the
|
||||
module will be called tcp_probe.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
#include <linux/ceph/types.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Robert Jenkin's hash function.
|
||||
@@ -104,6 +105,7 @@ unsigned ceph_str_hash(int type, const char *s, unsigned len)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ceph_str_hash);
|
||||
|
||||
const char *ceph_str_hash_name(int type)
|
||||
{
|
||||
@@ -116,3 +118,4 @@ const char *ceph_str_hash_name(int type)
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ceph_str_hash_name);
|
||||
|
@@ -96,7 +96,7 @@ struct workqueue_struct *ceph_msgr_wq;
|
||||
|
||||
int ceph_msgr_init(void)
|
||||
{
|
||||
ceph_msgr_wq = create_workqueue("ceph-msgr");
|
||||
ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0);
|
||||
if (!ceph_msgr_wq) {
|
||||
pr_err("msgr_init failed to create workqueue\n");
|
||||
return -ENOMEM;
|
||||
@@ -1920,20 +1920,6 @@ bad_tag:
|
||||
/*
|
||||
* Atomically queue work on a connection. Bump @con reference to
|
||||
* avoid races with connection teardown.
|
||||
*
|
||||
* There is some trickery going on with QUEUED and BUSY because we
|
||||
* only want a _single_ thread operating on each connection at any
|
||||
* point in time, but we want to use all available CPUs.
|
||||
*
|
||||
* The worker thread only proceeds if it can atomically set BUSY. It
|
||||
* clears QUEUED and does it's thing. When it thinks it's done, it
|
||||
* clears BUSY, then rechecks QUEUED.. if it's set again, it loops
|
||||
* (tries again to set BUSY).
|
||||
*
|
||||
* To queue work, we first set QUEUED, _then_ if BUSY isn't set, we
|
||||
* try to queue work. If that fails (work is already queued, or BUSY)
|
||||
* we give up (work also already being done or is queued) but leave QUEUED
|
||||
* set so that the worker thread will loop if necessary.
|
||||
*/
|
||||
static void queue_con(struct ceph_connection *con)
|
||||
{
|
||||
@@ -1948,11 +1934,7 @@ static void queue_con(struct ceph_connection *con)
|
||||
return;
|
||||
}
|
||||
|
||||
set_bit(QUEUED, &con->state);
|
||||
if (test_bit(BUSY, &con->state)) {
|
||||
dout("queue_con %p - already BUSY\n", con);
|
||||
con->ops->put(con);
|
||||
} else if (!queue_work(ceph_msgr_wq, &con->work.work)) {
|
||||
if (!queue_delayed_work(ceph_msgr_wq, &con->work, 0)) {
|
||||
dout("queue_con %p - already queued\n", con);
|
||||
con->ops->put(con);
|
||||
} else {
|
||||
@@ -1967,15 +1949,6 @@ static void con_work(struct work_struct *work)
|
||||
{
|
||||
struct ceph_connection *con = container_of(work, struct ceph_connection,
|
||||
work.work);
|
||||
int backoff = 0;
|
||||
|
||||
more:
|
||||
if (test_and_set_bit(BUSY, &con->state) != 0) {
|
||||
dout("con_work %p BUSY already set\n", con);
|
||||
goto out;
|
||||
}
|
||||
dout("con_work %p start, clearing QUEUED\n", con);
|
||||
clear_bit(QUEUED, &con->state);
|
||||
|
||||
mutex_lock(&con->mutex);
|
||||
|
||||
@@ -1994,28 +1967,13 @@ more:
|
||||
try_read(con) < 0 ||
|
||||
try_write(con) < 0) {
|
||||
mutex_unlock(&con->mutex);
|
||||
backoff = 1;
|
||||
ceph_fault(con); /* error/fault path */
|
||||
goto done_unlocked;
|
||||
}
|
||||
|
||||
done:
|
||||
mutex_unlock(&con->mutex);
|
||||
|
||||
done_unlocked:
|
||||
clear_bit(BUSY, &con->state);
|
||||
dout("con->state=%lu\n", con->state);
|
||||
if (test_bit(QUEUED, &con->state)) {
|
||||
if (!backoff || test_bit(OPENING, &con->state)) {
|
||||
dout("con_work %p QUEUED reset, looping\n", con);
|
||||
goto more;
|
||||
}
|
||||
dout("con_work %p QUEUED reset, but just faulted\n", con);
|
||||
clear_bit(QUEUED, &con->state);
|
||||
}
|
||||
dout("con_work %p done\n", con);
|
||||
|
||||
out:
|
||||
con->ops->put(con);
|
||||
}
|
||||
|
||||
|
@@ -605,8 +605,10 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end)
|
||||
goto bad;
|
||||
}
|
||||
err = __decode_pool(p, end, pi);
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
kfree(pi);
|
||||
goto bad;
|
||||
}
|
||||
__insert_pg_pool(&map->pg_pools, pi);
|
||||
}
|
||||
|
||||
|
@@ -6190,7 +6190,7 @@ static void __net_exit default_device_exit(struct net *net)
|
||||
static void __net_exit default_device_exit_batch(struct list_head *net_list)
|
||||
{
|
||||
/* At exit all network devices most be removed from a network
|
||||
* namespace. Do this in the reverse order of registeration.
|
||||
* namespace. Do this in the reverse order of registration.
|
||||
* Do this across as many network namespaces as possible to
|
||||
* improve batching efficiency.
|
||||
*/
|
||||
|
@@ -157,7 +157,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
|
||||
"sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" ,
|
||||
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
|
||||
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
|
||||
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" ,
|
||||
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
|
||||
"sk_lock-AF_MAX"
|
||||
};
|
||||
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
|
||||
@@ -173,7 +173,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
|
||||
"slock-27" , "slock-28" , "slock-AF_CAN" ,
|
||||
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
|
||||
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
|
||||
"slock-AF_IEEE802154", "slock-AF_CAIF" ,
|
||||
"slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
|
||||
"slock-AF_MAX"
|
||||
};
|
||||
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
|
||||
@@ -189,7 +189,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
|
||||
"clock-27" , "clock-28" , "clock-AF_CAN" ,
|
||||
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
|
||||
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
|
||||
"clock-AF_IEEE802154", "clock-AF_CAIF" ,
|
||||
"clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
|
||||
"clock-AF_MAX"
|
||||
};
|
||||
|
||||
|
@@ -49,7 +49,9 @@ config NET_DCCPPROBE
|
||||
what was just said, you don't need it: say N.
|
||||
|
||||
Documentation on how to use DCCP connection probing can be found
|
||||
at http://linux-net.osdl.org/index.php/DccpProbe
|
||||
at:
|
||||
|
||||
http://www.linuxfoundation.org/collaborate/workgroups/networking/dccpprobe
|
||||
|
||||
To compile this code as a module, choose M here: the
|
||||
module will be called dccp_probe.
|
||||
|
@@ -1130,7 +1130,7 @@ static struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
|
||||
/*
|
||||
* This processes a device up event. We only start up
|
||||
* the loopback device & ethernet devices with correct
|
||||
* MAC addreses automatically. Others must be started
|
||||
* MAC addresses automatically. Others must be started
|
||||
* specifically.
|
||||
*
|
||||
* FIXME: How should we configure the loopback address ? If we could dispense
|
||||
|
@@ -428,7 +428,7 @@ static void __exit dsa_cleanup_module(void)
|
||||
}
|
||||
module_exit(dsa_cleanup_module);
|
||||
|
||||
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>")
|
||||
MODULE_AUTHOR("Lennert Buytenhek <buytenh@wantstofly.org>");
|
||||
MODULE_DESCRIPTION("Driver for Distributed Switch Architecture switch chips");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:dsa");
|
||||
|
@@ -432,7 +432,9 @@ config INET_DIAG
|
||||
---help---
|
||||
Support for INET (TCP, DCCP, etc) socket monitoring interface used by
|
||||
native Linux tools such as ss. ss is included in iproute2, currently
|
||||
downloadable at <http://linux-net.osdl.org/index.php/Iproute2>.
|
||||
downloadable at:
|
||||
|
||||
http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
@@ -1350,7 +1350,7 @@ static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Intialize TSO state of a skb.
|
||||
/* Initialize TSO state of a skb.
|
||||
* This must be invoked the first time we consider transmitting
|
||||
* SKB onto the wire.
|
||||
*/
|
||||
|
@@ -300,7 +300,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Reproduce AF_INET checks to make the bindings consitant */
|
||||
/* Reproduce AF_INET checks to make the bindings consistent */
|
||||
v4addr = addr->sin6_addr.s6_addr32[3];
|
||||
chk_addr_ret = inet_addr_type(net, v4addr);
|
||||
if (!sysctl_ip_nonlocal_bind &&
|
||||
|
@@ -20,7 +20,7 @@ config MAC80211_HAS_RC
|
||||
def_bool n
|
||||
|
||||
config MAC80211_RC_PID
|
||||
bool "PID controller based rate control algorithm" if EMBEDDED
|
||||
bool "PID controller based rate control algorithm" if EXPERT
|
||||
select MAC80211_HAS_RC
|
||||
---help---
|
||||
This option enables a TX rate control algorithm for
|
||||
@@ -28,14 +28,14 @@ config MAC80211_RC_PID
|
||||
rate.
|
||||
|
||||
config MAC80211_RC_MINSTREL
|
||||
bool "Minstrel" if EMBEDDED
|
||||
bool "Minstrel" if EXPERT
|
||||
select MAC80211_HAS_RC
|
||||
default y
|
||||
---help---
|
||||
This option enables the 'minstrel' TX rate control algorithm
|
||||
|
||||
config MAC80211_RC_MINSTREL_HT
|
||||
bool "Minstrel 802.11n support" if EMBEDDED
|
||||
bool "Minstrel 802.11n support" if EXPERT
|
||||
depends on MAC80211_RC_MINSTREL
|
||||
default y
|
||||
---help---
|
||||
|
@@ -18,7 +18,7 @@ config RFKILL_LEDS
|
||||
default y
|
||||
|
||||
config RFKILL_INPUT
|
||||
bool "RF switch input support" if EMBEDDED
|
||||
bool "RF switch input support" if EXPERT
|
||||
depends on RFKILL
|
||||
depends on INPUT = y || RFKILL = INPUT
|
||||
default y if !EMBEDDED
|
||||
default y if !EXPERT
|
||||
|
@@ -808,7 +808,7 @@ static int __init af_rxrpc_init(void)
|
||||
goto error_call_jar;
|
||||
}
|
||||
|
||||
rxrpc_workqueue = create_workqueue("krxrpcd");
|
||||
rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);
|
||||
if (!rxrpc_workqueue) {
|
||||
printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");
|
||||
goto error_work_queue;
|
||||
|
@@ -24,7 +24,7 @@ menuconfig NET_SCHED
|
||||
To administer these schedulers, you'll need the user-level utilities
|
||||
from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>.
|
||||
That package also contains some documentation; for more, check out
|
||||
<http://linux-net.osdl.org/index.php/Iproute2>.
|
||||
<http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2>.
|
||||
|
||||
This Quality of Service (QoS) support will enable you to use
|
||||
Differentiated Services (diffserv) and Resource Reservation Protocol
|
||||
|
30
net/socket.c
30
net/socket.c
@@ -306,20 +306,6 @@ static const struct super_operations sockfs_ops = {
|
||||
.statfs = simple_statfs,
|
||||
};
|
||||
|
||||
static struct dentry *sockfs_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
{
|
||||
return mount_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC);
|
||||
}
|
||||
|
||||
static struct vfsmount *sock_mnt __read_mostly;
|
||||
|
||||
static struct file_system_type sock_fs_type = {
|
||||
.name = "sockfs",
|
||||
.mount = sockfs_mount,
|
||||
.kill_sb = kill_anon_super,
|
||||
};
|
||||
|
||||
/*
|
||||
* sockfs_dname() is called from d_path().
|
||||
*/
|
||||
@@ -333,6 +319,21 @@ static const struct dentry_operations sockfs_dentry_operations = {
|
||||
.d_dname = sockfs_dname,
|
||||
};
|
||||
|
||||
static struct dentry *sockfs_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
{
|
||||
return mount_pseudo(fs_type, "socket:", &sockfs_ops,
|
||||
&sockfs_dentry_operations, SOCKFS_MAGIC);
|
||||
}
|
||||
|
||||
static struct vfsmount *sock_mnt __read_mostly;
|
||||
|
||||
static struct file_system_type sock_fs_type = {
|
||||
.name = "sockfs",
|
||||
.mount = sockfs_mount,
|
||||
.kill_sb = kill_anon_super,
|
||||
};
|
||||
|
||||
/*
|
||||
* Obtains the first available file descriptor and sets it up for use.
|
||||
*
|
||||
@@ -368,7 +369,6 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
|
||||
}
|
||||
path.mnt = mntget(sock_mnt);
|
||||
|
||||
d_set_d_op(path.dentry, &sockfs_dentry_operations);
|
||||
d_instantiate(path.dentry, SOCK_INODE(sock));
|
||||
SOCK_INODE(sock)->i_fop = &socket_file_ops;
|
||||
|
||||
|
@@ -563,8 +563,17 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p)
|
||||
return cred->cr_ops->crvalidate(task, p);
|
||||
}
|
||||
|
||||
static void rpcauth_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
|
||||
__be32 *data, void *obj)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_encode(&xdr, &rqstp->rq_snd_buf, data);
|
||||
encode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
|
||||
rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp,
|
||||
__be32 *data, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_rqstp->rq_cred;
|
||||
@@ -574,11 +583,22 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
|
||||
if (cred->cr_ops->crwrap_req)
|
||||
return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
|
||||
/* By default, we encode the arguments normally. */
|
||||
return encode(rqstp, data, obj);
|
||||
rpcauth_wrap_req_encode(encode, rqstp, data, obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
|
||||
__be32 *data, void *obj)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data);
|
||||
return decode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
int
|
||||
rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
|
||||
rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp,
|
||||
__be32 *data, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_rqstp->rq_cred;
|
||||
@@ -589,7 +609,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
|
||||
return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
|
||||
data, obj);
|
||||
/* By default, we decode the arguments normally. */
|
||||
return decode(rqstp, data, obj);
|
||||
return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
|
||||
}
|
||||
|
||||
int
|
||||
|
@@ -1231,9 +1231,19 @@ out_bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void gss_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
|
||||
__be32 *p, void *obj)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_encode(&xdr, &rqstp->rq_snd_buf, p);
|
||||
encode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
static inline int
|
||||
gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
|
||||
kxdreproc_t encode, struct rpc_rqst *rqstp,
|
||||
__be32 *p, void *obj)
|
||||
{
|
||||
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
|
||||
struct xdr_buf integ_buf;
|
||||
@@ -1249,9 +1259,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
|
||||
*p++ = htonl(rqstp->rq_seqno);
|
||||
|
||||
status = encode(rqstp, p, obj);
|
||||
if (status)
|
||||
return status;
|
||||
gss_wrap_req_encode(encode, rqstp, p, obj);
|
||||
|
||||
if (xdr_buf_subsegment(snd_buf, &integ_buf,
|
||||
offset, snd_buf->len - offset))
|
||||
@@ -1325,7 +1333,8 @@ out:
|
||||
|
||||
static inline int
|
||||
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
|
||||
kxdreproc_t encode, struct rpc_rqst *rqstp,
|
||||
__be32 *p, void *obj)
|
||||
{
|
||||
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
|
||||
u32 offset;
|
||||
@@ -1342,9 +1351,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
|
||||
*p++ = htonl(rqstp->rq_seqno);
|
||||
|
||||
status = encode(rqstp, p, obj);
|
||||
if (status)
|
||||
return status;
|
||||
gss_wrap_req_encode(encode, rqstp, p, obj);
|
||||
|
||||
status = alloc_enc_pages(rqstp);
|
||||
if (status)
|
||||
@@ -1394,7 +1401,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
|
||||
static int
|
||||
gss_wrap_req(struct rpc_task *task,
|
||||
kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
|
||||
kxdreproc_t encode, void *rqstp, __be32 *p, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_rqstp->rq_cred;
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
|
||||
@@ -1407,12 +1414,14 @@ gss_wrap_req(struct rpc_task *task,
|
||||
/* The spec seems a little ambiguous here, but I think that not
|
||||
* wrapping context destruction requests makes the most sense.
|
||||
*/
|
||||
status = encode(rqstp, p, obj);
|
||||
gss_wrap_req_encode(encode, rqstp, p, obj);
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
switch (gss_cred->gc_service) {
|
||||
case RPC_GSS_SVC_NONE:
|
||||
status = encode(rqstp, p, obj);
|
||||
gss_wrap_req_encode(encode, rqstp, p, obj);
|
||||
status = 0;
|
||||
break;
|
||||
case RPC_GSS_SVC_INTEGRITY:
|
||||
status = gss_wrap_req_integ(cred, ctx, encode,
|
||||
@@ -1494,10 +1503,19 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
|
||||
__be32 *p, void *obj)
|
||||
{
|
||||
struct xdr_stream xdr;
|
||||
|
||||
xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
|
||||
return decode(rqstp, &xdr, obj);
|
||||
}
|
||||
|
||||
static int
|
||||
gss_unwrap_resp(struct rpc_task *task,
|
||||
kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
|
||||
kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
|
||||
{
|
||||
struct rpc_cred *cred = task->tk_rqstp->rq_cred;
|
||||
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
|
||||
@@ -1528,7 +1546,7 @@ gss_unwrap_resp(struct rpc_task *task,
|
||||
cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
|
||||
+ (savedlen - head->iov_len);
|
||||
out_decode:
|
||||
status = decode(rqstp, p, obj);
|
||||
status = gss_unwrap_req_decode(decode, rqstp, p, obj);
|
||||
out:
|
||||
gss_put_ctx(ctx);
|
||||
dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
|
||||
|
@@ -137,7 +137,7 @@ arcfour_hmac_md5_usage_to_salt(unsigned int usage, u8 salt[4])
|
||||
ms_usage = 13;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;;
|
||||
return -EINVAL;
|
||||
}
|
||||
salt[0] = (ms_usage >> 0) & 0xff;
|
||||
salt[1] = (ms_usage >> 8) & 0xff;
|
||||
|
@@ -67,7 +67,6 @@ static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
|
||||
|
||||
#define RSI_HASHBITS 6
|
||||
#define RSI_HASHMAX (1<<RSI_HASHBITS)
|
||||
#define RSI_HASHMASK (RSI_HASHMAX-1)
|
||||
|
||||
struct rsi {
|
||||
struct cache_head h;
|
||||
@@ -319,7 +318,6 @@ static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
|
||||
|
||||
#define RSC_HASHBITS 10
|
||||
#define RSC_HASHMAX (1<<RSC_HASHBITS)
|
||||
#define RSC_HASHMASK (RSC_HASHMAX-1)
|
||||
|
||||
#define GSS_SEQ_WIN 128
|
||||
|
||||
|
@@ -59,8 +59,8 @@ int bc_send(struct rpc_rqst *req)
|
||||
ret = task->tk_status;
|
||||
rpc_put_task(task);
|
||||
}
|
||||
return ret;
|
||||
dprintk("RPC: bc_send ret= %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
@@ -37,7 +37,7 @@
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_CACHE
|
||||
|
||||
static void cache_defer_req(struct cache_req *req, struct cache_head *item);
|
||||
static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
|
||||
static void cache_revisit_request(struct cache_head *item);
|
||||
|
||||
static void cache_init(struct cache_head *h)
|
||||
@@ -128,6 +128,7 @@ static void cache_fresh_locked(struct cache_head *head, time_t expiry)
|
||||
{
|
||||
head->expiry_time = expiry;
|
||||
head->last_refresh = seconds_since_boot();
|
||||
smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
|
||||
set_bit(CACHE_VALID, &head->flags);
|
||||
}
|
||||
|
||||
@@ -208,11 +209,36 @@ static inline int cache_is_valid(struct cache_detail *detail, struct cache_head
|
||||
/* entry is valid */
|
||||
if (test_bit(CACHE_NEGATIVE, &h->flags))
|
||||
return -ENOENT;
|
||||
else
|
||||
else {
|
||||
/*
|
||||
* In combination with write barrier in
|
||||
* sunrpc_cache_update, ensures that anyone
|
||||
* using the cache entry after this sees the
|
||||
* updated contents:
|
||||
*/
|
||||
smp_rmb();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h)
|
||||
{
|
||||
int rv;
|
||||
|
||||
write_lock(&detail->hash_lock);
|
||||
rv = cache_is_valid(detail, h);
|
||||
if (rv != -EAGAIN) {
|
||||
write_unlock(&detail->hash_lock);
|
||||
return rv;
|
||||
}
|
||||
set_bit(CACHE_NEGATIVE, &h->flags);
|
||||
cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
|
||||
write_unlock(&detail->hash_lock);
|
||||
cache_fresh_unlocked(h, detail);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the generic cache management routine for all
|
||||
* the authentication caches.
|
||||
@@ -251,14 +277,8 @@ int cache_check(struct cache_detail *detail,
|
||||
case -EINVAL:
|
||||
clear_bit(CACHE_PENDING, &h->flags);
|
||||
cache_revisit_request(h);
|
||||
if (rv == -EAGAIN) {
|
||||
set_bit(CACHE_NEGATIVE, &h->flags);
|
||||
cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
|
||||
cache_fresh_unlocked(h, detail);
|
||||
rv = -ENOENT;
|
||||
}
|
||||
rv = try_to_negate_entry(detail, h);
|
||||
break;
|
||||
|
||||
case -EAGAIN:
|
||||
clear_bit(CACHE_PENDING, &h->flags);
|
||||
cache_revisit_request(h);
|
||||
@@ -268,9 +288,11 @@ int cache_check(struct cache_detail *detail,
|
||||
}
|
||||
|
||||
if (rv == -EAGAIN) {
|
||||
cache_defer_req(rqstp, h);
|
||||
if (!test_bit(CACHE_PENDING, &h->flags)) {
|
||||
/* Request is not deferred */
|
||||
if (!cache_defer_req(rqstp, h)) {
|
||||
/*
|
||||
* Request was not deferred; handle it as best
|
||||
* we can ourselves:
|
||||
*/
|
||||
rv = cache_is_valid(detail, h);
|
||||
if (rv == -EAGAIN)
|
||||
rv = -ETIMEDOUT;
|
||||
@@ -618,18 +640,19 @@ static void cache_limit_defers(void)
|
||||
discard->revisit(discard, 1);
|
||||
}
|
||||
|
||||
static void cache_defer_req(struct cache_req *req, struct cache_head *item)
|
||||
/* Return true if and only if a deferred request is queued. */
|
||||
static bool cache_defer_req(struct cache_req *req, struct cache_head *item)
|
||||
{
|
||||
struct cache_deferred_req *dreq;
|
||||
|
||||
if (req->thread_wait) {
|
||||
cache_wait_req(req, item);
|
||||
if (!test_bit(CACHE_PENDING, &item->flags))
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
dreq = req->defer(req);
|
||||
if (dreq == NULL)
|
||||
return;
|
||||
return false;
|
||||
setup_deferral(dreq, item, 1);
|
||||
if (!test_bit(CACHE_PENDING, &item->flags))
|
||||
/* Bit could have been cleared before we managed to
|
||||
@@ -638,6 +661,7 @@ static void cache_defer_req(struct cache_req *req, struct cache_head *item)
|
||||
cache_revisit_request(item);
|
||||
|
||||
cache_limit_defers();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cache_revisit_request(struct cache_head *item)
|
||||
|
@@ -1095,7 +1095,7 @@ static void
|
||||
rpc_xdr_encode(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
kxdrproc_t encode;
|
||||
kxdreproc_t encode;
|
||||
__be32 *p;
|
||||
|
||||
dprint_status(task);
|
||||
@@ -1535,7 +1535,7 @@ call_decode(struct rpc_task *task)
|
||||
{
|
||||
struct rpc_clnt *clnt = task->tk_client;
|
||||
struct rpc_rqst *req = task->tk_rqstp;
|
||||
kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
|
||||
kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode;
|
||||
__be32 *p;
|
||||
|
||||
dprintk("RPC: %5u call_decode (status %d)\n",
|
||||
@@ -1776,12 +1776,11 @@ out_overflow:
|
||||
goto out_garbage;
|
||||
}
|
||||
|
||||
static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj)
|
||||
static void rpcproc_encode_null(void *rqstp, struct xdr_stream *xdr, void *obj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj)
|
||||
static int rpcproc_decode_null(void *rqstp, struct xdr_stream *xdr, void *obj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1830,23 +1829,15 @@ static void rpc_show_task(const struct rpc_clnt *clnt,
|
||||
const struct rpc_task *task)
|
||||
{
|
||||
const char *rpc_waitq = "none";
|
||||
char *p, action[KSYM_SYMBOL_LEN];
|
||||
|
||||
if (RPC_IS_QUEUED(task))
|
||||
rpc_waitq = rpc_qname(task->tk_waitqueue);
|
||||
|
||||
/* map tk_action pointer to a function name; then trim off
|
||||
* the "+0x0 [sunrpc]" */
|
||||
sprint_symbol(action, (unsigned long)task->tk_action);
|
||||
p = strchr(action, '+');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%s q:%s\n",
|
||||
printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",
|
||||
task->tk_pid, task->tk_flags, task->tk_status,
|
||||
clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops,
|
||||
clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task),
|
||||
action, rpc_waitq);
|
||||
task->tk_action, rpc_waitq);
|
||||
}
|
||||
|
||||
void rpc_show_tasks(void)
|
||||
|
@@ -474,7 +474,7 @@ static int __rpc_create_common(struct inode *dir, struct dentry *dentry,
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
BUG_ON(!d_unhashed(dentry));
|
||||
d_drop(dentry);
|
||||
inode = rpc_get_inode(dir->i_sb, mode);
|
||||
if (!inode)
|
||||
goto out_err;
|
||||
|
@@ -57,10 +57,6 @@ enum {
|
||||
RPCBPROC_GETSTAT,
|
||||
};
|
||||
|
||||
#define RPCB_HIGHPROC_2 RPCBPROC_CALLIT
|
||||
#define RPCB_HIGHPROC_3 RPCBPROC_TADDR2UADDR
|
||||
#define RPCB_HIGHPROC_4 RPCBPROC_GETSTAT
|
||||
|
||||
/*
|
||||
* r_owner
|
||||
*
|
||||
@@ -693,46 +689,37 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
|
||||
* XDR functions for rpcbind
|
||||
*/
|
||||
|
||||
static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p,
|
||||
const struct rpcbind_args *rpcb)
|
||||
static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
const struct rpcbind_args *rpcb)
|
||||
{
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
__be32 *p;
|
||||
|
||||
dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name,
|
||||
rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
|
||||
p = xdr_reserve_space(&xdr, sizeof(__be32) * RPCB_mappingargs_sz);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
*p++ = htonl(rpcb->r_prog);
|
||||
*p++ = htonl(rpcb->r_vers);
|
||||
*p++ = htonl(rpcb->r_prot);
|
||||
*p = htonl(rpcb->r_port);
|
||||
|
||||
return 0;
|
||||
p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2);
|
||||
*p++ = cpu_to_be32(rpcb->r_prog);
|
||||
*p++ = cpu_to_be32(rpcb->r_vers);
|
||||
*p++ = cpu_to_be32(rpcb->r_prot);
|
||||
*p = cpu_to_be32(rpcb->r_port);
|
||||
}
|
||||
|
||||
static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p,
|
||||
static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
struct rpcbind_args *rpcb)
|
||||
{
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
unsigned long port;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
__be32 *p;
|
||||
|
||||
rpcb->r_port = 0;
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
port = ntohl(*p);
|
||||
port = be32_to_cpup(p);
|
||||
dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
|
||||
task->tk_msg.rpc_proc->p_name, port);
|
||||
if (unlikely(port > USHRT_MAX))
|
||||
@@ -742,20 +729,18 @@ static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_dec_set(struct rpc_rqst *req, __be32 *p,
|
||||
static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
unsigned int *boolp)
|
||||
{
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
__be32 *p;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
|
||||
*boolp = 0;
|
||||
if (*p)
|
||||
if (*p != xdr_zero)
|
||||
*boolp = 1;
|
||||
|
||||
dprintk("RPC: %5u RPCB_%s call %s\n",
|
||||
@@ -764,73 +749,53 @@ static int rpcb_dec_set(struct rpc_rqst *req, __be32 *p,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int encode_rpcb_string(struct xdr_stream *xdr, const char *string,
|
||||
const u32 maxstrlen)
|
||||
static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,
|
||||
const u32 maxstrlen)
|
||||
{
|
||||
u32 len;
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (unlikely(string == NULL))
|
||||
return -EIO;
|
||||
len = strlen(string);
|
||||
if (unlikely(len > maxstrlen))
|
||||
return -EIO;
|
||||
|
||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
BUG_ON(len > maxstrlen);
|
||||
p = xdr_reserve_space(xdr, 4 + len);
|
||||
xdr_encode_opaque(p, string, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
const struct rpcbind_args *rpcb)
|
||||
static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
const struct rpcbind_args *rpcb)
|
||||
{
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
__be32 *p;
|
||||
|
||||
dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
|
||||
task->tk_pid, task->tk_msg.rpc_proc->p_name,
|
||||
rpcb->r_prog, rpcb->r_vers,
|
||||
rpcb->r_netid, rpcb->r_addr);
|
||||
|
||||
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
|
||||
p = xdr_reserve_space(xdr, (RPCB_program_sz + RPCB_version_sz) << 2);
|
||||
*p++ = cpu_to_be32(rpcb->r_prog);
|
||||
*p = cpu_to_be32(rpcb->r_vers);
|
||||
|
||||
p = xdr_reserve_space(&xdr,
|
||||
sizeof(__be32) * (RPCB_program_sz + RPCB_version_sz));
|
||||
if (unlikely(p == NULL))
|
||||
return -EIO;
|
||||
*p++ = htonl(rpcb->r_prog);
|
||||
*p = htonl(rpcb->r_vers);
|
||||
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN))
|
||||
return -EIO;
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN))
|
||||
return -EIO;
|
||||
if (encode_rpcb_string(&xdr, rpcb->r_owner, RPCB_MAXOWNERLEN))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
encode_rpcb_string(xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN);
|
||||
encode_rpcb_string(xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN);
|
||||
encode_rpcb_string(xdr, rpcb->r_owner, RPCB_MAXOWNERLEN);
|
||||
}
|
||||
|
||||
static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,
|
||||
struct rpcbind_args *rpcb)
|
||||
{
|
||||
struct sockaddr_storage address;
|
||||
struct sockaddr *sap = (struct sockaddr *)&address;
|
||||
struct rpc_task *task = req->rq_task;
|
||||
struct xdr_stream xdr;
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
rpcb->r_port = 0;
|
||||
|
||||
xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
|
||||
|
||||
p = xdr_inline_decode(&xdr, sizeof(__be32));
|
||||
p = xdr_inline_decode(xdr, 4);
|
||||
if (unlikely(p == NULL))
|
||||
goto out_fail;
|
||||
len = ntohl(*p);
|
||||
len = be32_to_cpup(p);
|
||||
|
||||
/*
|
||||
* If the returned universal address is a null string,
|
||||
@@ -845,7 +810,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p,
|
||||
if (unlikely(len > RPCBIND_MAXUADDRLEN))
|
||||
goto out_fail;
|
||||
|
||||
p = xdr_inline_decode(&xdr, len);
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (unlikely(p == NULL))
|
||||
goto out_fail;
|
||||
dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid,
|
||||
@@ -871,8 +836,8 @@ out_fail:
|
||||
static struct rpc_procinfo rpcb_procedures2[] = {
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
@@ -881,8 +846,8 @@ static struct rpc_procinfo rpcb_procedures2[] = {
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
@@ -891,8 +856,8 @@ static struct rpc_procinfo rpcb_procedures2[] = {
|
||||
},
|
||||
[RPCBPROC_GETPORT] = {
|
||||
.p_proc = RPCBPROC_GETPORT,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getport,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_mapping,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_getport,
|
||||
.p_arglen = RPCB_mappingargs_sz,
|
||||
.p_replen = RPCB_getportres_sz,
|
||||
.p_statidx = RPCBPROC_GETPORT,
|
||||
@@ -904,8 +869,8 @@ static struct rpc_procinfo rpcb_procedures2[] = {
|
||||
static struct rpc_procinfo rpcb_procedures3[] = {
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
@@ -914,8 +879,8 @@ static struct rpc_procinfo rpcb_procedures3[] = {
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
@@ -924,8 +889,8 @@ static struct rpc_procinfo rpcb_procedures3[] = {
|
||||
},
|
||||
[RPCBPROC_GETADDR] = {
|
||||
.p_proc = RPCBPROC_GETADDR,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getaddr,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_getaddr,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_getaddrres_sz,
|
||||
.p_statidx = RPCBPROC_GETADDR,
|
||||
@@ -937,8 +902,8 @@ static struct rpc_procinfo rpcb_procedures3[] = {
|
||||
static struct rpc_procinfo rpcb_procedures4[] = {
|
||||
[RPCBPROC_SET] = {
|
||||
.p_proc = RPCBPROC_SET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_SET,
|
||||
@@ -947,8 +912,8 @@ static struct rpc_procinfo rpcb_procedures4[] = {
|
||||
},
|
||||
[RPCBPROC_UNSET] = {
|
||||
.p_proc = RPCBPROC_UNSET,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_set,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_set,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_setres_sz,
|
||||
.p_statidx = RPCBPROC_UNSET,
|
||||
@@ -957,8 +922,8 @@ static struct rpc_procinfo rpcb_procedures4[] = {
|
||||
},
|
||||
[RPCBPROC_GETADDR] = {
|
||||
.p_proc = RPCBPROC_GETADDR,
|
||||
.p_encode = (kxdrproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrproc_t)rpcb_dec_getaddr,
|
||||
.p_encode = (kxdreproc_t)rpcb_enc_getaddr,
|
||||
.p_decode = (kxdrdproc_t)rpcb_dec_getaddr,
|
||||
.p_arglen = RPCB_getaddrargs_sz,
|
||||
.p_replen = RPCB_getaddrres_sz,
|
||||
.p_statidx = RPCBPROC_GETADDR,
|
||||
@@ -993,19 +958,19 @@ static struct rpcb_info rpcb_next_version6[] = {
|
||||
|
||||
static struct rpc_version rpcb_version2 = {
|
||||
.number = RPCBVERS_2,
|
||||
.nrprocs = RPCB_HIGHPROC_2,
|
||||
.nrprocs = ARRAY_SIZE(rpcb_procedures2),
|
||||
.procs = rpcb_procedures2
|
||||
};
|
||||
|
||||
static struct rpc_version rpcb_version3 = {
|
||||
.number = RPCBVERS_3,
|
||||
.nrprocs = RPCB_HIGHPROC_3,
|
||||
.nrprocs = ARRAY_SIZE(rpcb_procedures3),
|
||||
.procs = rpcb_procedures3
|
||||
};
|
||||
|
||||
static struct rpc_version rpcb_version4 = {
|
||||
.number = RPCBVERS_4,
|
||||
.nrprocs = RPCB_HIGHPROC_4,
|
||||
.nrprocs = ARRAY_SIZE(rpcb_procedures4),
|
||||
.procs = rpcb_procedures4
|
||||
};
|
||||
|
||||
|
@@ -488,10 +488,6 @@ svc_destroy(struct svc_serv *serv)
|
||||
if (svc_serv_is_pooled(serv))
|
||||
svc_pool_map_put();
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
svc_sock_destroy(serv->bc_xprt);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
svc_unregister(serv);
|
||||
kfree(serv->sv_pools);
|
||||
kfree(serv);
|
||||
@@ -1005,6 +1001,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||
rqstp->rq_splice_ok = 1;
|
||||
/* Will be turned off only when NFSv4 Sessions are used */
|
||||
rqstp->rq_usedeferral = 1;
|
||||
rqstp->rq_dropme = false;
|
||||
|
||||
/* Setup reply header */
|
||||
rqstp->rq_xprt->xpt_ops->xpo_prep_reply_hdr(rqstp);
|
||||
@@ -1106,7 +1103,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
|
||||
|
||||
/* Encode reply */
|
||||
if (*statp == rpc_drop_reply) {
|
||||
if (rqstp->rq_dropme) {
|
||||
if (procp->pc_release)
|
||||
procp->pc_release(rqstp, NULL, rqstp->rq_resp);
|
||||
goto dropit;
|
||||
@@ -1147,7 +1144,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
|
||||
dropit:
|
||||
svc_authorise(rqstp); /* doesn't hurt to call this twice */
|
||||
dprintk("svc: svc_process dropit\n");
|
||||
svc_drop(rqstp);
|
||||
return 0;
|
||||
|
||||
err_short_len:
|
||||
@@ -1218,7 +1214,6 @@ svc_process(struct svc_rqst *rqstp)
|
||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||
struct svc_serv *serv = rqstp->rq_server;
|
||||
u32 dir;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Setup response xdr_buf.
|
||||
@@ -1246,11 +1241,13 @@ svc_process(struct svc_rqst *rqstp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
error = svc_process_common(rqstp, argv, resv);
|
||||
if (error <= 0)
|
||||
return error;
|
||||
|
||||
return svc_send(rqstp);
|
||||
/* Returns 1 for send, 0 for drop */
|
||||
if (svc_process_common(rqstp, argv, resv))
|
||||
return svc_send(rqstp);
|
||||
else {
|
||||
svc_drop(rqstp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
@@ -1264,10 +1261,9 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
|
||||
{
|
||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||
int error;
|
||||
|
||||
/* Build the svc_rqst used by the common processing routine */
|
||||
rqstp->rq_xprt = serv->bc_xprt;
|
||||
rqstp->rq_xprt = serv->sv_bc_xprt;
|
||||
rqstp->rq_xid = req->rq_xid;
|
||||
rqstp->rq_prot = req->rq_xprt->prot;
|
||||
rqstp->rq_server = serv;
|
||||
@@ -1292,12 +1288,15 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
|
||||
svc_getu32(argv); /* XID */
|
||||
svc_getnl(argv); /* CALLDIR */
|
||||
|
||||
error = svc_process_common(rqstp, argv, resv);
|
||||
if (error <= 0)
|
||||
return error;
|
||||
|
||||
memcpy(&req->rq_snd_buf, &rqstp->rq_res, sizeof(req->rq_snd_buf));
|
||||
return bc_send(req);
|
||||
/* Returns 1 for send, 0 for drop */
|
||||
if (svc_process_common(rqstp, argv, resv)) {
|
||||
memcpy(&req->rq_snd_buf, &rqstp->rq_res,
|
||||
sizeof(req->rq_snd_buf));
|
||||
return bc_send(req);
|
||||
} else {
|
||||
/* Nothing to do to drop request */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(bc_svc_process);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/svc_xprt.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/sunrpc/xprt.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
|
||||
|
||||
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref)
|
||||
if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags))
|
||||
svcauth_unix_info_release(xprt);
|
||||
put_net(xprt->xpt_net);
|
||||
/* See comment on corresponding get in xs_setup_bc_tcp(): */
|
||||
if (xprt->xpt_bc_xprt)
|
||||
xprt_put(xprt->xpt_bc_xprt);
|
||||
xprt->xpt_ops->xpo_free(xprt);
|
||||
module_put(owner);
|
||||
}
|
||||
@@ -303,6 +307,15 @@ static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
|
||||
list_del(&rqstp->rq_list);
|
||||
}
|
||||
|
||||
static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt)
|
||||
{
|
||||
if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE)))
|
||||
return true;
|
||||
if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED)))
|
||||
return xprt->xpt_ops->xpo_has_wspace(xprt);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Queue up a transport with data pending. If there are idle nfsd
|
||||
* processes, wake 'em up.
|
||||
@@ -315,8 +328,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||
struct svc_rqst *rqstp;
|
||||
int cpu;
|
||||
|
||||
if (!(xprt->xpt_flags &
|
||||
((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED))))
|
||||
if (!svc_xprt_has_something_to_do(xprt))
|
||||
return;
|
||||
|
||||
cpu = get_cpu();
|
||||
@@ -343,28 +355,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||
dprintk("svc: transport %p busy, not enqueued\n", xprt);
|
||||
goto out_unlock;
|
||||
}
|
||||
BUG_ON(xprt->xpt_pool != NULL);
|
||||
xprt->xpt_pool = pool;
|
||||
|
||||
/* Handle pending connection */
|
||||
if (test_bit(XPT_CONN, &xprt->xpt_flags))
|
||||
goto process;
|
||||
|
||||
/* Handle close in-progress */
|
||||
if (test_bit(XPT_CLOSE, &xprt->xpt_flags))
|
||||
goto process;
|
||||
|
||||
/* Check if we have space to reply to a request */
|
||||
if (!xprt->xpt_ops->xpo_has_wspace(xprt)) {
|
||||
/* Don't enqueue while not enough space for reply */
|
||||
dprintk("svc: no write space, transport %p not enqueued\n",
|
||||
xprt);
|
||||
xprt->xpt_pool = NULL;
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
process:
|
||||
if (!list_empty(&pool->sp_threads)) {
|
||||
rqstp = list_entry(pool->sp_threads.next,
|
||||
struct svc_rqst,
|
||||
@@ -381,13 +372,11 @@ void svc_xprt_enqueue(struct svc_xprt *xprt)
|
||||
rqstp->rq_reserved = serv->sv_max_mesg;
|
||||
atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved);
|
||||
pool->sp_stats.threads_woken++;
|
||||
BUG_ON(xprt->xpt_pool != pool);
|
||||
wake_up(&rqstp->rq_wait);
|
||||
} else {
|
||||
dprintk("svc: transport %p put into queue\n", xprt);
|
||||
list_add_tail(&xprt->xpt_ready, &pool->sp_sockets);
|
||||
pool->sp_stats.sockets_queued++;
|
||||
BUG_ON(xprt->xpt_pool != pool);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
@@ -426,7 +415,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool)
|
||||
void svc_xprt_received(struct svc_xprt *xprt)
|
||||
{
|
||||
BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
|
||||
xprt->xpt_pool = NULL;
|
||||
/* As soon as we clear busy, the xprt could be closed and
|
||||
* 'put', so we need a reference to call svc_xprt_enqueue with:
|
||||
*/
|
||||
@@ -722,7 +710,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
|
||||
dprintk("svc_recv: found XPT_CLOSE\n");
|
||||
svc_delete_xprt(xprt);
|
||||
} else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
|
||||
/* Leave XPT_BUSY set on the dead xprt: */
|
||||
goto out;
|
||||
}
|
||||
if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) {
|
||||
struct svc_xprt *newxpt;
|
||||
newxpt = xprt->xpt_ops->xpo_accept(xprt);
|
||||
if (newxpt) {
|
||||
@@ -747,28 +738,23 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_received(newxpt);
|
||||
}
|
||||
svc_xprt_received(xprt);
|
||||
} else {
|
||||
} else if (xprt->xpt_ops->xpo_has_wspace(xprt)) {
|
||||
dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
|
||||
rqstp, pool->sp_id, xprt,
|
||||
atomic_read(&xprt->xpt_ref.refcount));
|
||||
rqstp->rq_deferred = svc_deferred_dequeue(xprt);
|
||||
if (rqstp->rq_deferred) {
|
||||
svc_xprt_received(xprt);
|
||||
if (rqstp->rq_deferred)
|
||||
len = svc_deferred_recv(rqstp);
|
||||
} else {
|
||||
else
|
||||
len = xprt->xpt_ops->xpo_recvfrom(rqstp);
|
||||
svc_xprt_received(xprt);
|
||||
}
|
||||
dprintk("svc: got len=%d\n", len);
|
||||
}
|
||||
svc_xprt_received(xprt);
|
||||
|
||||
/* No data, incomplete (TCP) read, or accept() */
|
||||
if (len == 0 || len == -EAGAIN) {
|
||||
rqstp->rq_res.len = 0;
|
||||
svc_xprt_release(rqstp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (len == 0 || len == -EAGAIN)
|
||||
goto out;
|
||||
|
||||
clear_bit(XPT_OLD, &xprt->xpt_flags);
|
||||
|
||||
rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp));
|
||||
@@ -777,6 +763,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
|
||||
if (serv->sv_stats)
|
||||
serv->sv_stats->netcnt++;
|
||||
return len;
|
||||
out:
|
||||
rqstp->rq_res.len = 0;
|
||||
svc_xprt_release(rqstp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_recv);
|
||||
|
||||
@@ -935,7 +925,12 @@ void svc_close_xprt(struct svc_xprt *xprt)
|
||||
if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags))
|
||||
/* someone else will have to effect the close */
|
||||
return;
|
||||
|
||||
/*
|
||||
* We expect svc_close_xprt() to work even when no threads are
|
||||
* running (e.g., while configuring the server before starting
|
||||
* any threads), so if the transport isn't busy, we delete
|
||||
* it ourself:
|
||||
*/
|
||||
svc_delete_xprt(xprt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_close_xprt);
|
||||
@@ -945,16 +940,16 @@ void svc_close_all(struct list_head *xprt_list)
|
||||
struct svc_xprt *xprt;
|
||||
struct svc_xprt *tmp;
|
||||
|
||||
/*
|
||||
* The server is shutting down, and no more threads are running.
|
||||
* svc_xprt_enqueue() might still be running, but at worst it
|
||||
* will re-add the xprt to sp_sockets, which will soon get
|
||||
* freed. So we don't bother with any more locking, and don't
|
||||
* leave the close to the (nonexistent) server threads:
|
||||
*/
|
||||
list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) {
|
||||
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
||||
if (test_bit(XPT_BUSY, &xprt->xpt_flags)) {
|
||||
/* Waiting to be processed, but no threads left,
|
||||
* So just remove it from the waiting list
|
||||
*/
|
||||
list_del_init(&xprt->xpt_ready);
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
}
|
||||
svc_close_xprt(xprt);
|
||||
svc_delete_xprt(xprt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1028,6 +1023,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req)
|
||||
}
|
||||
svc_xprt_get(rqstp->rq_xprt);
|
||||
dr->xprt = rqstp->rq_xprt;
|
||||
rqstp->rq_dropme = true;
|
||||
|
||||
dr->handle.revisit = svc_revisit;
|
||||
return &dr->handle;
|
||||
@@ -1065,14 +1061,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt)
|
||||
if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags))
|
||||
return NULL;
|
||||
spin_lock(&xprt->xpt_lock);
|
||||
clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
|
||||
if (!list_empty(&xprt->xpt_deferred)) {
|
||||
dr = list_entry(xprt->xpt_deferred.next,
|
||||
struct svc_deferred_req,
|
||||
handle.recent);
|
||||
list_del_init(&dr->handle.recent);
|
||||
set_bit(XPT_DEFERRED, &xprt->xpt_flags);
|
||||
}
|
||||
} else
|
||||
clear_bit(XPT_DEFERRED, &xprt->xpt_flags);
|
||||
spin_unlock(&xprt->xpt_lock);
|
||||
return dr;
|
||||
}
|
||||
|
@@ -118,7 +118,6 @@ EXPORT_SYMBOL_GPL(svc_auth_unregister);
|
||||
|
||||
#define DN_HASHBITS 6
|
||||
#define DN_HASHMAX (1<<DN_HASHBITS)
|
||||
#define DN_HASHMASK (DN_HASHMAX-1)
|
||||
|
||||
static struct hlist_head auth_domain_table[DN_HASHMAX];
|
||||
static spinlock_t auth_domain_lock =
|
||||
|
@@ -30,7 +30,9 @@
|
||||
|
||||
struct unix_domain {
|
||||
struct auth_domain h;
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
int addr_changes;
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
/* other stuff later */
|
||||
};
|
||||
|
||||
@@ -64,7 +66,9 @@ struct auth_domain *unix_domain_find(char *name)
|
||||
return NULL;
|
||||
}
|
||||
new->h.flavour = &svcauth_unix;
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
new->addr_changes = 0;
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
rv = auth_domain_lookup(name, &new->h);
|
||||
}
|
||||
}
|
||||
@@ -85,14 +89,15 @@ static void svcauth_unix_domain_release(struct auth_domain *dom)
|
||||
*/
|
||||
#define IP_HASHBITS 8
|
||||
#define IP_HASHMAX (1<<IP_HASHBITS)
|
||||
#define IP_HASHMASK (IP_HASHMAX-1)
|
||||
|
||||
struct ip_map {
|
||||
struct cache_head h;
|
||||
char m_class[8]; /* e.g. "nfsd" */
|
||||
struct in6_addr m_addr;
|
||||
struct unix_domain *m_client;
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
int m_add_change;
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
};
|
||||
|
||||
static void ip_map_put(struct kref *kref)
|
||||
@@ -146,7 +151,9 @@ static void update(struct cache_head *cnew, struct cache_head *citem)
|
||||
|
||||
kref_get(&item->m_client->h.ref);
|
||||
new->m_client = item->m_client;
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
new->m_add_change = item->m_add_change;
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
}
|
||||
static struct cache_head *ip_map_alloc(void)
|
||||
{
|
||||
@@ -331,6 +338,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
|
||||
ip.h.flags = 0;
|
||||
if (!udom)
|
||||
set_bit(CACHE_NEGATIVE, &ip.h.flags);
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
else {
|
||||
ip.m_add_change = udom->addr_changes;
|
||||
/* if this is from the legacy set_client system call,
|
||||
@@ -339,6 +347,7 @@ static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
|
||||
if (expiry == NEVER)
|
||||
ip.m_add_change++;
|
||||
}
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
ip.h.expiry_time = expiry;
|
||||
ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
|
||||
hash_str(ipm->m_class, IP_HASHBITS) ^
|
||||
@@ -358,6 +367,7 @@ static inline int ip_map_update(struct net *net, struct ip_map *ipm,
|
||||
return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_DEPRECATED
|
||||
int auth_unix_add_addr(struct net *net, struct in6_addr *addr, struct auth_domain *dom)
|
||||
{
|
||||
struct unix_domain *udom;
|
||||
@@ -402,8 +412,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
|
||||
return NULL;
|
||||
|
||||
if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
|
||||
if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)
|
||||
auth_domain_put(&ipm->m_client->h);
|
||||
sunrpc_invalidate(&ipm->h, sn->ip_map_cache);
|
||||
rv = NULL;
|
||||
} else {
|
||||
rv = &ipm->m_client->h;
|
||||
@@ -413,6 +422,7 @@ struct auth_domain *auth_unix_lookup(struct net *net, struct in6_addr *addr)
|
||||
return rv;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(auth_unix_lookup);
|
||||
#endif /* CONFIG_NFSD_DEPRECATED */
|
||||
|
||||
void svcauth_unix_purge(void)
|
||||
{
|
||||
@@ -497,7 +507,6 @@ svcauth_unix_info_release(struct svc_xprt *xpt)
|
||||
*/
|
||||
#define GID_HASHBITS 8
|
||||
#define GID_HASHMAX (1<<GID_HASHBITS)
|
||||
#define GID_HASHMASK (GID_HASHMAX - 1)
|
||||
|
||||
struct unix_gid {
|
||||
struct cache_head h;
|
||||
|
@@ -66,6 +66,13 @@ static void svc_sock_free(struct svc_xprt *);
|
||||
static struct svc_xprt *svc_create_socket(struct svc_serv *, int,
|
||||
struct net *, struct sockaddr *,
|
||||
int, int);
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
|
||||
struct net *, struct sockaddr *,
|
||||
int, int);
|
||||
static void svc_bc_sock_free(struct svc_xprt *xprt);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
static struct lock_class_key svc_key[2];
|
||||
static struct lock_class_key svc_slock_key[2];
|
||||
@@ -324,19 +331,21 @@ int svc_sock_names(struct svc_serv *serv, char *buf, const size_t buflen,
|
||||
len = onelen;
|
||||
break;
|
||||
}
|
||||
if (toclose && strcmp(toclose, buf + len) == 0)
|
||||
if (toclose && strcmp(toclose, buf + len) == 0) {
|
||||
closesk = svsk;
|
||||
else
|
||||
svc_xprt_get(&closesk->sk_xprt);
|
||||
} else
|
||||
len += onelen;
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
|
||||
if (closesk)
|
||||
if (closesk) {
|
||||
/* Should unregister with portmap, but you cannot
|
||||
* unregister just one protocol...
|
||||
*/
|
||||
svc_close_xprt(&closesk->sk_xprt);
|
||||
else if (toclose)
|
||||
svc_xprt_put(&closesk->sk_xprt);
|
||||
} else if (toclose)
|
||||
return -ENOENT;
|
||||
return len;
|
||||
}
|
||||
@@ -985,15 +994,17 @@ static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
|
||||
vec[0] = rqstp->rq_arg.head[0];
|
||||
} else {
|
||||
/* REPLY */
|
||||
if (svsk->sk_bc_xprt)
|
||||
req = xprt_lookup_rqst(svsk->sk_bc_xprt, xid);
|
||||
struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
|
||||
|
||||
if (bc_xprt)
|
||||
req = xprt_lookup_rqst(bc_xprt, xid);
|
||||
|
||||
if (!req) {
|
||||
printk(KERN_NOTICE
|
||||
"%s: Got unrecognized reply: "
|
||||
"calldir 0x%x sk_bc_xprt %p xid %08x\n",
|
||||
"calldir 0x%x xpt_bc_xprt %p xid %08x\n",
|
||||
__func__, ntohl(calldir),
|
||||
svsk->sk_bc_xprt, xid);
|
||||
bc_xprt, xid);
|
||||
vec[0] = rqstp->rq_arg.head[0];
|
||||
goto out;
|
||||
}
|
||||
@@ -1184,6 +1195,57 @@ static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
|
||||
return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int,
|
||||
struct net *, struct sockaddr *,
|
||||
int, int);
|
||||
static void svc_bc_sock_free(struct svc_xprt *xprt);
|
||||
|
||||
static struct svc_xprt *svc_bc_tcp_create(struct svc_serv *serv,
|
||||
struct net *net,
|
||||
struct sockaddr *sa, int salen,
|
||||
int flags)
|
||||
{
|
||||
return svc_bc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags);
|
||||
}
|
||||
|
||||
static void svc_bc_tcp_sock_detach(struct svc_xprt *xprt)
|
||||
{
|
||||
}
|
||||
|
||||
static struct svc_xprt_ops svc_tcp_bc_ops = {
|
||||
.xpo_create = svc_bc_tcp_create,
|
||||
.xpo_detach = svc_bc_tcp_sock_detach,
|
||||
.xpo_free = svc_bc_sock_free,
|
||||
.xpo_prep_reply_hdr = svc_tcp_prep_reply_hdr,
|
||||
};
|
||||
|
||||
static struct svc_xprt_class svc_tcp_bc_class = {
|
||||
.xcl_name = "tcp-bc",
|
||||
.xcl_owner = THIS_MODULE,
|
||||
.xcl_ops = &svc_tcp_bc_ops,
|
||||
.xcl_max_payload = RPCSVC_MAXPAYLOAD_TCP,
|
||||
};
|
||||
|
||||
static void svc_init_bc_xprt_sock(void)
|
||||
{
|
||||
svc_reg_xprt_class(&svc_tcp_bc_class);
|
||||
}
|
||||
|
||||
static void svc_cleanup_bc_xprt_sock(void)
|
||||
{
|
||||
svc_unreg_xprt_class(&svc_tcp_bc_class);
|
||||
}
|
||||
#else /* CONFIG_NFS_V4_1 */
|
||||
static void svc_init_bc_xprt_sock(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void svc_cleanup_bc_xprt_sock(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
static struct svc_xprt_ops svc_tcp_ops = {
|
||||
.xpo_create = svc_tcp_create,
|
||||
.xpo_recvfrom = svc_tcp_recvfrom,
|
||||
@@ -1207,12 +1269,14 @@ void svc_init_xprt_sock(void)
|
||||
{
|
||||
svc_reg_xprt_class(&svc_tcp_class);
|
||||
svc_reg_xprt_class(&svc_udp_class);
|
||||
svc_init_bc_xprt_sock();
|
||||
}
|
||||
|
||||
void svc_cleanup_xprt_sock(void)
|
||||
{
|
||||
svc_unreg_xprt_class(&svc_tcp_class);
|
||||
svc_unreg_xprt_class(&svc_udp_class);
|
||||
svc_cleanup_bc_xprt_sock();
|
||||
}
|
||||
|
||||
static void svc_tcp_init(struct svc_sock *svsk, struct svc_serv *serv)
|
||||
@@ -1509,41 +1573,45 @@ static void svc_sock_free(struct svc_xprt *xprt)
|
||||
kfree(svsk);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
/*
|
||||
* Create a svc_xprt.
|
||||
*
|
||||
* For internal use only (e.g. nfsv4.1 backchannel).
|
||||
* Callers should typically use the xpo_create() method.
|
||||
* Create a back channel svc_xprt which shares the fore channel socket.
|
||||
*/
|
||||
struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot)
|
||||
static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv,
|
||||
int protocol,
|
||||
struct net *net,
|
||||
struct sockaddr *sin, int len,
|
||||
int flags)
|
||||
{
|
||||
struct svc_sock *svsk;
|
||||
struct svc_xprt *xprt = NULL;
|
||||
struct svc_xprt *xprt;
|
||||
|
||||
if (protocol != IPPROTO_TCP) {
|
||||
printk(KERN_WARNING "svc: only TCP sockets"
|
||||
" supported on shared back channel\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
dprintk("svc: %s\n", __func__);
|
||||
svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
|
||||
if (!svsk)
|
||||
goto out;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xprt = &svsk->sk_xprt;
|
||||
if (prot == IPPROTO_TCP)
|
||||
svc_xprt_init(&svc_tcp_class, xprt, serv);
|
||||
else if (prot == IPPROTO_UDP)
|
||||
svc_xprt_init(&svc_udp_class, xprt, serv);
|
||||
else
|
||||
BUG();
|
||||
out:
|
||||
dprintk("svc: %s return %p\n", __func__, xprt);
|
||||
svc_xprt_init(&svc_tcp_bc_class, xprt, serv);
|
||||
|
||||
serv->sv_bc_xprt = xprt;
|
||||
|
||||
return xprt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_sock_create);
|
||||
|
||||
/*
|
||||
* Destroy a svc_sock.
|
||||
* Free a back channel svc_sock.
|
||||
*/
|
||||
void svc_sock_destroy(struct svc_xprt *xprt)
|
||||
static void svc_bc_sock_free(struct svc_xprt *xprt)
|
||||
{
|
||||
if (xprt)
|
||||
if (xprt) {
|
||||
kfree(xprt->xpt_bc_sid);
|
||||
kfree(container_of(xprt, struct svc_sock, sk_xprt));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_sock_destroy);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
155
net/sunrpc/xdr.c
155
net/sunrpc/xdr.c
@@ -552,6 +552,74 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_write_pages);
|
||||
|
||||
static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
|
||||
__be32 *p, unsigned int len)
|
||||
{
|
||||
if (len > iov->iov_len)
|
||||
len = iov->iov_len;
|
||||
if (p == NULL)
|
||||
p = (__be32*)iov->iov_base;
|
||||
xdr->p = p;
|
||||
xdr->end = (__be32*)(iov->iov_base + len);
|
||||
xdr->iov = iov;
|
||||
xdr->page_ptr = NULL;
|
||||
}
|
||||
|
||||
static int xdr_set_page_base(struct xdr_stream *xdr,
|
||||
unsigned int base, unsigned int len)
|
||||
{
|
||||
unsigned int pgnr;
|
||||
unsigned int maxlen;
|
||||
unsigned int pgoff;
|
||||
unsigned int pgend;
|
||||
void *kaddr;
|
||||
|
||||
maxlen = xdr->buf->page_len;
|
||||
if (base >= maxlen)
|
||||
return -EINVAL;
|
||||
maxlen -= base;
|
||||
if (len > maxlen)
|
||||
len = maxlen;
|
||||
|
||||
base += xdr->buf->page_base;
|
||||
|
||||
pgnr = base >> PAGE_SHIFT;
|
||||
xdr->page_ptr = &xdr->buf->pages[pgnr];
|
||||
kaddr = page_address(*xdr->page_ptr);
|
||||
|
||||
pgoff = base & ~PAGE_MASK;
|
||||
xdr->p = (__be32*)(kaddr + pgoff);
|
||||
|
||||
pgend = pgoff + len;
|
||||
if (pgend > PAGE_SIZE)
|
||||
pgend = PAGE_SIZE;
|
||||
xdr->end = (__be32*)(kaddr + pgend);
|
||||
xdr->iov = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xdr_set_next_page(struct xdr_stream *xdr)
|
||||
{
|
||||
unsigned int newbase;
|
||||
|
||||
newbase = (1 + xdr->page_ptr - xdr->buf->pages) << PAGE_SHIFT;
|
||||
newbase -= xdr->buf->page_base;
|
||||
|
||||
if (xdr_set_page_base(xdr, newbase, PAGE_SIZE) < 0)
|
||||
xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
|
||||
}
|
||||
|
||||
static bool xdr_set_next_buffer(struct xdr_stream *xdr)
|
||||
{
|
||||
if (xdr->page_ptr != NULL)
|
||||
xdr_set_next_page(xdr);
|
||||
else if (xdr->iov == xdr->buf->head) {
|
||||
if (xdr_set_page_base(xdr, 0, PAGE_SIZE) < 0)
|
||||
xdr_set_iov(xdr, xdr->buf->tail, NULL, xdr->buf->len);
|
||||
}
|
||||
return xdr->p != xdr->end;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_init_decode - Initialize an xdr_stream for decoding data.
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
@@ -560,41 +628,67 @@ EXPORT_SYMBOL_GPL(xdr_write_pages);
|
||||
*/
|
||||
void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
|
||||
{
|
||||
struct kvec *iov = buf->head;
|
||||
unsigned int len = iov->iov_len;
|
||||
|
||||
if (len > buf->len)
|
||||
len = buf->len;
|
||||
xdr->buf = buf;
|
||||
xdr->iov = iov;
|
||||
xdr->p = p;
|
||||
xdr->end = (__be32 *)((char *)iov->iov_base + len);
|
||||
xdr->scratch.iov_base = NULL;
|
||||
xdr->scratch.iov_len = 0;
|
||||
if (buf->head[0].iov_len != 0)
|
||||
xdr_set_iov(xdr, buf->head, p, buf->len);
|
||||
else if (buf->page_len != 0)
|
||||
xdr_set_page_base(xdr, 0, buf->len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_init_decode);
|
||||
|
||||
/**
|
||||
* xdr_inline_peek - Allow read-ahead in the XDR data stream
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
* @nbytes: number of bytes of data to decode
|
||||
*
|
||||
* Check if the input buffer is long enough to enable us to decode
|
||||
* 'nbytes' more bytes of data starting at the current position.
|
||||
* If so return the current pointer without updating the current
|
||||
* pointer position.
|
||||
*/
|
||||
__be32 * xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes)
|
||||
static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
|
||||
{
|
||||
__be32 *p = xdr->p;
|
||||
__be32 *q = p + XDR_QUADLEN(nbytes);
|
||||
|
||||
if (unlikely(q > xdr->end || q < p))
|
||||
return NULL;
|
||||
xdr->p = q;
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_inline_peek);
|
||||
|
||||
/**
|
||||
* xdr_inline_decode - Retrieve non-page XDR data to decode
|
||||
* xdr_set_scratch_buffer - Attach a scratch buffer for decoding data.
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
* @buf: pointer to an empty buffer
|
||||
* @buflen: size of 'buf'
|
||||
*
|
||||
* The scratch buffer is used when decoding from an array of pages.
|
||||
* If an xdr_inline_decode() call spans across page boundaries, then
|
||||
* we copy the data into the scratch buffer in order to allow linear
|
||||
* access.
|
||||
*/
|
||||
void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen)
|
||||
{
|
||||
xdr->scratch.iov_base = buf;
|
||||
xdr->scratch.iov_len = buflen;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer);
|
||||
|
||||
static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes)
|
||||
{
|
||||
__be32 *p;
|
||||
void *cpdest = xdr->scratch.iov_base;
|
||||
size_t cplen = (char *)xdr->end - (char *)xdr->p;
|
||||
|
||||
if (nbytes > xdr->scratch.iov_len)
|
||||
return NULL;
|
||||
memcpy(cpdest, xdr->p, cplen);
|
||||
cpdest += cplen;
|
||||
nbytes -= cplen;
|
||||
if (!xdr_set_next_buffer(xdr))
|
||||
return NULL;
|
||||
p = __xdr_inline_decode(xdr, nbytes);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
memcpy(cpdest, p, nbytes);
|
||||
return xdr->scratch.iov_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_inline_decode - Retrieve XDR data to decode
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
* @nbytes: number of bytes of data to decode
|
||||
*
|
||||
@@ -605,13 +699,16 @@ EXPORT_SYMBOL_GPL(xdr_inline_peek);
|
||||
*/
|
||||
__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
|
||||
{
|
||||
__be32 *p = xdr->p;
|
||||
__be32 *q = p + XDR_QUADLEN(nbytes);
|
||||
__be32 *p;
|
||||
|
||||
if (unlikely(q > xdr->end || q < p))
|
||||
if (nbytes == 0)
|
||||
return xdr->p;
|
||||
if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr))
|
||||
return NULL;
|
||||
xdr->p = q;
|
||||
return p;
|
||||
p = __xdr_inline_decode(xdr, nbytes);
|
||||
if (p != NULL)
|
||||
return p;
|
||||
return xdr_copy_to_scratch(xdr, nbytes);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_inline_decode);
|
||||
|
||||
@@ -671,16 +768,12 @@ EXPORT_SYMBOL_GPL(xdr_read_pages);
|
||||
*/
|
||||
void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
|
||||
{
|
||||
char * kaddr = page_address(xdr->buf->pages[0]);
|
||||
xdr_read_pages(xdr, len);
|
||||
/*
|
||||
* Position current pointer at beginning of tail, and
|
||||
* set remaining message length.
|
||||
*/
|
||||
if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
|
||||
len = PAGE_CACHE_SIZE - xdr->buf->page_base;
|
||||
xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
|
||||
xdr->end = (__be32 *)((char *)xdr->p + len);
|
||||
xdr_set_page_base(xdr, 0, len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_enter_page);
|
||||
|
||||
|
@@ -965,6 +965,7 @@ struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req)
|
||||
xprt = kzalloc(size, GFP_KERNEL);
|
||||
if (xprt == NULL)
|
||||
goto out;
|
||||
kref_init(&xprt->kref);
|
||||
|
||||
xprt->max_reqs = max_req;
|
||||
xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL);
|
||||
@@ -1101,8 +1102,10 @@ found:
|
||||
-PTR_ERR(xprt));
|
||||
return xprt;
|
||||
}
|
||||
if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state))
|
||||
/* ->setup returned a pre-initialized xprt: */
|
||||
return xprt;
|
||||
|
||||
kref_init(&xprt->kref);
|
||||
spin_lock_init(&xprt->transport_lock);
|
||||
spin_lock_init(&xprt->reserve_lock);
|
||||
|
||||
|
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
|
||||
struct svc_sock *bc_sock;
|
||||
struct rpc_xprt *ret;
|
||||
|
||||
if (args->bc_xprt->xpt_bc_xprt) {
|
||||
/*
|
||||
* This server connection already has a backchannel
|
||||
* export; we can't create a new one, as we wouldn't be
|
||||
* able to match replies based on xid any more. So,
|
||||
* reuse the already-existing one:
|
||||
*/
|
||||
return args->bc_xprt->xpt_bc_xprt;
|
||||
}
|
||||
xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
|
||||
if (IS_ERR(xprt))
|
||||
return xprt;
|
||||
@@ -2375,16 +2384,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
|
||||
xprt->reestablish_timeout = 0;
|
||||
xprt->idle_timeout = 0;
|
||||
|
||||
/*
|
||||
* The backchannel uses the same socket connection as the
|
||||
* forechannel
|
||||
*/
|
||||
xprt->bc_xprt = args->bc_xprt;
|
||||
bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
|
||||
bc_sock->sk_bc_xprt = xprt;
|
||||
transport->sock = bc_sock->sk_sock;
|
||||
transport->inet = bc_sock->sk_sk;
|
||||
|
||||
xprt->ops = &bc_tcp_ops;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
@@ -2406,6 +2405,20 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
|
||||
xprt->address_strings[RPC_DISPLAY_PORT],
|
||||
xprt->address_strings[RPC_DISPLAY_PROTO]);
|
||||
|
||||
/*
|
||||
* Once we've associated a backchannel xprt with a connection,
|
||||
* we want to keep it around as long as long as the connection
|
||||
* lasts, in case we need to start using it for a backchannel
|
||||
* again; this reference won't be dropped until bc_xprt is
|
||||
* destroyed.
|
||||
*/
|
||||
xprt_get(xprt);
|
||||
args->bc_xprt->xpt_bc_xprt = xprt;
|
||||
xprt->bc_xprt = args->bc_xprt;
|
||||
bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
|
||||
transport->sock = bc_sock->sk_sock;
|
||||
transport->inet = bc_sock->sk_sk;
|
||||
|
||||
/*
|
||||
* Since we don't want connections for the backchannel, we set
|
||||
* the xprt status to connected
|
||||
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
|
||||
|
||||
if (try_module_get(THIS_MODULE))
|
||||
return xprt;
|
||||
xprt_put(xprt);
|
||||
ret = ERR_PTR(-EINVAL);
|
||||
out_err:
|
||||
xprt_free(xprt);
|
||||
|
@@ -95,7 +95,7 @@ config CFG80211_DEBUGFS
|
||||
If unsure, say N.
|
||||
|
||||
config CFG80211_INTERNAL_REGDB
|
||||
bool "use statically compiled regulatory rules database" if EMBEDDED
|
||||
bool "use statically compiled regulatory rules database" if EXPERT
|
||||
default n
|
||||
depends on CFG80211
|
||||
---help---
|
||||
|
Reference in New Issue
Block a user