forked from Minki/linux
Merge branch 'devel' into linux-next
This commit is contained in:
commit
7285f2d2ff
@ -78,11 +78,6 @@ nfs4_callback_svc(void *vrqstp)
|
||||
|
||||
set_freezable();
|
||||
|
||||
/*
|
||||
* FIXME: do we really need to run this under the BKL? If so, please
|
||||
* add a comment about what it's intended to protect.
|
||||
*/
|
||||
lock_kernel();
|
||||
while (!kthread_should_stop()) {
|
||||
/*
|
||||
* Listen for a request on the socket
|
||||
@ -104,7 +99,6 @@ nfs4_callback_svc(void *vrqstp)
|
||||
preverr = err;
|
||||
svc_process(rqstp);
|
||||
}
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -160,11 +154,6 @@ nfs41_callback_svc(void *vrqstp)
|
||||
|
||||
set_freezable();
|
||||
|
||||
/*
|
||||
* FIXME: do we really need to run this under the BKL? If so, please
|
||||
* add a comment about what it's intended to protect.
|
||||
*/
|
||||
lock_kernel();
|
||||
while (!kthread_should_stop()) {
|
||||
prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE);
|
||||
spin_lock_bh(&serv->sv_cb_lock);
|
||||
@ -183,7 +172,6 @@ nfs41_callback_svc(void *vrqstp)
|
||||
}
|
||||
finish_wait(&serv->sv_cb_waitq, &wq);
|
||||
}
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
67
fs/nfs/dir.c
67
fs/nfs/dir.c
@ -1579,55 +1579,46 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct dentry *dentry = NULL, *rehash = NULL;
|
||||
int error = -EBUSY;
|
||||
|
||||
/*
|
||||
* To prevent any new references to the target during the rename,
|
||||
* we unhash the dentry and free the inode in advance.
|
||||
*/
|
||||
if (!d_unhashed(new_dentry)) {
|
||||
d_drop(new_dentry);
|
||||
rehash = new_dentry;
|
||||
}
|
||||
|
||||
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
|
||||
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
|
||||
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
|
||||
atomic_read(&new_dentry->d_count));
|
||||
|
||||
/*
|
||||
* First check whether the target is busy ... we can't
|
||||
* safely do _any_ rename if the target is in use.
|
||||
*
|
||||
* For files, make a copy of the dentry and then do a
|
||||
* silly-rename. If the silly-rename succeeds, the
|
||||
* copied dentry is hashed and becomes the new target.
|
||||
* For non-directories, check whether the target is busy and if so,
|
||||
* make a copy of the dentry and then do a silly-rename. If the
|
||||
* silly-rename succeeds, the copied dentry is hashed and becomes
|
||||
* the new target.
|
||||
*/
|
||||
if (!new_inode)
|
||||
goto go_ahead;
|
||||
if (S_ISDIR(new_inode->i_mode)) {
|
||||
error = -EISDIR;
|
||||
if (!S_ISDIR(old_inode->i_mode))
|
||||
goto out;
|
||||
} else if (atomic_read(&new_dentry->d_count) > 2) {
|
||||
int err;
|
||||
/* copy the target dentry's name */
|
||||
dentry = d_alloc(new_dentry->d_parent,
|
||||
&new_dentry->d_name);
|
||||
if (!dentry)
|
||||
goto out;
|
||||
if (new_inode && !S_ISDIR(new_inode->i_mode)) {
|
||||
/*
|
||||
* To prevent any new references to the target during the
|
||||
* rename, we unhash the dentry in advance.
|
||||
*/
|
||||
if (!d_unhashed(new_dentry)) {
|
||||
d_drop(new_dentry);
|
||||
rehash = new_dentry;
|
||||
}
|
||||
|
||||
/* silly-rename the existing target ... */
|
||||
err = nfs_sillyrename(new_dir, new_dentry);
|
||||
if (!err) {
|
||||
new_dentry = rehash = dentry;
|
||||
if (atomic_read(&new_dentry->d_count) > 2) {
|
||||
int err;
|
||||
|
||||
/* copy the target dentry's name */
|
||||
dentry = d_alloc(new_dentry->d_parent,
|
||||
&new_dentry->d_name);
|
||||
if (!dentry)
|
||||
goto out;
|
||||
|
||||
/* silly-rename the existing target ... */
|
||||
err = nfs_sillyrename(new_dir, new_dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
new_dentry = dentry;
|
||||
new_inode = NULL;
|
||||
/* instantiate the replacement target */
|
||||
d_instantiate(new_dentry, NULL);
|
||||
} else if (atomic_read(&new_dentry->d_count) > 1)
|
||||
/* dentry still busy? */
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
go_ahead:
|
||||
/*
|
||||
* ... prune child dentries and writebacks if needed.
|
||||
*/
|
||||
|
@ -275,6 +275,13 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
|
||||
/* FALLTHROUGH */
|
||||
#endif /* !defined(CONFIG_NFS_V4_1) */
|
||||
case -NFS4ERR_FILE_OPEN:
|
||||
if (exception->timeout > HZ) {
|
||||
/* We have retried a decent amount, time to
|
||||
* fail
|
||||
*/
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
case -NFS4ERR_GRACE:
|
||||
case -NFS4ERR_DELAY:
|
||||
ret = nfs4_delay(server->client, &exception->timeout);
|
||||
|
@ -877,6 +877,10 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
|
||||
case -NFS4ERR_EXPIRED:
|
||||
case -NFS4ERR_NO_GRACE:
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
case -NFS4ERR_BADSESSION:
|
||||
case -NFS4ERR_BADSLOT:
|
||||
case -NFS4ERR_BAD_HIGH_SLOT:
|
||||
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
|
||||
goto out;
|
||||
default:
|
||||
printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
|
||||
@ -959,6 +963,10 @@ restart:
|
||||
case -NFS4ERR_NO_GRACE:
|
||||
nfs4_state_mark_reclaim_nograce(sp->so_client, state);
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
case -NFS4ERR_BADSESSION:
|
||||
case -NFS4ERR_BADSLOT:
|
||||
case -NFS4ERR_BAD_HIGH_SLOT:
|
||||
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
|
||||
goto out_err;
|
||||
}
|
||||
nfs4_put_open_state(state);
|
||||
|
104
fs/nfs/super.c
104
fs/nfs/super.c
@ -175,14 +175,16 @@ static const match_table_t nfs_mount_option_tokens = {
|
||||
};
|
||||
|
||||
enum {
|
||||
Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma,
|
||||
Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
|
||||
|
||||
Opt_xprt_err
|
||||
};
|
||||
|
||||
static const match_table_t nfs_xprt_protocol_tokens = {
|
||||
{ Opt_xprt_udp, "udp" },
|
||||
{ Opt_xprt_udp6, "udp6" },
|
||||
{ Opt_xprt_tcp, "tcp" },
|
||||
{ Opt_xprt_tcp6, "tcp6" },
|
||||
{ Opt_xprt_rdma, "rdma" },
|
||||
|
||||
{ Opt_xprt_err, NULL }
|
||||
@ -492,6 +494,45 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
|
||||
return sec_flavours[i].str;
|
||||
}
|
||||
|
||||
static void nfs_show_mountd_netid(struct seq_file *m, struct nfs_server *nfss,
|
||||
int showdefaults)
|
||||
{
|
||||
struct sockaddr *sap = (struct sockaddr *) &nfss->mountd_address;
|
||||
|
||||
seq_printf(m, ",mountproto=");
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
switch (nfss->mountd_protocol) {
|
||||
case IPPROTO_UDP:
|
||||
seq_printf(m, RPCBIND_NETID_UDP);
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
seq_printf(m, RPCBIND_NETID_TCP);
|
||||
break;
|
||||
default:
|
||||
if (showdefaults)
|
||||
seq_printf(m, "auto");
|
||||
}
|
||||
break;
|
||||
case AF_INET6:
|
||||
switch (nfss->mountd_protocol) {
|
||||
case IPPROTO_UDP:
|
||||
seq_printf(m, RPCBIND_NETID_UDP6);
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
seq_printf(m, RPCBIND_NETID_TCP6);
|
||||
break;
|
||||
default:
|
||||
if (showdefaults)
|
||||
seq_printf(m, "auto");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (showdefaults)
|
||||
seq_printf(m, "auto");
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
int showdefaults)
|
||||
{
|
||||
@ -505,7 +546,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
|
||||
seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr);
|
||||
seq_printf(m, ",mountaddr=%pI6c", &sin6->sin6_addr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -518,17 +559,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
if (nfss->mountd_port || showdefaults)
|
||||
seq_printf(m, ",mountport=%u", nfss->mountd_port);
|
||||
|
||||
switch (nfss->mountd_protocol) {
|
||||
case IPPROTO_UDP:
|
||||
seq_printf(m, ",mountproto=udp");
|
||||
break;
|
||||
case IPPROTO_TCP:
|
||||
seq_printf(m, ",mountproto=tcp");
|
||||
break;
|
||||
default:
|
||||
if (showdefaults)
|
||||
seq_printf(m, ",mountproto=auto");
|
||||
}
|
||||
nfs_show_mountd_netid(m, nfss, showdefaults);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -578,7 +609,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
|
||||
seq_puts(m, nfs_infop->nostr);
|
||||
}
|
||||
seq_printf(m, ",proto=%s",
|
||||
rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO));
|
||||
rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
|
||||
if (version == 4) {
|
||||
if (nfss->port != NFS_PORT)
|
||||
seq_printf(m, ",port=%u", nfss->port);
|
||||
@ -714,8 +745,6 @@ static void nfs_umount_begin(struct super_block *sb)
|
||||
struct nfs_server *server;
|
||||
struct rpc_clnt *rpc;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
server = NFS_SB(sb);
|
||||
/* -EIO all pending I/O */
|
||||
rpc = server->client_acl;
|
||||
@ -724,8 +753,6 @@ static void nfs_umount_begin(struct super_block *sb)
|
||||
rpc = server->client;
|
||||
if (!IS_ERR(rpc))
|
||||
rpc_killall_tasks(rpc);
|
||||
|
||||
unlock_kernel();
|
||||
}
|
||||
|
||||
static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version)
|
||||
@ -734,8 +761,6 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (data) {
|
||||
data->rsize = NFS_MAX_FILE_IO_SIZE;
|
||||
data->wsize = NFS_MAX_FILE_IO_SIZE;
|
||||
data->acregmin = NFS_DEF_ACREGMIN;
|
||||
data->acregmax = NFS_DEF_ACREGMAX;
|
||||
data->acdirmin = NFS_DEF_ACDIRMIN;
|
||||
@ -887,6 +912,8 @@ static int nfs_parse_mount_options(char *raw,
|
||||
{
|
||||
char *p, *string, *secdata;
|
||||
int rc, sloppy = 0, invalid_option = 0;
|
||||
unsigned short protofamily = AF_UNSPEC;
|
||||
unsigned short mountfamily = AF_UNSPEC;
|
||||
|
||||
if (!raw) {
|
||||
dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
|
||||
@ -1232,12 +1259,17 @@ static int nfs_parse_mount_options(char *raw,
|
||||
token = match_token(string,
|
||||
nfs_xprt_protocol_tokens, args);
|
||||
|
||||
protofamily = AF_INET;
|
||||
switch (token) {
|
||||
case Opt_xprt_udp6:
|
||||
protofamily = AF_INET6;
|
||||
case Opt_xprt_udp:
|
||||
mnt->flags &= ~NFS_MOUNT_TCP;
|
||||
mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
|
||||
kfree(string);
|
||||
break;
|
||||
case Opt_xprt_tcp6:
|
||||
protofamily = AF_INET6;
|
||||
case Opt_xprt_tcp:
|
||||
mnt->flags |= NFS_MOUNT_TCP;
|
||||
mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
|
||||
@ -1265,10 +1297,15 @@ static int nfs_parse_mount_options(char *raw,
|
||||
nfs_xprt_protocol_tokens, args);
|
||||
kfree(string);
|
||||
|
||||
mountfamily = AF_INET;
|
||||
switch (token) {
|
||||
case Opt_xprt_udp6:
|
||||
mountfamily = AF_INET6;
|
||||
case Opt_xprt_udp:
|
||||
mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
|
||||
break;
|
||||
case Opt_xprt_tcp6:
|
||||
mountfamily = AF_INET6;
|
||||
case Opt_xprt_tcp:
|
||||
mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
|
||||
break;
|
||||
@ -1367,8 +1404,33 @@ static int nfs_parse_mount_options(char *raw,
|
||||
if (!sloppy && invalid_option)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* verify that any proto=/mountproto= options match the address
|
||||
* familiies in the addr=/mountaddr= options.
|
||||
*/
|
||||
if (protofamily != AF_UNSPEC &&
|
||||
protofamily != mnt->nfs_server.address.ss_family)
|
||||
goto out_proto_mismatch;
|
||||
|
||||
if (mountfamily != AF_UNSPEC) {
|
||||
if (mnt->mount_server.addrlen) {
|
||||
if (mountfamily != mnt->mount_server.address.ss_family)
|
||||
goto out_mountproto_mismatch;
|
||||
} else {
|
||||
if (mountfamily != mnt->nfs_server.address.ss_family)
|
||||
goto out_mountproto_mismatch;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
out_mountproto_mismatch:
|
||||
printk(KERN_INFO "NFS: mount server address does not match mountproto= "
|
||||
"option\n");
|
||||
return 0;
|
||||
out_proto_mismatch:
|
||||
printk(KERN_INFO "NFS: server address does not match proto= option\n");
|
||||
return 0;
|
||||
out_invalid_address:
|
||||
printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
|
||||
return 0;
|
||||
@ -1881,7 +1943,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
lock_kernel();
|
||||
/* fill out struct with values from existing mount */
|
||||
data->flags = nfss->flags;
|
||||
data->rsize = nfss->rsize;
|
||||
@ -1907,7 +1968,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
|
||||
error = nfs_compare_remount_data(nfss, data);
|
||||
out:
|
||||
kfree(data);
|
||||
unlock_kernel();
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -170,8 +170,8 @@ struct nfs4_sequence_args {
|
||||
struct nfs4_sequence_res {
|
||||
struct nfs4_session *sr_session;
|
||||
u8 sr_slotid; /* slot used to send request */
|
||||
unsigned long sr_renewal_time;
|
||||
int sr_status; /* sequence operation status */
|
||||
unsigned long sr_renewal_time;
|
||||
};
|
||||
|
||||
struct nfs4_get_lease_time_args {
|
||||
|
@ -130,12 +130,14 @@ struct rpc_task_setup {
|
||||
#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */
|
||||
#define RPC_TASK_KILLED 0x0100 /* task was killed */
|
||||
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
|
||||
#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
|
||||
|
||||
#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
|
||||
#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
|
||||
#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS)
|
||||
#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED)
|
||||
#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT)
|
||||
#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN)
|
||||
|
||||
#define RPC_TASK_RUNNING 0
|
||||
#define RPC_TASK_QUEUED 1
|
||||
|
@ -55,16 +55,8 @@ static size_t rpc_ntop6_noscopeid(const struct sockaddr *sap,
|
||||
|
||||
/*
|
||||
* RFC 4291, Section 2.2.1
|
||||
*
|
||||
* To keep the result as short as possible, especially
|
||||
* since we don't shorthand, we don't want leading zeros
|
||||
* in each halfword, so avoid %pI6.
|
||||
*/
|
||||
return snprintf(buf, buflen, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
ntohs(addr->s6_addr16[0]), ntohs(addr->s6_addr16[1]),
|
||||
ntohs(addr->s6_addr16[2]), ntohs(addr->s6_addr16[3]),
|
||||
ntohs(addr->s6_addr16[4]), ntohs(addr->s6_addr16[5]),
|
||||
ntohs(addr->s6_addr16[6]), ntohs(addr->s6_addr16[7]));
|
||||
return snprintf(buf, buflen, "%pI6c", addr);
|
||||
}
|
||||
|
||||
static size_t rpc_ntop6(const struct sockaddr *sap,
|
||||
|
@ -79,7 +79,7 @@ static void call_connect_status(struct rpc_task *task);
|
||||
|
||||
static __be32 *rpc_encode_header(struct rpc_task *task);
|
||||
static __be32 *rpc_verify_header(struct rpc_task *task);
|
||||
static int rpc_ping(struct rpc_clnt *clnt, int flags);
|
||||
static int rpc_ping(struct rpc_clnt *clnt);
|
||||
|
||||
static void rpc_register_client(struct rpc_clnt *clnt)
|
||||
{
|
||||
@ -340,7 +340,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
|
||||
return clnt;
|
||||
|
||||
if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
|
||||
int err = rpc_ping(clnt, RPC_TASK_SOFT);
|
||||
int err = rpc_ping(clnt);
|
||||
if (err != 0) {
|
||||
rpc_shutdown_client(clnt);
|
||||
return ERR_PTR(err);
|
||||
@ -528,7 +528,7 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
|
||||
clnt->cl_prog = program->number;
|
||||
clnt->cl_vers = version->number;
|
||||
clnt->cl_stats = program->stats;
|
||||
err = rpc_ping(clnt, RPC_TASK_SOFT);
|
||||
err = rpc_ping(clnt);
|
||||
if (err != 0) {
|
||||
rpc_shutdown_client(clnt);
|
||||
clnt = ERR_PTR(err);
|
||||
@ -1060,7 +1060,7 @@ call_bind_status(struct rpc_task *task)
|
||||
goto retry_timeout;
|
||||
case -EPFNOSUPPORT:
|
||||
/* server doesn't support any rpcbind version we know of */
|
||||
dprintk("RPC: %5u remote rpcbind service unavailable\n",
|
||||
dprintk("RPC: %5u unrecognized remote rpcbind service\n",
|
||||
task->tk_pid);
|
||||
break;
|
||||
case -EPROTONOSUPPORT:
|
||||
@ -1069,6 +1069,21 @@ call_bind_status(struct rpc_task *task)
|
||||
task->tk_status = 0;
|
||||
task->tk_action = call_bind;
|
||||
return;
|
||||
case -ECONNREFUSED: /* connection problems */
|
||||
case -ECONNRESET:
|
||||
case -ENOTCONN:
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
case -EPIPE:
|
||||
dprintk("RPC: %5u remote rpcbind unreachable: %d\n",
|
||||
task->tk_pid, task->tk_status);
|
||||
if (!RPC_IS_SOFTCONN(task)) {
|
||||
rpc_delay(task, 5*HZ);
|
||||
goto retry_timeout;
|
||||
}
|
||||
status = task->tk_status;
|
||||
break;
|
||||
default:
|
||||
dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
|
||||
task->tk_pid, -task->tk_status);
|
||||
@ -1180,11 +1195,25 @@ static void
|
||||
call_transmit_status(struct rpc_task *task)
|
||||
{
|
||||
task->tk_action = call_status;
|
||||
|
||||
/*
|
||||
* Common case: success. Force the compiler to put this
|
||||
* test first.
|
||||
*/
|
||||
if (task->tk_status == 0) {
|
||||
xprt_end_transmit(task);
|
||||
rpc_task_force_reencode(task);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (task->tk_status) {
|
||||
case -EAGAIN:
|
||||
break;
|
||||
default:
|
||||
dprint_status(task);
|
||||
xprt_end_transmit(task);
|
||||
rpc_task_force_reencode(task);
|
||||
break;
|
||||
/*
|
||||
* Special cases: if we've been waiting on the
|
||||
* socket's write_space() callback, or if the
|
||||
@ -1192,11 +1221,16 @@ call_transmit_status(struct rpc_task *task)
|
||||
* then hold onto the transport lock.
|
||||
*/
|
||||
case -ECONNREFUSED:
|
||||
case -ECONNRESET:
|
||||
case -ENOTCONN:
|
||||
case -EHOSTDOWN:
|
||||
case -EHOSTUNREACH:
|
||||
case -ENETUNREACH:
|
||||
if (RPC_IS_SOFTCONN(task)) {
|
||||
xprt_end_transmit(task);
|
||||
rpc_exit(task, task->tk_status);
|
||||
break;
|
||||
}
|
||||
case -ECONNRESET:
|
||||
case -ENOTCONN:
|
||||
case -EPIPE:
|
||||
rpc_task_force_reencode(task);
|
||||
}
|
||||
@ -1346,6 +1380,10 @@ call_timeout(struct rpc_task *task)
|
||||
dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);
|
||||
task->tk_timeouts++;
|
||||
|
||||
if (RPC_IS_SOFTCONN(task)) {
|
||||
rpc_exit(task, -ETIMEDOUT);
|
||||
return;
|
||||
}
|
||||
if (RPC_IS_SOFT(task)) {
|
||||
if (clnt->cl_chatty)
|
||||
printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
|
||||
@ -1675,14 +1713,14 @@ static struct rpc_procinfo rpcproc_null = {
|
||||
.p_decode = rpcproc_decode_null,
|
||||
};
|
||||
|
||||
static int rpc_ping(struct rpc_clnt *clnt, int flags)
|
||||
static int rpc_ping(struct rpc_clnt *clnt)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &rpcproc_null,
|
||||
};
|
||||
int err;
|
||||
msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
|
||||
err = rpc_call_sync(clnt, &msg, flags);
|
||||
err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN);
|
||||
put_rpccred(msg.rpc_cred);
|
||||
return err;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/in6.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
@ -110,6 +111,9 @@ static void rpcb_getport_done(struct rpc_task *, void *);
|
||||
static void rpcb_map_release(void *data);
|
||||
static struct rpc_program rpcb_program;
|
||||
|
||||
static struct rpc_clnt * rpcb_local_clnt;
|
||||
static struct rpc_clnt * rpcb_local_clnt4;
|
||||
|
||||
struct rpcbind_args {
|
||||
struct rpc_xprt * r_xprt;
|
||||
|
||||
@ -163,21 +167,60 @@ static const struct sockaddr_in rpcb_inaddr_loopback = {
|
||||
.sin_port = htons(RPCBIND_PORT),
|
||||
};
|
||||
|
||||
static struct rpc_clnt *rpcb_create_local(struct sockaddr *addr,
|
||||
size_t addrlen, u32 version)
|
||||
static DEFINE_MUTEX(rpcb_create_local_mutex);
|
||||
|
||||
/*
|
||||
* Returns zero on success, otherwise a negative errno value
|
||||
* is returned.
|
||||
*/
|
||||
static int rpcb_create_local(void)
|
||||
{
|
||||
struct rpc_create_args args = {
|
||||
.protocol = XPRT_TRANSPORT_UDP,
|
||||
.address = addr,
|
||||
.addrsize = addrlen,
|
||||
.protocol = XPRT_TRANSPORT_TCP,
|
||||
.address = (struct sockaddr *)&rpcb_inaddr_loopback,
|
||||
.addrsize = sizeof(rpcb_inaddr_loopback),
|
||||
.servername = "localhost",
|
||||
.program = &rpcb_program,
|
||||
.version = version,
|
||||
.version = RPCBVERS_2,
|
||||
.authflavor = RPC_AUTH_UNIX,
|
||||
.flags = RPC_CLNT_CREATE_NOPING,
|
||||
};
|
||||
struct rpc_clnt *clnt, *clnt4;
|
||||
int result = 0;
|
||||
|
||||
return rpc_create(&args);
|
||||
if (rpcb_local_clnt)
|
||||
return result;
|
||||
|
||||
mutex_lock(&rpcb_create_local_mutex);
|
||||
if (rpcb_local_clnt)
|
||||
goto out;
|
||||
|
||||
clnt = rpc_create(&args);
|
||||
if (IS_ERR(clnt)) {
|
||||
dprintk("RPC: failed to create local rpcbind "
|
||||
"client (errno %ld).\n", PTR_ERR(clnt));
|
||||
result = -PTR_ERR(clnt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* This results in an RPC ping. On systems running portmapper,
|
||||
* the v4 ping will fail. Proceed anyway, but disallow rpcb
|
||||
* v4 upcalls.
|
||||
*/
|
||||
clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4);
|
||||
if (IS_ERR(clnt4)) {
|
||||
dprintk("RPC: failed to create local rpcbind v4 "
|
||||
"cleint (errno %ld).\n", PTR_ERR(clnt4));
|
||||
clnt4 = NULL;
|
||||
}
|
||||
|
||||
rpcb_local_clnt = clnt;
|
||||
rpcb_local_clnt4 = clnt4;
|
||||
|
||||
out:
|
||||
mutex_unlock(&rpcb_create_local_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
||||
@ -209,22 +252,13 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
static int rpcb_register_call(const u32 version, struct rpc_message *msg)
|
||||
static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
|
||||
{
|
||||
struct sockaddr *addr = (struct sockaddr *)&rpcb_inaddr_loopback;
|
||||
size_t addrlen = sizeof(rpcb_inaddr_loopback);
|
||||
struct rpc_clnt *rpcb_clnt;
|
||||
int result, error = 0;
|
||||
|
||||
msg->rpc_resp = &result;
|
||||
|
||||
rpcb_clnt = rpcb_create_local(addr, addrlen, version);
|
||||
if (!IS_ERR(rpcb_clnt)) {
|
||||
error = rpc_call_sync(rpcb_clnt, msg, 0);
|
||||
rpc_shutdown_client(rpcb_clnt);
|
||||
} else
|
||||
error = PTR_ERR(rpcb_clnt);
|
||||
|
||||
error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN);
|
||||
if (error < 0) {
|
||||
dprintk("RPC: failed to contact local rpcbind "
|
||||
"server (errno %d).\n", -error);
|
||||
@ -279,6 +313,11 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = &map,
|
||||
};
|
||||
int error;
|
||||
|
||||
error = rpcb_create_local();
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
|
||||
"rpcbind\n", (port ? "" : "un"),
|
||||
@ -288,7 +327,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
|
||||
if (port)
|
||||
msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
|
||||
|
||||
return rpcb_register_call(RPCBVERS_2, &msg);
|
||||
return rpcb_register_call(rpcb_local_clnt, &msg);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -313,7 +352,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,
|
||||
if (port)
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
||||
|
||||
result = rpcb_register_call(RPCBVERS_4, msg);
|
||||
result = rpcb_register_call(rpcb_local_clnt4, msg);
|
||||
kfree(map->r_addr);
|
||||
return result;
|
||||
}
|
||||
@ -340,7 +379,7 @@ static int rpcb_register_inet6(const struct sockaddr *sap,
|
||||
if (port)
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
|
||||
|
||||
result = rpcb_register_call(RPCBVERS_4, msg);
|
||||
result = rpcb_register_call(rpcb_local_clnt4, msg);
|
||||
kfree(map->r_addr);
|
||||
return result;
|
||||
}
|
||||
@ -356,7 +395,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)
|
||||
map->r_addr = "";
|
||||
msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
|
||||
|
||||
return rpcb_register_call(RPCBVERS_4, msg);
|
||||
return rpcb_register_call(rpcb_local_clnt4, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -414,6 +453,13 @@ int rpcb_v4_register(const u32 program, const u32 version,
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = &map,
|
||||
};
|
||||
int error;
|
||||
|
||||
error = rpcb_create_local();
|
||||
if (error)
|
||||
return error;
|
||||
if (rpcb_local_clnt4 == NULL)
|
||||
return -EPROTONOSUPPORT;
|
||||
|
||||
if (address == NULL)
|
||||
return rpcb_unregister_all_protofamilies(&msg);
|
||||
@ -491,7 +537,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
|
||||
.rpc_message = &msg,
|
||||
.callback_ops = &rpcb_getport_ops,
|
||||
.callback_data = map,
|
||||
.flags = RPC_TASK_ASYNC,
|
||||
.flags = RPC_TASK_ASYNC | RPC_TASK_SOFTCONN,
|
||||
};
|
||||
|
||||
return rpc_run_task(&task_setup_data);
|
||||
@ -1027,3 +1073,15 @@ static struct rpc_program rpcb_program = {
|
||||
.version = rpcb_version,
|
||||
.stats = &rpcb_stats,
|
||||
};
|
||||
|
||||
/**
|
||||
* cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
|
||||
*
|
||||
*/
|
||||
void cleanup_rpcb_clnt(void)
|
||||
{
|
||||
if (rpcb_local_clnt4)
|
||||
rpc_shutdown_client(rpcb_local_clnt4);
|
||||
if (rpcb_local_clnt)
|
||||
rpc_shutdown_client(rpcb_local_clnt);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
extern struct cache_detail ip_map_cache, unix_gid_cache;
|
||||
|
||||
extern void cleanup_rpcb_clnt(void);
|
||||
|
||||
static int __init
|
||||
init_sunrpc(void)
|
||||
{
|
||||
@ -53,6 +55,7 @@ out:
|
||||
static void __exit
|
||||
cleanup_sunrpc(void)
|
||||
{
|
||||
cleanup_rpcb_clnt();
|
||||
rpcauth_remove_module();
|
||||
cleanup_socket_xprt();
|
||||
svc_cleanup_xprt_sock();
|
||||
|
@ -2033,7 +2033,7 @@ static void xs_connect(struct rpc_task *task)
|
||||
if (xprt_test_and_set_connecting(xprt))
|
||||
return;
|
||||
|
||||
if (transport->sock != NULL) {
|
||||
if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
|
||||
dprintk("RPC: xs_connect delayed xprt %p for %lu "
|
||||
"seconds\n",
|
||||
xprt, xprt->reestablish_timeout / HZ);
|
||||
|
Loading…
Reference in New Issue
Block a user