Merge tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
- stable fix for an infinite loop in RPC state machine
- stable fix for a use after free situation in the NFSv4 trunking discovery
- stable fix for error handling in the NFSv4 trunking discovery
- stable fix for the page write update code
- stable fix for the NFSv4.1 mount time security negotiation
- stable fix for the NFSv4 open code.
- O_DIRECT locking fixes
- fix an Oops in the pnfs file commit code
- RPC layer needs finer grained handling of connection errors
- more RPC GSS upcall fixes"
* tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (30 commits)
pnfs: Proper delay for NFS4ERR_RECALLCONFLICT in layout_get_done
pnfs: fix BUG in filelayout_recover_commit_reqs
nfs4: fix discover_server_trunking use after free
NFSv4.1: Handle errors correctly in nfs41_walk_client_list
nfs: always make sure page is up-to-date before extending a write to cover the entire page
nfs: page cache invalidation for dio
nfs: take i_mutex during direct I/O reads
nfs: merge nfs_direct_write into nfs_file_direct_write
nfs: merge nfs_direct_read into nfs_file_direct_read
nfs: increment i_dio_count for reads, too
nfs: defer inode_dio_done call until size update is done
nfs: fix size updates for aio writes
nfs4.1: properly handle ENOTSUP in SECINFO_NO_NAME
NFSv4.1: Fix a race in nfs4_write_inode
NFSv4.1: Don't trust attributes if a pNFS LAYOUTCOMMIT is outstanding
point to the right include file in a comment (left over from a9004abc3)
NFS: dprintk() should not print negative fileids and inode numbers
nfs: fix dead code of ipv6_addr_scope
sunrpc: Fix infinite loop in RPC state machine
SUNRPC: Add tracepoint for socket errors
...
This commit is contained in:
@@ -536,8 +536,7 @@ static void warn_gssd(void)
|
||||
unsigned long now = jiffies;
|
||||
|
||||
if (time_after(now, ratelimit)) {
|
||||
printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n"
|
||||
"Please check user daemon is running.\n");
|
||||
pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n");
|
||||
ratelimit = now + 15*HZ;
|
||||
}
|
||||
}
|
||||
@@ -600,7 +599,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
|
||||
struct rpc_pipe *pipe;
|
||||
struct rpc_cred *cred = &gss_cred->gc_base;
|
||||
struct gss_upcall_msg *gss_msg;
|
||||
unsigned long timeout;
|
||||
DEFINE_WAIT(wait);
|
||||
int err;
|
||||
|
||||
@@ -608,17 +606,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
|
||||
__func__, from_kuid(&init_user_ns, cred->cr_uid));
|
||||
retry:
|
||||
err = 0;
|
||||
/* Default timeout is 15s unless we know that gssd is not running */
|
||||
timeout = 15 * HZ;
|
||||
if (!sn->gssd_running)
|
||||
timeout = HZ >> 2;
|
||||
/* if gssd is down, just skip upcalling altogether */
|
||||
if (!gssd_running(net)) {
|
||||
warn_gssd();
|
||||
return -EACCES;
|
||||
}
|
||||
gss_msg = gss_setup_upcall(gss_auth, cred);
|
||||
if (PTR_ERR(gss_msg) == -EAGAIN) {
|
||||
err = wait_event_interruptible_timeout(pipe_version_waitqueue,
|
||||
sn->pipe_version >= 0, timeout);
|
||||
sn->pipe_version >= 0, 15 * HZ);
|
||||
if (sn->pipe_version < 0) {
|
||||
if (err == 0)
|
||||
sn->gssd_running = 0;
|
||||
warn_gssd();
|
||||
err = -EACCES;
|
||||
}
|
||||
|
||||
@@ -1529,9 +1529,13 @@ call_refreshresult(struct rpc_task *task)
|
||||
task->tk_action = call_refresh;
|
||||
switch (status) {
|
||||
case 0:
|
||||
if (rpcauth_uptodatecred(task))
|
||||
if (rpcauth_uptodatecred(task)) {
|
||||
task->tk_action = call_allocate;
|
||||
return;
|
||||
return;
|
||||
}
|
||||
/* Use rate-limiting and a max number of retries if refresh
|
||||
* had status 0 but failed to update the cred.
|
||||
*/
|
||||
case -ETIMEDOUT:
|
||||
rpc_delay(task, 3*HZ);
|
||||
case -EAGAIN:
|
||||
@@ -1729,6 +1733,7 @@ call_bind_status(struct rpc_task *task)
|
||||
return;
|
||||
case -ECONNREFUSED: /* connection problems */
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENOTCONN:
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
@@ -1799,7 +1804,9 @@ call_connect_status(struct rpc_task *task)
|
||||
return;
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENETUNREACH:
|
||||
case -EHOSTUNREACH:
|
||||
/* retry with existing socket, after a delay */
|
||||
rpc_delay(task, 3*HZ);
|
||||
if (RPC_IS_SOFTCONN(task))
|
||||
@@ -1902,6 +1909,7 @@ call_transmit_status(struct rpc_task *task)
|
||||
break;
|
||||
}
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENOTCONN:
|
||||
case -EPIPE:
|
||||
rpc_task_force_reencode(task);
|
||||
@@ -2011,8 +2019,9 @@ call_status(struct rpc_task *task)
|
||||
xprt_conditional_disconnect(req->rq_xprt,
|
||||
req->rq_connect_cookie);
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
rpc_force_rebind(clnt);
|
||||
rpc_delay(task, 3*HZ);
|
||||
case -EPIPE:
|
||||
|
||||
@@ -14,6 +14,7 @@ struct sunrpc_net {
|
||||
struct cache_detail *rsi_cache;
|
||||
|
||||
struct super_block *pipefs_sb;
|
||||
struct rpc_pipe *gssd_dummy;
|
||||
struct mutex pipefs_sb_lock;
|
||||
|
||||
struct list_head all_clients;
|
||||
@@ -32,8 +33,6 @@ struct sunrpc_net {
|
||||
int pipe_version;
|
||||
atomic_t pipe_users;
|
||||
struct proc_dir_entry *use_gssp_proc;
|
||||
|
||||
unsigned int gssd_running;
|
||||
};
|
||||
|
||||
extern int sunrpc_net_id;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <asm/ioctls.h>
|
||||
#include <linux/poll.h>
|
||||
@@ -38,7 +39,7 @@
|
||||
#define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "")
|
||||
|
||||
static struct file_system_type rpc_pipe_fs_type;
|
||||
|
||||
static const struct rpc_pipe_ops gssd_dummy_pipe_ops;
|
||||
|
||||
static struct kmem_cache *rpc_inode_cachep __read_mostly;
|
||||
|
||||
@@ -216,14 +217,11 @@ rpc_destroy_inode(struct inode *inode)
|
||||
static int
|
||||
rpc_pipe_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct net *net = inode->i_sb->s_fs_info;
|
||||
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
|
||||
struct rpc_pipe *pipe;
|
||||
int first_open;
|
||||
int res = -ENXIO;
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
sn->gssd_running = 1;
|
||||
pipe = RPC_I(inode)->pipe;
|
||||
if (pipe == NULL)
|
||||
goto out;
|
||||
@@ -1159,6 +1157,7 @@ enum {
|
||||
RPCAUTH_nfsd4_cb,
|
||||
RPCAUTH_cache,
|
||||
RPCAUTH_nfsd,
|
||||
RPCAUTH_gssd,
|
||||
RPCAUTH_RootEOF
|
||||
};
|
||||
|
||||
@@ -1195,6 +1194,10 @@ static const struct rpc_filelist files[] = {
|
||||
.name = "nfsd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
[RPCAUTH_gssd] = {
|
||||
.name = "gssd",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1208,13 +1211,24 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
|
||||
|
||||
void rpc_pipefs_init_net(struct net *net)
|
||||
int rpc_pipefs_init_net(struct net *net)
|
||||
{
|
||||
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
|
||||
|
||||
sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0);
|
||||
if (IS_ERR(sn->gssd_dummy))
|
||||
return PTR_ERR(sn->gssd_dummy);
|
||||
|
||||
mutex_init(&sn->pipefs_sb_lock);
|
||||
sn->gssd_running = 1;
|
||||
sn->pipe_version = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rpc_pipefs_exit_net(struct net *net)
|
||||
{
|
||||
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
|
||||
|
||||
rpc_destroy_pipe_data(sn->gssd_dummy);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1244,11 +1258,134 @@ void rpc_put_sb_net(const struct net *net)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rpc_put_sb_net);
|
||||
|
||||
static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
|
||||
[0] = {
|
||||
.name = "clntXX",
|
||||
.mode = S_IFDIR | S_IRUGO | S_IXUGO,
|
||||
},
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
dummy_downcall(struct file *filp, const char __user *src, size_t len)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct rpc_pipe_ops gssd_dummy_pipe_ops = {
|
||||
.upcall = rpc_pipe_generic_upcall,
|
||||
.downcall = dummy_downcall,
|
||||
};
|
||||
|
||||
/*
|
||||
* Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect
|
||||
* that it will ever use this info to handle an upcall, but rpc.gssd expects
|
||||
* that this file will be there and have a certain format.
|
||||
*/
|
||||
static int
|
||||
rpc_show_dummy_info(struct seq_file *m, void *v)
|
||||
{
|
||||
seq_printf(m, "RPC server: %s\n", utsname()->nodename);
|
||||
seq_printf(m, "service: foo (1) version 0\n");
|
||||
seq_printf(m, "address: 127.0.0.1\n");
|
||||
seq_printf(m, "protocol: tcp\n");
|
||||
seq_printf(m, "port: 0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_dummy_info_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, rpc_show_dummy_info, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations rpc_dummy_info_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = rpc_dummy_info_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static const struct rpc_filelist gssd_dummy_info_file[] = {
|
||||
[0] = {
|
||||
.name = "info",
|
||||
.i_fop = &rpc_dummy_info_operations,
|
||||
.mode = S_IFREG | S_IRUSR,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* rpc_gssd_dummy_populate - create a dummy gssd pipe
|
||||
* @root: root of the rpc_pipefs filesystem
|
||||
* @pipe_data: pipe data created when netns is initialized
|
||||
*
|
||||
* Create a dummy set of directories and a pipe that gssd can hold open to
|
||||
* indicate that it is up and running.
|
||||
*/
|
||||
static struct dentry *
|
||||
rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dentry *gssd_dentry;
|
||||
struct dentry *clnt_dentry = NULL;
|
||||
struct dentry *pipe_dentry = NULL;
|
||||
struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name,
|
||||
strlen(files[RPCAUTH_gssd].name));
|
||||
|
||||
/* We should never get this far if "gssd" doesn't exist */
|
||||
gssd_dentry = d_hash_and_lookup(root, &q);
|
||||
if (!gssd_dentry)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
|
||||
if (ret) {
|
||||
pipe_dentry = ERR_PTR(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
q.name = gssd_dummy_clnt_dir[0].name;
|
||||
q.len = strlen(gssd_dummy_clnt_dir[0].name);
|
||||
clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
|
||||
if (!clnt_dentry) {
|
||||
pipe_dentry = ERR_PTR(-ENOENT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
|
||||
if (ret) {
|
||||
__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
|
||||
pipe_dentry = ERR_PTR(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
|
||||
if (IS_ERR(pipe_dentry)) {
|
||||
__rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1);
|
||||
__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
|
||||
}
|
||||
out:
|
||||
dput(clnt_dentry);
|
||||
dput(gssd_dentry);
|
||||
return pipe_dentry;
|
||||
}
|
||||
|
||||
static void
|
||||
rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
|
||||
{
|
||||
struct dentry *clnt_dir = pipe_dentry->d_parent;
|
||||
struct dentry *gssd_dir = clnt_dir->d_parent;
|
||||
|
||||
__rpc_rmpipe(clnt_dir->d_inode, pipe_dentry);
|
||||
__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
|
||||
__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
|
||||
dput(pipe_dentry);
|
||||
}
|
||||
|
||||
static int
|
||||
rpc_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *root;
|
||||
struct dentry *root, *gssd_dentry;
|
||||
struct net *net = data;
|
||||
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
|
||||
int err;
|
||||
@@ -1266,6 +1403,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
|
||||
return -ENOMEM;
|
||||
if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
|
||||
if (IS_ERR(gssd_dentry)) {
|
||||
__rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
|
||||
return PTR_ERR(gssd_dentry);
|
||||
}
|
||||
|
||||
dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n",
|
||||
net, NET_NAME(net));
|
||||
mutex_lock(&sn->pipefs_sb_lock);
|
||||
@@ -1280,6 +1424,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
|
||||
return 0;
|
||||
|
||||
err_depopulate:
|
||||
rpc_gssd_dummy_depopulate(gssd_dentry);
|
||||
blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
|
||||
RPC_PIPEFS_UMOUNT,
|
||||
sb);
|
||||
@@ -1289,6 +1434,16 @@ err_depopulate:
|
||||
return err;
|
||||
}
|
||||
|
||||
bool
|
||||
gssd_running(struct net *net)
|
||||
{
|
||||
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
|
||||
struct rpc_pipe *pipe = sn->gssd_dummy;
|
||||
|
||||
return pipe->nreaders || pipe->nwriters;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gssd_running);
|
||||
|
||||
static struct dentry *
|
||||
rpc_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
|
||||
@@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net)
|
||||
if (err)
|
||||
goto err_unixgid;
|
||||
|
||||
rpc_pipefs_init_net(net);
|
||||
err = rpc_pipefs_init_net(net);
|
||||
if (err)
|
||||
goto err_pipefs;
|
||||
|
||||
INIT_LIST_HEAD(&sn->all_clients);
|
||||
spin_lock_init(&sn->rpc_client_lock);
|
||||
spin_lock_init(&sn->rpcb_clnt_lock);
|
||||
return 0;
|
||||
|
||||
err_pipefs:
|
||||
unix_gid_cache_destroy(net);
|
||||
err_unixgid:
|
||||
ip_map_cache_destroy(net);
|
||||
err_ipmap:
|
||||
@@ -60,6 +65,7 @@ err_proc:
|
||||
|
||||
static __net_exit void sunrpc_exit_net(struct net *net)
|
||||
{
|
||||
rpc_pipefs_exit_net(net);
|
||||
unix_gid_cache_destroy(net);
|
||||
ip_map_cache_destroy(net);
|
||||
rpc_proc_exit(net);
|
||||
|
||||
@@ -749,6 +749,11 @@ static void xprt_connect_status(struct rpc_task *task)
|
||||
}
|
||||
|
||||
switch (task->tk_status) {
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
case -ECONNABORTED:
|
||||
case -ENETUNREACH:
|
||||
case -EHOSTUNREACH:
|
||||
case -EAGAIN:
|
||||
dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
|
||||
break;
|
||||
|
||||
@@ -257,6 +257,7 @@ struct sock_xprt {
|
||||
void (*old_data_ready)(struct sock *, int);
|
||||
void (*old_state_change)(struct sock *);
|
||||
void (*old_write_space)(struct sock *);
|
||||
void (*old_error_report)(struct sock *);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -274,6 +275,11 @@ struct sock_xprt {
|
||||
*/
|
||||
#define TCP_RPC_REPLY (1UL << 6)
|
||||
|
||||
static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
|
||||
{
|
||||
return (struct rpc_xprt *) sk->sk_user_data;
|
||||
}
|
||||
|
||||
static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
|
||||
{
|
||||
return (struct sockaddr *) &xprt->addr;
|
||||
@@ -799,6 +805,7 @@ 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)
|
||||
@@ -806,6 +813,34 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* xs_error_report - callback to handle TCP socket state errors
|
||||
* @sk: socket
|
||||
*
|
||||
* Note: we don't call sock_error() since there may be a rpc_task
|
||||
* using the socket, and so we don't want to clear sk->sk_err.
|
||||
*/
|
||||
static void xs_error_report(struct sock *sk)
|
||||
{
|
||||
struct rpc_xprt *xprt;
|
||||
int err;
|
||||
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
if (!(xprt = xprt_from_sock(sk)))
|
||||
goto out;
|
||||
|
||||
err = -sk->sk_err;
|
||||
if (err == 0)
|
||||
goto out;
|
||||
dprintk("RPC: xs_error_report client %p, error=%d...\n",
|
||||
xprt, -err);
|
||||
trace_rpc_socket_error(xprt, sk->sk_socket, err);
|
||||
xprt_wake_pending_tasks(xprt, err);
|
||||
out:
|
||||
read_unlock_bh(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
static void xs_reset_transport(struct sock_xprt *transport)
|
||||
@@ -885,11 +920,6 @@ static void xs_destroy(struct rpc_xprt *xprt)
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
|
||||
{
|
||||
return (struct rpc_xprt *) sk->sk_user_data;
|
||||
}
|
||||
|
||||
static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
|
||||
{
|
||||
struct xdr_skb_reader desc = {
|
||||
@@ -1869,6 +1899,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,
|
||||
sk->sk_user_data = xprt;
|
||||
sk->sk_data_ready = xs_local_data_ready;
|
||||
sk->sk_write_space = xs_udp_write_space;
|
||||
sk->sk_error_report = xs_error_report;
|
||||
sk->sk_allocation = GFP_ATOMIC;
|
||||
|
||||
xprt_clear_connected(xprt);
|
||||
@@ -2146,6 +2177,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
|
||||
sk->sk_data_ready = xs_tcp_data_ready;
|
||||
sk->sk_state_change = xs_tcp_state_change;
|
||||
sk->sk_write_space = xs_tcp_write_space;
|
||||
sk->sk_error_report = xs_error_report;
|
||||
sk->sk_allocation = GFP_ATOMIC;
|
||||
|
||||
/* socket options */
|
||||
|
||||
Reference in New Issue
Block a user