diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2010-12-24 01:32:32 +0000 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-01-06 14:47:56 -0500 |
commit | fca5238ef3232cd0cf4bf0457e751b3bb20912a9 (patch) | |
tree | 5b61da0d71e3e89b835d46a49e0f4945b5002cea /fs/nfs/client.c | |
parent | f7e8917a67980924651a9e244510e63ef05c7755 (diff) | |
download | lwn-fca5238ef3232cd0cf4bf0457e751b3bb20912a9.tar.gz lwn-fca5238ef3232cd0cf4bf0457e751b3bb20912a9.zip |
NFS: Allow walking nfs_client.cl_superblocks list outside client.c
We're about to move some fields from struct nfs_client to struct
nfs_server. There is a many-to-one relationship between nfs_servers
and nfs_clients. After these fields are moved to the nfs_server
struct, to visit all of the data in these fields that is owned by one
nfs_client, code will need to visit each nfs_server on the
cl_superblocks list for that nfs_client.
To serialize changes to the cl_superblocks list during these little
expeditions, protect the list with RCU.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 684b67771199..32b5fbfab35e 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1003,6 +1003,27 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve target->options = source->options; } +static void nfs_server_insert_lists(struct nfs_server *server) +{ + struct nfs_client *clp = server->nfs_client; + + spin_lock(&nfs_client_lock); + list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); + list_add_tail(&server->master_link, &nfs_volume_list); + spin_unlock(&nfs_client_lock); + +} + +static void nfs_server_remove_lists(struct nfs_server *server) +{ + spin_lock(&nfs_client_lock); + list_del_rcu(&server->client_link); + list_del(&server->master_link); + spin_unlock(&nfs_client_lock); + + synchronize_rcu(); +} + /* * Allocate and initialise a server record */ @@ -1046,11 +1067,8 @@ void nfs_free_server(struct nfs_server *server) { dprintk("--> nfs_free_server()\n"); + nfs_server_remove_lists(server); unset_pnfs_layoutdriver(server); - spin_lock(&nfs_client_lock); - list_del(&server->client_link); - list_del(&server->master_link); - spin_unlock(&nfs_client_lock); if (server->destroy != NULL) server->destroy(server); @@ -1125,11 +1143,7 @@ struct nfs_server *nfs_create_server(const struct nfs_parsed_mount_data *data, (unsigned long long) server->fsid.major, (unsigned long long) server->fsid.minor); - spin_lock(&nfs_client_lock); - list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); - list_add_tail(&server->master_link, &nfs_volume_list); - spin_unlock(&nfs_client_lock); - + nfs_server_insert_lists(server); server->mount_time = jiffies; nfs_free_fattr(fattr); return server; @@ -1454,11 +1468,7 @@ static int nfs4_server_common_setup(struct nfs_server *server, if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) server->namelen = NFS4_MAXNAMLEN; - spin_lock(&nfs_client_lock); - list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); - list_add_tail(&server->master_link, &nfs_volume_list); - spin_unlock(&nfs_client_lock); - + nfs_server_insert_lists(server); server->mount_time = jiffies; out: nfs_free_fattr(fattr); @@ -1663,11 +1673,7 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, if (error < 0) goto out_free_server; - spin_lock(&nfs_client_lock); - list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks); - list_add_tail(&server->master_link, &nfs_volume_list); - spin_unlock(&nfs_client_lock); - + nfs_server_insert_lists(server); server->mount_time = jiffies; nfs_free_fattr(fattr_fsinfo); |