Merge tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates for Linux 3.4 from Trond Myklebust: "New features include: - Add NFS client support for containers. This should enable most of the necessary functionality, including lockd support, and support for rpc.statd, NFSv4 idmapper and RPCSEC_GSS upcalls into the correct network namespace from which the mount system call was issued. - NFSv4 idmapper scalability improvements Base the idmapper cache on the keyring interface to allow concurrent access to idmapper entries. Start the process of migrating users from the single-threaded daemon-based approach to the multi-threaded request-key based approach. - NFSv4.1 implementation id. Allows the NFSv4.1 client and server to mutually identify each other for logging and debugging purposes. - Support the 'vers=4.1' mount option for mounting NFSv4.1 instead of having to use the more counterintuitive 'vers=4,minorversion=1'. - SUNRPC tracepoints. Start the process of adding tracepoints in order to improve debugging of the RPC layer. - pNFS object layout support for autologin. Important bugfixes include: - Fix a bug in rpc_wake_up/rpc_wake_up_status that caused them to fail to wake up all tasks when applied to priority waitqueues. - Ensure that we handle read delegations correctly, when we try to truncate a file. - A number of fixes for NFSv4 state manager loops (mostly to do with delegation recovery)." * tag 'nfs-for-3.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (224 commits) NFS: fix sb->s_id in nfs debug prints xprtrdma: Remove assumption that each segment is <= PAGE_SIZE xprtrdma: The transport should not bug-check when a dup reply is received pnfs-obj: autologin: Add support for protocol autologin NFS: Remove nfs4_setup_sequence from generic rename code NFS: Remove nfs4_setup_sequence from generic unlink code NFS: Remove nfs4_setup_sequence from generic read code NFS: Remove nfs4_setup_sequence from generic write code NFS: Fix more NFS debug related build warnings SUNRPC/LOCKD: Fix build warnings when CONFIG_SUNRPC_DEBUG is undefined nfs: non void functions must return a value SUNRPC: Kill compiler warning when RPC_DEBUG is unset SUNRPC/NFS: Add Kbuild dependencies for NFS_DEBUG/RPC_DEBUG NFS: Use cond_resched_lock() to reduce latencies in the commit scans NFSv4: It is not safe to dereference lsp->ls_state in release_lockowner NFS: ncommit count is being double decremented SUNRPC: We must not use list_for_each_entry_safe() in rpc_wake_up() Try using machine credentials for RENEW calls NFSv4.1: Fix a few issues in filelayout_commit_pagelist NFSv4.1: Clean ups and bugfixes for the pNFS read/writeback/commit code ...
This commit is contained in:
246
fs/nfs/client.c
246
fs/nfs/client.c
@@ -40,6 +40,8 @@
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/nfs_xdr.h>
|
||||
#include <linux/sunrpc/bc_xprt.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
|
||||
@@ -50,15 +52,12 @@
|
||||
#include "internal.h"
|
||||
#include "fscache.h"
|
||||
#include "pnfs.h"
|
||||
#include "netns.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CLIENT
|
||||
|
||||
static DEFINE_SPINLOCK(nfs_client_lock);
|
||||
static LIST_HEAD(nfs_client_list);
|
||||
static LIST_HEAD(nfs_volume_list);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
|
||||
|
||||
/*
|
||||
* Get a unique NFSv4.0 callback identifier which will be used
|
||||
@@ -67,15 +66,16 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
|
||||
static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
|
||||
{
|
||||
int ret = 0;
|
||||
struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
|
||||
|
||||
if (clp->rpc_ops->version != 4 || minorversion != 0)
|
||||
return ret;
|
||||
retry:
|
||||
if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
|
||||
if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
spin_lock(&nfs_client_lock);
|
||||
ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
return ret;
|
||||
@@ -90,7 +90,7 @@ static bool nfs4_disable_idmapping = true;
|
||||
/*
|
||||
* RPC cruft for NFS
|
||||
*/
|
||||
static struct rpc_version *nfs_version[5] = {
|
||||
static const struct rpc_version *nfs_version[5] = {
|
||||
[2] = &nfs_version2,
|
||||
#ifdef CONFIG_NFS_V3
|
||||
[3] = &nfs_version3,
|
||||
@@ -100,7 +100,7 @@ static struct rpc_version *nfs_version[5] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct rpc_program nfs_program = {
|
||||
const struct rpc_program nfs_program = {
|
||||
.name = "nfs",
|
||||
.number = NFS_PROGRAM,
|
||||
.nrvers = ARRAY_SIZE(nfs_version),
|
||||
@@ -116,11 +116,11 @@ struct rpc_stat nfs_rpcstat = {
|
||||
|
||||
#ifdef CONFIG_NFS_V3_ACL
|
||||
static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
|
||||
static struct rpc_version * nfsacl_version[] = {
|
||||
static const struct rpc_version *nfsacl_version[] = {
|
||||
[3] = &nfsacl_version3,
|
||||
};
|
||||
|
||||
struct rpc_program nfsacl_program = {
|
||||
const struct rpc_program nfsacl_program = {
|
||||
.name = "nfsacl",
|
||||
.number = NFS_ACL_PROGRAM,
|
||||
.nrvers = ARRAY_SIZE(nfsacl_version),
|
||||
@@ -136,6 +136,7 @@ struct nfs_client_initdata {
|
||||
const struct nfs_rpc_ops *rpc_ops;
|
||||
int proto;
|
||||
u32 minorversion;
|
||||
struct net *net;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -172,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
|
||||
clp->cl_rpcclient = ERR_PTR(-EINVAL);
|
||||
|
||||
clp->cl_proto = cl_init->proto;
|
||||
clp->net = get_net(cl_init->net);
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
|
||||
@@ -203,8 +205,11 @@ error_0:
|
||||
#ifdef CONFIG_NFS_V4_1
|
||||
static void nfs4_shutdown_session(struct nfs_client *clp)
|
||||
{
|
||||
if (nfs4_has_session(clp))
|
||||
if (nfs4_has_session(clp)) {
|
||||
nfs4_deviceid_purge_client(clp);
|
||||
nfs4_destroy_session(clp->cl_session);
|
||||
}
|
||||
|
||||
}
|
||||
#else /* CONFIG_NFS_V4_1 */
|
||||
static void nfs4_shutdown_session(struct nfs_client *clp)
|
||||
@@ -234,16 +239,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
|
||||
}
|
||||
|
||||
/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
|
||||
void nfs_cleanup_cb_ident_idr(void)
|
||||
void nfs_cleanup_cb_ident_idr(struct net *net)
|
||||
{
|
||||
idr_destroy(&cb_ident_idr);
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
|
||||
idr_destroy(&nn->cb_ident_idr);
|
||||
}
|
||||
|
||||
/* nfs_client_lock held */
|
||||
static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
|
||||
|
||||
if (clp->cl_cb_ident)
|
||||
idr_remove(&cb_ident_idr, clp->cl_cb_ident);
|
||||
idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
|
||||
}
|
||||
|
||||
static void pnfs_init_server(struct nfs_server *server)
|
||||
@@ -261,7 +270,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
|
||||
{
|
||||
}
|
||||
|
||||
void nfs_cleanup_cb_ident_idr(void)
|
||||
void nfs_cleanup_cb_ident_idr(struct net *net)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -293,10 +302,10 @@ static void nfs_free_client(struct nfs_client *clp)
|
||||
if (clp->cl_machine_cred != NULL)
|
||||
put_rpccred(clp->cl_machine_cred);
|
||||
|
||||
nfs4_deviceid_purge_client(clp);
|
||||
|
||||
put_net(clp->net);
|
||||
kfree(clp->cl_hostname);
|
||||
kfree(clp->server_scope);
|
||||
kfree(clp->impl_id);
|
||||
kfree(clp);
|
||||
|
||||
dprintk("<-- nfs_free_client()\n");
|
||||
@@ -307,15 +316,18 @@ static void nfs_free_client(struct nfs_client *clp)
|
||||
*/
|
||||
void nfs_put_client(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_net *nn;
|
||||
|
||||
if (!clp)
|
||||
return;
|
||||
|
||||
dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count));
|
||||
nn = net_generic(clp->net, nfs_net_id);
|
||||
|
||||
if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
|
||||
if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
|
||||
list_del(&clp->cl_share_link);
|
||||
nfs_cb_idr_remove_locked(clp);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
BUG_ON(!list_empty(&clp->cl_superblocks));
|
||||
|
||||
@@ -393,6 +405,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
|
||||
(sin1->sin_port == sin2->sin_port);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
/*
|
||||
* Test if two socket addresses represent the same actual socket,
|
||||
* by comparing (only) relevant fields, excluding the port number.
|
||||
@@ -411,6 +424,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
/*
|
||||
* Test if two socket addresses represent the same actual socket,
|
||||
@@ -431,10 +445,10 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
/* Common match routine for v4.0 and v4.1 callback services */
|
||||
bool
|
||||
nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
|
||||
u32 minorversion)
|
||||
static bool nfs4_cb_match_client(const struct sockaddr *addr,
|
||||
struct nfs_client *clp, u32 minorversion)
|
||||
{
|
||||
struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
|
||||
|
||||
@@ -454,6 +468,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
/*
|
||||
* Find an nfs_client on the list that matches the initialisation data
|
||||
@@ -463,8 +478,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
const struct sockaddr *sap = data->addr;
|
||||
struct nfs_net *nn = net_generic(data->net, nfs_net_id);
|
||||
|
||||
list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
|
||||
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
|
||||
const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
|
||||
/* Don't match clients that failed to initialise properly */
|
||||
if (clp->cl_cons_state < 0)
|
||||
@@ -502,13 +518,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
|
||||
{
|
||||
struct nfs_client *clp, *new = NULL;
|
||||
int error;
|
||||
struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
|
||||
|
||||
dprintk("--> nfs_get_client(%s,v%u)\n",
|
||||
cl_init->hostname ?: "", cl_init->rpc_ops->version);
|
||||
|
||||
/* see if the client already exists */
|
||||
do {
|
||||
spin_lock(&nfs_client_lock);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
|
||||
clp = nfs_match_client(cl_init);
|
||||
if (clp)
|
||||
@@ -516,7 +533,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
|
||||
if (new)
|
||||
goto install_client;
|
||||
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
new = nfs_alloc_client(cl_init);
|
||||
} while (!IS_ERR(new));
|
||||
@@ -527,8 +544,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
|
||||
/* install a new client and return with it unready */
|
||||
install_client:
|
||||
clp = new;
|
||||
list_add(&clp->cl_share_link, &nfs_client_list);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
list_add(&clp->cl_share_link, &nn->nfs_client_list);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
|
||||
authflavour, noresvport);
|
||||
@@ -543,7 +560,7 @@ install_client:
|
||||
* - make sure it's ready before returning
|
||||
*/
|
||||
found_client:
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
if (new)
|
||||
nfs_free_client(new);
|
||||
@@ -643,7 +660,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,
|
||||
{
|
||||
struct rpc_clnt *clnt = NULL;
|
||||
struct rpc_create_args args = {
|
||||
.net = &init_net,
|
||||
.net = clp->net,
|
||||
.protocol = clp->cl_proto,
|
||||
.address = (struct sockaddr *)&clp->cl_addr,
|
||||
.addrsize = clp->cl_addrlen,
|
||||
@@ -697,6 +714,7 @@ static int nfs_start_lockd(struct nfs_server *server)
|
||||
.nfs_version = clp->rpc_ops->version,
|
||||
.noresvport = server->flags & NFS_MOUNT_NORESVPORT ?
|
||||
1 : 0,
|
||||
.net = clp->net,
|
||||
};
|
||||
|
||||
if (nlm_init.nfs_version > 3)
|
||||
@@ -832,6 +850,7 @@ static int nfs_init_server(struct nfs_server *server,
|
||||
.addrlen = data->nfs_server.addrlen,
|
||||
.rpc_ops = &nfs_v2_clientops,
|
||||
.proto = data->nfs_server.protocol,
|
||||
.net = data->net,
|
||||
};
|
||||
struct rpc_timeout timeparms;
|
||||
struct nfs_client *clp;
|
||||
@@ -1030,25 +1049,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve
|
||||
static void nfs_server_insert_lists(struct nfs_server *server)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs_net *nn = net_generic(clp->net, nfs_net_id);
|
||||
|
||||
spin_lock(&nfs_client_lock);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
|
||||
list_add_tail(&server->master_link, &nfs_volume_list);
|
||||
list_add_tail(&server->master_link, &nn->nfs_volume_list);
|
||||
clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
}
|
||||
|
||||
static void nfs_server_remove_lists(struct nfs_server *server)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs_net *nn;
|
||||
|
||||
spin_lock(&nfs_client_lock);
|
||||
if (clp == NULL)
|
||||
return;
|
||||
nn = net_generic(clp->net, nfs_net_id);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_del_rcu(&server->client_link);
|
||||
if (clp && list_empty(&clp->cl_superblocks))
|
||||
if (list_empty(&clp->cl_superblocks))
|
||||
set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
|
||||
list_del(&server->master_link);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
synchronize_rcu();
|
||||
}
|
||||
@@ -1087,6 +1111,8 @@ static struct nfs_server *nfs_alloc_server(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ida_init(&server->openowner_id);
|
||||
ida_init(&server->lockowner_id);
|
||||
pnfs_init_server(server);
|
||||
|
||||
return server;
|
||||
@@ -1112,6 +1138,8 @@ void nfs_free_server(struct nfs_server *server)
|
||||
|
||||
nfs_put_client(server->nfs_client);
|
||||
|
||||
ida_destroy(&server->lockowner_id);
|
||||
ida_destroy(&server->openowner_id);
|
||||
nfs_free_iostats(server->io_stats);
|
||||
bdi_destroy(&server->backing_dev_info);
|
||||
kfree(server);
|
||||
@@ -1187,48 +1215,22 @@ error:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFS_V4
|
||||
/*
|
||||
* NFSv4.0 callback thread helper
|
||||
*
|
||||
* Find a client by IP address, protocol version, and minorversion
|
||||
*
|
||||
* Called from the pg_authenticate method. The callback identifier
|
||||
* is not used as it has not been decoded.
|
||||
*
|
||||
* Returns NULL if no such client
|
||||
*/
|
||||
struct nfs_client *
|
||||
nfs4_find_client_no_ident(const struct sockaddr *addr)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
|
||||
spin_lock(&nfs_client_lock);
|
||||
list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
|
||||
if (nfs4_cb_match_client(addr, clp, 0) == false)
|
||||
continue;
|
||||
atomic_inc(&clp->cl_count);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
return clp;
|
||||
}
|
||||
spin_unlock(&nfs_client_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* NFSv4.0 callback thread helper
|
||||
*
|
||||
* Find a client by callback identifier
|
||||
*/
|
||||
struct nfs_client *
|
||||
nfs4_find_client_ident(int cb_ident)
|
||||
nfs4_find_client_ident(struct net *net, int cb_ident)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
|
||||
spin_lock(&nfs_client_lock);
|
||||
clp = idr_find(&cb_ident_idr, cb_ident);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
clp = idr_find(&nn->cb_ident_idr, cb_ident);
|
||||
if (clp)
|
||||
atomic_inc(&clp->cl_count);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
return clp;
|
||||
}
|
||||
|
||||
@@ -1241,13 +1243,14 @@ nfs4_find_client_ident(int cb_ident)
|
||||
* Returns NULL if no such client
|
||||
*/
|
||||
struct nfs_client *
|
||||
nfs4_find_client_sessionid(const struct sockaddr *addr,
|
||||
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
||||
struct nfs4_sessionid *sid)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
|
||||
spin_lock(&nfs_client_lock);
|
||||
list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
|
||||
if (nfs4_cb_match_client(addr, clp, 1) == false)
|
||||
continue;
|
||||
|
||||
@@ -1260,17 +1263,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
|
||||
continue;
|
||||
|
||||
atomic_inc(&clp->cl_count);
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
return clp;
|
||||
}
|
||||
spin_unlock(&nfs_client_lock);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else /* CONFIG_NFS_V4_1 */
|
||||
|
||||
struct nfs_client *
|
||||
nfs4_find_client_sessionid(const struct sockaddr *addr,
|
||||
nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
|
||||
struct nfs4_sessionid *sid)
|
||||
{
|
||||
return NULL;
|
||||
@@ -1285,16 +1288,18 @@ static int nfs4_init_callback(struct nfs_client *clp)
|
||||
int error;
|
||||
|
||||
if (clp->rpc_ops->version == 4) {
|
||||
struct rpc_xprt *xprt;
|
||||
|
||||
xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
|
||||
|
||||
if (nfs4_has_session(clp)) {
|
||||
error = xprt_setup_backchannel(
|
||||
clp->cl_rpcclient->cl_xprt,
|
||||
error = xprt_setup_backchannel(xprt,
|
||||
NFS41_BC_MIN_CALLBACKS);
|
||||
if (error < 0)
|
||||
return error;
|
||||
}
|
||||
|
||||
error = nfs_callback_up(clp->cl_mvops->minor_version,
|
||||
clp->cl_rpcclient->cl_xprt);
|
||||
error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
|
||||
if (error < 0) {
|
||||
dprintk("%s: failed to start callback. Error = %d\n",
|
||||
__func__, error);
|
||||
@@ -1345,6 +1350,7 @@ int nfs4_init_client(struct nfs_client *clp,
|
||||
rpc_authflavor_t authflavour,
|
||||
int noresvport)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN + 1];
|
||||
int error;
|
||||
|
||||
if (clp->cl_cons_state == NFS_CS_READY) {
|
||||
@@ -1360,6 +1366,20 @@ int nfs4_init_client(struct nfs_client *clp,
|
||||
1, noresvport);
|
||||
if (error < 0)
|
||||
goto error;
|
||||
|
||||
/* If no clientaddr= option was specified, find a usable cb address */
|
||||
if (ip_addr == NULL) {
|
||||
struct sockaddr_storage cb_addr;
|
||||
struct sockaddr *sap = (struct sockaddr *)&cb_addr;
|
||||
|
||||
error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
|
||||
if (error < 0)
|
||||
goto error;
|
||||
error = rpc_ntop(sap, buf, sizeof(buf));
|
||||
if (error < 0)
|
||||
goto error;
|
||||
ip_addr = (const char *)buf;
|
||||
}
|
||||
strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
|
||||
|
||||
error = nfs_idmap_new(clp);
|
||||
@@ -1394,7 +1414,7 @@ static int nfs4_set_client(struct nfs_server *server,
|
||||
const char *ip_addr,
|
||||
rpc_authflavor_t authflavour,
|
||||
int proto, const struct rpc_timeout *timeparms,
|
||||
u32 minorversion)
|
||||
u32 minorversion, struct net *net)
|
||||
{
|
||||
struct nfs_client_initdata cl_init = {
|
||||
.hostname = hostname,
|
||||
@@ -1403,6 +1423,7 @@ static int nfs4_set_client(struct nfs_server *server,
|
||||
.rpc_ops = &nfs_v4_clientops,
|
||||
.proto = proto,
|
||||
.minorversion = minorversion,
|
||||
.net = net,
|
||||
};
|
||||
struct nfs_client *clp;
|
||||
int error;
|
||||
@@ -1454,6 +1475,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
|
||||
.rpc_ops = &nfs_v4_clientops,
|
||||
.proto = ds_proto,
|
||||
.minorversion = mds_clp->cl_minorversion,
|
||||
.net = mds_clp->net,
|
||||
};
|
||||
struct rpc_timeout ds_timeout = {
|
||||
.to_initval = 15 * HZ,
|
||||
@@ -1581,7 +1603,8 @@ static int nfs4_init_server(struct nfs_server *server,
|
||||
data->auth_flavors[0],
|
||||
data->nfs_server.protocol,
|
||||
&timeparms,
|
||||
data->minorversion);
|
||||
data->minorversion,
|
||||
data->net);
|
||||
if (error < 0)
|
||||
goto error;
|
||||
|
||||
@@ -1676,9 +1699,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
|
||||
data->addrlen,
|
||||
parent_client->cl_ipaddr,
|
||||
data->authflavor,
|
||||
parent_server->client->cl_xprt->prot,
|
||||
rpc_protocol(parent_server->client),
|
||||
parent_server->client->cl_timeout,
|
||||
parent_client->cl_mvops->minor_version);
|
||||
parent_client->cl_mvops->minor_version,
|
||||
parent_client->net);
|
||||
if (error < 0)
|
||||
goto error;
|
||||
|
||||
@@ -1771,6 +1795,18 @@ out_free_server:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
void nfs_clients_init(struct net *net)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(net, nfs_net_id);
|
||||
|
||||
INIT_LIST_HEAD(&nn->nfs_client_list);
|
||||
INIT_LIST_HEAD(&nn->nfs_volume_list);
|
||||
#ifdef CONFIG_NFS_V4
|
||||
idr_init(&nn->cb_ident_idr);
|
||||
#endif
|
||||
spin_lock_init(&nn->nfs_client_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static struct proc_dir_entry *proc_fs_nfs;
|
||||
|
||||
@@ -1824,13 +1860,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m;
|
||||
int ret;
|
||||
struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
|
||||
struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
|
||||
|
||||
ret = seq_open(file, &nfs_server_list_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
m = file->private_data;
|
||||
m->private = PDE(inode)->data;
|
||||
m->private = net;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1840,9 +1878,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
|
||||
*/
|
||||
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
|
||||
|
||||
/* lock the list against modification */
|
||||
spin_lock(&nfs_client_lock);
|
||||
return seq_list_start_head(&nfs_client_list, *_pos);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
return seq_list_start_head(&nn->nfs_client_list, *_pos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1850,7 +1890,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
|
||||
*/
|
||||
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(v, &nfs_client_list, pos);
|
||||
struct nfs_net *nn = net_generic(p->private, nfs_net_id);
|
||||
|
||||
return seq_list_next(v, &nn->nfs_client_list, pos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1858,7 +1900,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
|
||||
*/
|
||||
static void nfs_server_list_stop(struct seq_file *p, void *v)
|
||||
{
|
||||
spin_unlock(&nfs_client_lock);
|
||||
struct nfs_net *nn = net_generic(p->private, nfs_net_id);
|
||||
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1867,9 +1911,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v)
|
||||
static int nfs_server_list_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct nfs_client *clp;
|
||||
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
|
||||
|
||||
/* display header on line 1 */
|
||||
if (v == &nfs_client_list) {
|
||||
if (v == &nn->nfs_client_list) {
|
||||
seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1881,12 +1926,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
|
||||
if (clp->cl_cons_state != NFS_CS_READY)
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
seq_printf(m, "v%u %s %s %3d %s\n",
|
||||
clp->rpc_ops->version,
|
||||
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
|
||||
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
|
||||
atomic_read(&clp->cl_count),
|
||||
clp->cl_hostname);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1898,13 +1945,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m;
|
||||
int ret;
|
||||
struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
|
||||
struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
|
||||
|
||||
ret = seq_open(file, &nfs_volume_list_ops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
m = file->private_data;
|
||||
m->private = PDE(inode)->data;
|
||||
m->private = net;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1914,9 +1963,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
|
||||
*/
|
||||
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
|
||||
|
||||
/* lock the list against modification */
|
||||
spin_lock(&nfs_client_lock);
|
||||
return seq_list_start_head(&nfs_volume_list, *_pos);
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
return seq_list_start_head(&nn->nfs_volume_list, *_pos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1924,7 +1975,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
|
||||
*/
|
||||
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
|
||||
{
|
||||
return seq_list_next(v, &nfs_volume_list, pos);
|
||||
struct nfs_net *nn = net_generic(p->private, nfs_net_id);
|
||||
|
||||
return seq_list_next(v, &nn->nfs_volume_list, pos);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1932,7 +1985,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
|
||||
*/
|
||||
static void nfs_volume_list_stop(struct seq_file *p, void *v)
|
||||
{
|
||||
spin_unlock(&nfs_client_lock);
|
||||
struct nfs_net *nn = net_generic(p->private, nfs_net_id);
|
||||
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1943,9 +1998,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
|
||||
struct nfs_server *server;
|
||||
struct nfs_client *clp;
|
||||
char dev[8], fsid[17];
|
||||
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
|
||||
|
||||
/* display header on line 1 */
|
||||
if (v == &nfs_volume_list) {
|
||||
if (v == &nn->nfs_volume_list) {
|
||||
seq_puts(m, "NV SERVER PORT DEV FSID FSC\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1960,6 +2016,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
|
||||
(unsigned long long) server->fsid.major,
|
||||
(unsigned long long) server->fsid.minor);
|
||||
|
||||
rcu_read_lock();
|
||||
seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
|
||||
clp->rpc_ops->version,
|
||||
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
|
||||
@@ -1967,6 +2024,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
|
||||
dev,
|
||||
fsid,
|
||||
nfs_server_fscache_state(server));
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user