Blame view

fs/nfs/client.c 33.7 KB
24c8dbbb5   David Howells   NFS: Generalise t...
1
2
3
4
5
6
7
8
9
10
  /* client.c: NFS client sharing and management code
   *
   * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
24c8dbbb5   David Howells   NFS: Generalise t...
11
12
  #include <linux/module.h>
  #include <linux/init.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
13
  #include <linux/sched.h>
24c8dbbb5   David Howells   NFS: Generalise t...
14
15
16
17
18
19
20
  #include <linux/time.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <linux/string.h>
  #include <linux/stat.h>
  #include <linux/errno.h>
  #include <linux/unistd.h>
d8efa4e62   Anna Schumaker   NFS: Use RPC func...
21
  #include <linux/sunrpc/addr.h>
24c8dbbb5   David Howells   NFS: Generalise t...
22
23
24
  #include <linux/sunrpc/clnt.h>
  #include <linux/sunrpc/stats.h>
  #include <linux/sunrpc/metrics.h>
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
25
  #include <linux/sunrpc/xprtsock.h>
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
26
  #include <linux/sunrpc/xprtrdma.h>
24c8dbbb5   David Howells   NFS: Generalise t...
27
28
29
30
  #include <linux/nfs_fs.h>
  #include <linux/nfs_mount.h>
  #include <linux/nfs4_mount.h>
  #include <linux/lockd/bind.h>
24c8dbbb5   David Howells   NFS: Generalise t...
31
32
  #include <linux/seq_file.h>
  #include <linux/mount.h>
24c8dbbb5   David Howells   NFS: Generalise t...
33
34
  #include <linux/vfs.h>
  #include <linux/inet.h>
3b0d3f93d   Trond Myklebust   NFS: Add support ...
35
  #include <linux/in6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
404015308   Al Viro   security: trim se...
37
  #include <linux/idr.h>
3b0d3f93d   Trond Myklebust   NFS: Add support ...
38
  #include <net/ipv6.h>
24c8dbbb5   David Howells   NFS: Generalise t...
39
  #include <linux/nfs_xdr.h>
0b5b7ae0a   Andy Adamson   nfs41: Setup the ...
40
  #include <linux/sunrpc/bc_xprt.h>
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
41
42
  #include <linux/nsproxy.h>
  #include <linux/pid_namespace.h>
24c8dbbb5   David Howells   NFS: Generalise t...
43

24c8dbbb5   David Howells   NFS: Generalise t...
44
45
46
47
48
49
  
  #include "nfs4_fs.h"
  #include "callback.h"
  #include "delegation.h"
  #include "iostat.h"
  #include "internal.h"
147272813   David Howells   NFS: Define and c...
50
  #include "fscache.h"
85e174ba6   Ricardo Labiaga   NFS: set layout d...
51
  #include "pnfs.h"
ab7017a3a   Bryan Schumaker   NFS: Add version ...
52
  #include "nfs.h"
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
53
  #include "netns.h"
24c8dbbb5   David Howells   NFS: Generalise t...
54
55
  
  #define NFSDBG_FACILITY		NFSDBG_CLIENT
24c8dbbb5   David Howells   NFS: Generalise t...
56
  static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
57
58
59
  static DEFINE_SPINLOCK(nfs_version_lock);
  static DEFINE_MUTEX(nfs_version_mutex);
  static LIST_HEAD(nfs_versions);
24c8dbbb5   David Howells   NFS: Generalise t...
60
61
  
  /*
5006a76cc   David Howells   NFS: Eliminate cl...
62
63
   * RPC cruft for NFS
   */
a613fa168   Trond Myklebust   SUNRPC: constify ...
64
  static const struct rpc_version *nfs_version[5] = {
ab7017a3a   Bryan Schumaker   NFS: Add version ...
65
66
67
  	[2] = NULL,
  	[3] = NULL,
  	[4] = NULL,
5006a76cc   David Howells   NFS: Eliminate cl...
68
  };
a613fa168   Trond Myklebust   SUNRPC: constify ...
69
  const struct rpc_program nfs_program = {
5006a76cc   David Howells   NFS: Eliminate cl...
70
71
72
73
74
  	.name			= "nfs",
  	.number			= NFS_PROGRAM,
  	.nrvers			= ARRAY_SIZE(nfs_version),
  	.version		= nfs_version,
  	.stats			= &nfs_rpcstat,
fe0a9b740   Jim Rees   pnfsblock: add de...
75
  	.pipe_dir_name		= NFS_PIPE_DIRNAME,
5006a76cc   David Howells   NFS: Eliminate cl...
76
77
78
79
80
  };
  
  struct rpc_stat nfs_rpcstat = {
  	.program		= &nfs_program
  };
ab7017a3a   Bryan Schumaker   NFS: Add version ...
81
82
83
84
85
86
87
88
89
90
  static struct nfs_subversion *find_nfs_version(unsigned int version)
  {
  	struct nfs_subversion *nfs;
  	spin_lock(&nfs_version_lock);
  
  	list_for_each_entry(nfs, &nfs_versions, list) {
  		if (nfs->rpc_ops->version == version) {
  			spin_unlock(&nfs_version_lock);
  			return nfs;
  		}
ee34e1362   Yanchuan Nian   NFS: Remove unnec...
91
  	}
ab7017a3a   Bryan Schumaker   NFS: Add version ...
92
93
  
  	spin_unlock(&nfs_version_lock);
ee34e1362   Yanchuan Nian   NFS: Remove unnec...
94
  	return ERR_PTR(-EPROTONOSUPPORT);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
95
96
97
98
99
100
101
102
  }
  
  struct nfs_subversion *get_nfs_version(unsigned int version)
  {
  	struct nfs_subversion *nfs = find_nfs_version(version);
  
  	if (IS_ERR(nfs)) {
  		mutex_lock(&nfs_version_mutex);
1ae811ee2   bjschuma@gmail.com   NFS: Fix a regres...
103
  		request_module("nfsv%d", version);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
104
105
106
  		nfs = find_nfs_version(version);
  		mutex_unlock(&nfs_version_mutex);
  	}
1f70ef96b   Alexey Khoroshilov   NFS: add checks f...
107
108
  	if (!IS_ERR(nfs) && !try_module_get(nfs->owner))
  		return ERR_PTR(-EAGAIN);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  	return nfs;
  }
  
  void put_nfs_version(struct nfs_subversion *nfs)
  {
  	module_put(nfs->owner);
  }
  
  void register_nfs_version(struct nfs_subversion *nfs)
  {
  	spin_lock(&nfs_version_lock);
  
  	list_add(&nfs->list, &nfs_versions);
  	nfs_version[nfs->rpc_ops->version] = nfs->rpc_vers;
  
  	spin_unlock(&nfs_version_lock);
  }
  EXPORT_SYMBOL_GPL(register_nfs_version);
  
  void unregister_nfs_version(struct nfs_subversion *nfs)
  {
  	spin_lock(&nfs_version_lock);
  
  	nfs_version[nfs->rpc_ops->version] = NULL;
  	list_del(&nfs->list);
  
  	spin_unlock(&nfs_version_lock);
  }
  EXPORT_SYMBOL_GPL(unregister_nfs_version);
  
  /*
24c8dbbb5   David Howells   NFS: Generalise t...
140
141
142
143
144
   * Allocate a shared client record
   *
   * Since these are allocated/deallocated very rarely, we don't
   * bother putting them in a slab cache...
   */
6663ee7f8   Bryan Schumaker   NFS: Create an al...
145
  struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init)
24c8dbbb5   David Howells   NFS: Generalise t...
146
147
  {
  	struct nfs_client *clp;
7c67db3a8   Trond Myklebust   NFSv4: Reintroduc...
148
  	struct rpc_cred *cred;
a21bdd9b9   Chuck Lever   NFS: Return error...
149
  	int err = -ENOMEM;
24c8dbbb5   David Howells   NFS: Generalise t...
150
151
152
  
  	if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
  		goto error_0;
ab7017a3a   Bryan Schumaker   NFS: Add version ...
153
  	clp->cl_nfs_mod = cl_init->nfs_mod;
1f70ef96b   Alexey Khoroshilov   NFS: add checks f...
154
155
  	if (!try_module_get(clp->cl_nfs_mod->owner))
  		goto error_dealloc;
ab7017a3a   Bryan Schumaker   NFS: Add version ...
156
157
  
  	clp->rpc_ops = clp->cl_nfs_mod->rpc_ops;
40c553193   Trond Myklebust   NFS: Remove the r...
158

24c8dbbb5   David Howells   NFS: Generalise t...
159
160
  	atomic_set(&clp->cl_count, 1);
  	clp->cl_cons_state = NFS_CS_INITING;
6e4cffd7b   Chuck Lever   NFS: Expand serve...
161
162
  	memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen);
  	clp->cl_addrlen = cl_init->addrlen;
24c8dbbb5   David Howells   NFS: Generalise t...
163

3a498026e   Trond Myklebust   NFS: Clean up the...
164
  	if (cl_init->hostname) {
a21bdd9b9   Chuck Lever   NFS: Return error...
165
  		err = -ENOMEM;
3a498026e   Trond Myklebust   NFS: Clean up the...
166
  		clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL);
24c8dbbb5   David Howells   NFS: Generalise t...
167
  		if (!clp->cl_hostname)
714685137   Benny Halevy   nfs41: minorversi...
168
  			goto error_cleanup;
24c8dbbb5   David Howells   NFS: Generalise t...
169
170
171
172
  	}
  
  	INIT_LIST_HEAD(&clp->cl_superblocks);
  	clp->cl_rpcclient = ERR_PTR(-EINVAL);
59dca3b28   Trond Myklebust   NFS: Fix the 'pro...
173
  	clp->cl_proto = cl_init->proto;
73ea666c2   Chuck Lever   NFS: Use proper n...
174
  	clp->cl_net = get_net(cl_init->net);
59dca3b28   Trond Myklebust   NFS: Fix the 'pro...
175

68c97153f   Trond Myklebust   SUNRPC: Clean up ...
176
  	cred = rpc_lookup_machine_cred("*");
7c67db3a8   Trond Myklebust   NFSv4: Reintroduc...
177
178
  	if (!IS_ERR(cred))
  		clp->cl_machine_cred = cred;
147272813   David Howells   NFS: Define and c...
179
  	nfs_fscache_get_client_cookie(clp);
24c8dbbb5   David Howells   NFS: Generalise t...
180
  	return clp;
714685137   Benny Halevy   nfs41: minorversi...
181
  error_cleanup:
ab7017a3a   Bryan Schumaker   NFS: Add version ...
182
  	put_nfs_version(clp->cl_nfs_mod);
1f70ef96b   Alexey Khoroshilov   NFS: add checks f...
183
  error_dealloc:
24c8dbbb5   David Howells   NFS: Generalise t...
184
185
  	kfree(clp);
  error_0:
a21bdd9b9   Chuck Lever   NFS: Return error...
186
  	return ERR_PTR(err);
24c8dbbb5   David Howells   NFS: Generalise t...
187
  }
ddda8e0aa   Bryan Schumaker   NFS: Convert v2 i...
188
  EXPORT_SYMBOL_GPL(nfs_alloc_client);
24c8dbbb5   David Howells   NFS: Generalise t...
189

89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
190
  #if IS_ENABLED(CONFIG_NFS_V4)
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
191
  void nfs_cleanup_cb_ident_idr(struct net *net)
f4eecd5da   Andy Adamson   NFS implement v4....
192
  {
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
193
194
195
  	struct nfs_net *nn = net_generic(net, nfs_net_id);
  
  	idr_destroy(&nn->cb_ident_idr);
f4eecd5da   Andy Adamson   NFS implement v4....
196
197
198
199
200
  }
  
  /* nfs_client_lock held */
  static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
  {
73ea666c2   Chuck Lever   NFS: Use proper n...
201
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
202

f4eecd5da   Andy Adamson   NFS implement v4....
203
  	if (clp->cl_cb_ident)
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
204
  		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
f4eecd5da   Andy Adamson   NFS implement v4....
205
  }
f7e8917a6   Fred Isaman   pnfs: layout roc ...
206
207
208
209
  static void pnfs_init_server(struct nfs_server *server)
  {
  	rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
  }
888ef2e3f   Alexandros Batsakis   nfs: kill renewd ...
210
  #else
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
211
  void nfs_cleanup_cb_ident_idr(struct net *net)
f4eecd5da   Andy Adamson   NFS implement v4....
212
213
214
215
216
217
  {
  }
  
  static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
  {
  }
f7e8917a6   Fred Isaman   pnfs: layout roc ...
218
219
220
221
  
  static void pnfs_init_server(struct nfs_server *server)
  {
  }
888ef2e3f   Alexandros Batsakis   nfs: kill renewd ...
222
  #endif /* CONFIG_NFS_V4 */
557134a39   Andy Adamson   nfs41: sessions c...
223
224
  
  /*
24c8dbbb5   David Howells   NFS: Generalise t...
225
226
   * Destroy a shared client record
   */
cdb7ecede   Bryan Schumaker   NFS: Create a fre...
227
  void nfs_free_client(struct nfs_client *clp)
24c8dbbb5   David Howells   NFS: Generalise t...
228
  {
147272813   David Howells   NFS: Define and c...
229
  	nfs_fscache_release_client_cookie(clp);
24c8dbbb5   David Howells   NFS: Generalise t...
230
231
232
  	/* -EIO all pending I/O */
  	if (!IS_ERR(clp->cl_rpcclient))
  		rpc_shutdown_client(clp->cl_rpcclient);
7c67db3a8   Trond Myklebust   NFSv4: Reintroduc...
233
234
  	if (clp->cl_machine_cred != NULL)
  		put_rpccred(clp->cl_machine_cred);
73ea666c2   Chuck Lever   NFS: Use proper n...
235
  	put_net(clp->cl_net);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
236
  	put_nfs_version(clp->cl_nfs_mod);
24c8dbbb5   David Howells   NFS: Generalise t...
237
  	kfree(clp->cl_hostname);
f11b2a1cf   Jeff Layton   nfs4: copy accept...
238
  	kfree(clp->cl_acceptor);
24c8dbbb5   David Howells   NFS: Generalise t...
239
  	kfree(clp);
24c8dbbb5   David Howells   NFS: Generalise t...
240
  }
ddda8e0aa   Bryan Schumaker   NFS: Convert v2 i...
241
  EXPORT_SYMBOL_GPL(nfs_free_client);
24c8dbbb5   David Howells   NFS: Generalise t...
242
243
244
245
246
247
  
  /*
   * Release a reference to a shared client record
   */
  void nfs_put_client(struct nfs_client *clp)
  {
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
248
  	struct nfs_net *nn;
27ba85124   David Howells   NFS: Fix error ha...
249
250
  	if (!clp)
  		return;
73ea666c2   Chuck Lever   NFS: Use proper n...
251
  	nn = net_generic(clp->cl_net, nfs_net_id);
24c8dbbb5   David Howells   NFS: Generalise t...
252

dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
253
  	if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {
24c8dbbb5   David Howells   NFS: Generalise t...
254
  		list_del(&clp->cl_share_link);
f4eecd5da   Andy Adamson   NFS implement v4....
255
  		nfs_cb_idr_remove_locked(clp);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
256
  		spin_unlock(&nn->nfs_client_lock);
24c8dbbb5   David Howells   NFS: Generalise t...
257

1fea73a86   Trond Myklebust   NFS: Get rid of u...
258
  		WARN_ON_ONCE(!list_empty(&clp->cl_superblocks));
24c8dbbb5   David Howells   NFS: Generalise t...
259

cdb7ecede   Bryan Schumaker   NFS: Create a fre...
260
  		clp->rpc_ops->free_client(clp);
24c8dbbb5   David Howells   NFS: Generalise t...
261
262
  	}
  }
16b374ca4   Andy Adamson   NFSv4.1: pnfs: fi...
263
  EXPORT_SYMBOL_GPL(nfs_put_client);
24c8dbbb5   David Howells   NFS: Generalise t...
264

3fbd67ad6   Trond Myklebust   NFSv4: Iterate th...
265
  /*
c81468a1a   Trond Myklebust   NFS: Clean up the...
266
267
   * Find an nfs_client on the list that matches the initialisation data
   * that is supplied.
24c8dbbb5   David Howells   NFS: Generalise t...
268
   */
c81468a1a   Trond Myklebust   NFS: Clean up the...
269
  static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
24c8dbbb5   David Howells   NFS: Generalise t...
270
271
  {
  	struct nfs_client *clp;
d7371c41b   Ian Dall   Bug 11061, NFS mo...
272
  	const struct sockaddr *sap = data->addr;
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
273
  	struct nfs_net *nn = net_generic(data->net, nfs_net_id);
24c8dbbb5   David Howells   NFS: Generalise t...
274

53818c764   Scott Mayhew   nfs: fix a deadlo...
275
  again:
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
276
  	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
d7371c41b   Ian Dall   Bug 11061, NFS mo...
277
  	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
c81468a1a   Trond Myklebust   NFS: Clean up the...
278
279
280
  		/* Don't match clients that failed to initialise properly */
  		if (clp->cl_cons_state < 0)
  			continue;
53818c764   Scott Mayhew   nfs: fix a deadlo...
281
282
283
284
285
286
287
288
289
  		/* If a client is still initializing then we need to wait */
  		if (clp->cl_cons_state > NFS_CS_READY) {
  			atomic_inc(&clp->cl_count);
  			spin_unlock(&nn->nfs_client_lock);
  			nfs_wait_client_init_complete(clp);
  			nfs_put_client(clp);
  			spin_lock(&nn->nfs_client_lock);
  			goto again;
  		}
c81468a1a   Trond Myklebust   NFS: Clean up the...
290
  		/* Different NFS versions cannot share the same nfs_client */
ab7017a3a   Bryan Schumaker   NFS: Add version ...
291
  		if (clp->rpc_ops != data->nfs_mod->rpc_ops)
c81468a1a   Trond Myklebust   NFS: Clean up the...
292
  			continue;
59dca3b28   Trond Myklebust   NFS: Fix the 'pro...
293
294
  		if (clp->cl_proto != data->proto)
  			continue;
5aae4a9ae   Benny Halevy   nfs41: Use mount ...
295
296
297
  		/* Match nfsv4 minorversion */
  		if (clp->cl_minorversion != data->minorversion)
  			continue;
c81468a1a   Trond Myklebust   NFS: Clean up the...
298
  		/* Match the full socket address */
d8efa4e62   Anna Schumaker   NFS: Use RPC func...
299
  		if (!rpc_cmp_addr_port(sap, clap))
04ea1b3e6   Andy Adamson   NFS add xprt swit...
300
  			/* Match all xprt_switch full socket addresses */
8ef329553   Petr Vandrovec   NFS: Ignore conne...
301
302
  			if (IS_ERR(clp->cl_rpcclient) ||
                              !rpc_clnt_xprt_switch_has_addr(clp->cl_rpcclient,
04ea1b3e6   Andy Adamson   NFS add xprt swit...
303
304
  							   sap))
  				continue;
c81468a1a   Trond Myklebust   NFS: Clean up the...
305
306
307
  
  		atomic_inc(&clp->cl_count);
  		return clp;
13bbc06af   Trond Myklebust   [PATCH] NFS: Fix ...
308
  	}
c81468a1a   Trond Myklebust   NFS: Clean up the...
309
  	return NULL;
24c8dbbb5   David Howells   NFS: Generalise t...
310
  }
a33e4b036   Weston Andros Adamson   pNFS: return stat...
311
312
313
314
315
316
  /*
   * Return true if @clp is done initializing, false if still working on it.
   *
   * Use nfs_client_init_status to check if it was successful.
   */
  bool nfs_client_init_is_complete(const struct nfs_client *clp)
4697bd5e9   Trond Myklebust   NFSv4: Fix a race...
317
  {
48d66b974   Trond Myklebust   NFSv4: Fix a race...
318
  	return clp->cl_cons_state <= NFS_CS_READY;
4697bd5e9   Trond Myklebust   NFSv4: Fix a race...
319
  }
a33e4b036   Weston Andros Adamson   pNFS: return stat...
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  EXPORT_SYMBOL_GPL(nfs_client_init_is_complete);
  
  /*
   * Return 0 if @clp was successfully initialized, -errno otherwise.
   *
   * This must be called *after* nfs_client_init_is_complete() returns true,
   * otherwise it will pop WARN_ON_ONCE and return -EINVAL
   */
  int nfs_client_init_status(const struct nfs_client *clp)
  {
  	/* called without checking nfs_client_init_is_complete */
  	if (clp->cl_cons_state > NFS_CS_READY) {
  		WARN_ON_ONCE(1);
  		return -EINVAL;
  	}
  	return clp->cl_cons_state;
  }
  EXPORT_SYMBOL_GPL(nfs_client_init_status);
4697bd5e9   Trond Myklebust   NFSv4: Fix a race...
338
339
340
341
342
343
  
  int nfs_wait_client_init_complete(const struct nfs_client *clp)
  {
  	return wait_event_killable(nfs_client_active_wq,
  			nfs_client_init_is_complete(clp));
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
344
  EXPORT_SYMBOL_GPL(nfs_wait_client_init_complete);
4697bd5e9   Trond Myklebust   NFSv4: Fix a race...
345

24c8dbbb5   David Howells   NFS: Generalise t...
346
  /*
f411703ad   Chuck Lever   NFS: Refactor nfs...
347
348
349
350
351
352
353
   * Found an existing client.  Make sure it's ready before returning.
   */
  static struct nfs_client *
  nfs_found_client(const struct nfs_client_initdata *cl_init,
  		 struct nfs_client *clp)
  {
  	int error;
4697bd5e9   Trond Myklebust   NFSv4: Fix a race...
354
  	error = nfs_wait_client_init_complete(clp);
f411703ad   Chuck Lever   NFS: Refactor nfs...
355
356
357
358
359
360
361
362
363
364
  	if (error < 0) {
  		nfs_put_client(clp);
  		return ERR_PTR(-ERESTARTSYS);
  	}
  
  	if (clp->cl_cons_state < NFS_CS_READY) {
  		error = clp->cl_cons_state;
  		nfs_put_client(clp);
  		return ERR_PTR(error);
  	}
54ac471c8   Trond Myklebust   NFS: Add memory b...
365
  	smp_rmb();
f411703ad   Chuck Lever   NFS: Refactor nfs...
366
367
368
369
  	return clp;
  }
  
  /*
24c8dbbb5   David Howells   NFS: Generalise t...
370
371
372
   * Look up a client by IP address and protocol version
   * - creates a new record if one doesn't yet exist
   */
7d38de3ff   Anna Schumaker   NFS: Remove unuse...
373
  struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)
24c8dbbb5   David Howells   NFS: Generalise t...
374
375
  {
  	struct nfs_client *clp, *new = NULL;
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
376
  	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
ab7017a3a   Bryan Schumaker   NFS: Add version ...
377
  	const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops;
24c8dbbb5   David Howells   NFS: Generalise t...
378

31434f496   Peng Tao   nfs: check hostna...
379
380
381
382
  	if (cl_init->hostname == NULL) {
  		WARN_ON(1);
  		return NULL;
  	}
24c8dbbb5   David Howells   NFS: Generalise t...
383
384
  	/* see if the client already exists */
  	do {
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
385
  		spin_lock(&nn->nfs_client_lock);
24c8dbbb5   David Howells   NFS: Generalise t...
386

c81468a1a   Trond Myklebust   NFS: Clean up the...
387
  		clp = nfs_match_client(cl_init);
f411703ad   Chuck Lever   NFS: Refactor nfs...
388
389
390
  		if (clp) {
  			spin_unlock(&nn->nfs_client_lock);
  			if (new)
cdb7ecede   Bryan Schumaker   NFS: Create a fre...
391
  				new->rpc_ops->free_client(new);
f411703ad   Chuck Lever   NFS: Refactor nfs...
392
393
  			return nfs_found_client(cl_init, clp);
  		}
8cab4c390   Chuck Lever   NFS: Refactor nfs...
394
  		if (new) {
05f4c350e   Chuck Lever   NFS: Discover NFS...
395
396
  			list_add_tail(&new->cl_share_link,
  					&nn->nfs_client_list);
8cab4c390   Chuck Lever   NFS: Refactor nfs...
397
  			spin_unlock(&nn->nfs_client_lock);
4bf590e08   Chuck Lever   NFS: Add nfs_clie...
398
  			new->cl_flags = cl_init->init_flags;
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
399
  			return rpc_ops->init_client(new, cl_init);
8cab4c390   Chuck Lever   NFS: Refactor nfs...
400
  		}
24c8dbbb5   David Howells   NFS: Generalise t...
401

dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
402
  		spin_unlock(&nn->nfs_client_lock);
24c8dbbb5   David Howells   NFS: Generalise t...
403

ab7017a3a   Bryan Schumaker   NFS: Add version ...
404
  		new = rpc_ops->alloc_client(cl_init);
a21bdd9b9   Chuck Lever   NFS: Return error...
405
  	} while (!IS_ERR(new));
24c8dbbb5   David Howells   NFS: Generalise t...
406

a21bdd9b9   Chuck Lever   NFS: Return error...
407
  	return new;
24c8dbbb5   David Howells   NFS: Generalise t...
408
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
409
  EXPORT_SYMBOL_GPL(nfs_get_client);
24c8dbbb5   David Howells   NFS: Generalise t...
410
411
412
413
  
  /*
   * Mark a server as ready or failed
   */
76db6d950   Andy Adamson   nfs41: add sessio...
414
  void nfs_mark_client_ready(struct nfs_client *clp, int state)
24c8dbbb5   David Howells   NFS: Generalise t...
415
  {
54ac471c8   Trond Myklebust   NFS: Add memory b...
416
  	smp_wmb();
24c8dbbb5   David Howells   NFS: Generalise t...
417
418
419
  	clp->cl_cons_state = state;
  	wake_up_all(&nfs_client_active_wq);
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
420
  EXPORT_SYMBOL_GPL(nfs_mark_client_ready);
5006a76cc   David Howells   NFS: Eliminate cl...
421
422
423
424
  
  /*
   * Initialise the timeout values for a connection
   */
fcf10398f   Bryan Schumaker   NFS: Split out NF...
425
  void nfs_init_timeout_values(struct rpc_timeout *to, int proto,
a956beda1   Trond Myklebust   NFS: Allow the mo...
426
  				    int timeo, int retrans)
5006a76cc   David Howells   NFS: Eliminate cl...
427
428
429
  {
  	to->to_initval = timeo * HZ / 10;
  	to->to_retries = retrans;
5006a76cc   David Howells   NFS: Eliminate cl...
430
431
  
  	switch (proto) {
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
432
  	case XPRT_TRANSPORT_TCP:
2cf7ff7a3   \"Talpey, Thomas\   NFS: support RDMA...
433
  	case XPRT_TRANSPORT_RDMA:
a956beda1   Trond Myklebust   NFS: Allow the mo...
434
  		if (retrans == NFS_UNSPEC_RETRANS)
259875efe   Trond Myklebust   NFS: set transpor...
435
  			to->to_retries = NFS_DEF_TCP_RETRANS;
a956beda1   Trond Myklebust   NFS: Allow the mo...
436
  		if (timeo == NFS_UNSPEC_TIMEO || to->to_retries == 0)
259875efe   Trond Myklebust   NFS: set transpor...
437
  			to->to_initval = NFS_DEF_TCP_TIMEO * HZ / 10;
5006a76cc   David Howells   NFS: Eliminate cl...
438
439
440
441
  		if (to->to_initval > NFS_MAX_TCP_TIMEOUT)
  			to->to_initval = NFS_MAX_TCP_TIMEOUT;
  		to->to_increment = to->to_initval;
  		to->to_maxval = to->to_initval + (to->to_increment * to->to_retries);
7a3e3e18e   Trond Myklebust   NFS: Ensure that ...
442
443
444
445
  		if (to->to_maxval > NFS_MAX_TCP_TIMEOUT)
  			to->to_maxval = NFS_MAX_TCP_TIMEOUT;
  		if (to->to_maxval < to->to_initval)
  			to->to_maxval = to->to_initval;
5006a76cc   David Howells   NFS: Eliminate cl...
446
447
  		to->to_exponential = 0;
  		break;
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
448
  	case XPRT_TRANSPORT_UDP:
a956beda1   Trond Myklebust   NFS: Allow the mo...
449
  		if (retrans == NFS_UNSPEC_RETRANS)
259875efe   Trond Myklebust   NFS: set transpor...
450
  			to->to_retries = NFS_DEF_UDP_RETRANS;
a956beda1   Trond Myklebust   NFS: Allow the mo...
451
  		if (timeo == NFS_UNSPEC_TIMEO || to->to_initval == 0)
259875efe   Trond Myklebust   NFS: set transpor...
452
  			to->to_initval = NFS_DEF_UDP_TIMEO * HZ / 10;
5006a76cc   David Howells   NFS: Eliminate cl...
453
454
455
456
457
  		if (to->to_initval > NFS_MAX_UDP_TIMEOUT)
  			to->to_initval = NFS_MAX_UDP_TIMEOUT;
  		to->to_maxval = NFS_MAX_UDP_TIMEOUT;
  		to->to_exponential = 1;
  		break;
259875efe   Trond Myklebust   NFS: set transpor...
458
459
  	default:
  		BUG();
5006a76cc   David Howells   NFS: Eliminate cl...
460
461
  	}
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
462
  EXPORT_SYMBOL_GPL(nfs_init_timeout_values);
5006a76cc   David Howells   NFS: Eliminate cl...
463
464
465
466
  
  /*
   * Create an RPC client handle
   */
428360d77   Bryan Schumaker   NFS: Initialize t...
467
  int nfs_create_rpc_client(struct nfs_client *clp,
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
468
  			  const struct nfs_client_initdata *cl_init,
428360d77   Bryan Schumaker   NFS: Initialize t...
469
  			  rpc_authflavor_t flavor)
5006a76cc   David Howells   NFS: Eliminate cl...
470
  {
5006a76cc   David Howells   NFS: Eliminate cl...
471
  	struct rpc_clnt		*clnt = NULL;
41877d207   Chuck Lever   NFS: Convert NFS ...
472
  	struct rpc_create_args args = {
73ea666c2   Chuck Lever   NFS: Use proper n...
473
  		.net		= clp->cl_net,
59dca3b28   Trond Myklebust   NFS: Fix the 'pro...
474
  		.protocol	= clp->cl_proto,
41877d207   Chuck Lever   NFS: Convert NFS ...
475
  		.address	= (struct sockaddr *)&clp->cl_addr,
6e4cffd7b   Chuck Lever   NFS: Expand serve...
476
  		.addrsize	= clp->cl_addrlen,
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
477
  		.timeout	= cl_init->timeparms,
41877d207   Chuck Lever   NFS: Convert NFS ...
478
  		.servername	= clp->cl_hostname,
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
479
  		.nodename	= cl_init->nodename,
41877d207   Chuck Lever   NFS: Convert NFS ...
480
481
482
483
  		.program	= &nfs_program,
  		.version	= clp->rpc_ops->version,
  		.authflavor	= flavor,
  	};
5006a76cc   David Howells   NFS: Eliminate cl...
484

4bf590e08   Chuck Lever   NFS: Add nfs_clie...
485
  	if (test_bit(NFS_CS_DISCRTRY, &clp->cl_flags))
4a01b8a4e   Chuck Lever   NFS: expand flags...
486
  		args.flags |= RPC_CLNT_CREATE_DISCRTRY;
99875249b   Trond Myklebust   NFSv4: Ensure tha...
487
488
  	if (test_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags))
  		args.flags |= RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT;
4bf590e08   Chuck Lever   NFS: Add nfs_clie...
489
  	if (test_bit(NFS_CS_NORESVPORT, &clp->cl_flags))
4a01b8a4e   Chuck Lever   NFS: expand flags...
490
  		args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
98f98cf57   Trond Myklebust   NFSv4.1: Set the ...
491
492
  	if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags))
  		args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS;
4a01b8a4e   Chuck Lever   NFS: expand flags...
493

5006a76cc   David Howells   NFS: Eliminate cl...
494
495
  	if (!IS_ERR(clp->cl_rpcclient))
  		return 0;
41877d207   Chuck Lever   NFS: Convert NFS ...
496
  	clnt = rpc_create(&args);
5006a76cc   David Howells   NFS: Eliminate cl...
497
498
499
  	if (IS_ERR(clnt)) {
  		dprintk("%s: cannot create RPC client. Error = %ld
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
500
  				__func__, PTR_ERR(clnt));
5006a76cc   David Howells   NFS: Eliminate cl...
501
502
  		return PTR_ERR(clnt);
  	}
5006a76cc   David Howells   NFS: Eliminate cl...
503
504
505
  	clp->cl_rpcclient = clnt;
  	return 0;
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
506
  EXPORT_SYMBOL_GPL(nfs_create_rpc_client);
54ceac451   David Howells   NFS: Share NFS su...
507
508
509
510
511
512
  
  /*
   * Version 2 or 3 client destruction
   */
  static void nfs_destroy_server(struct nfs_server *server)
  {
f259613a1   NeilBrown   NFS: avoid NULL d...
513
  	if (server->nlm_host)
9289e7f91   Chuck Lever   NFS: Invoke nlmcl...
514
  		nlmclnt_done(server->nlm_host);
54ceac451   David Howells   NFS: Share NFS su...
515
516
517
518
519
520
521
  }
  
  /*
   * Version 2 or 3 lockd setup
   */
  static int nfs_start_lockd(struct nfs_server *server)
  {
9289e7f91   Chuck Lever   NFS: Invoke nlmcl...
522
523
  	struct nlm_host *host;
  	struct nfs_client *clp = server->nfs_client;
883bb163f   Chuck Lever   NLM: Introduce an...
524
525
526
527
  	struct nlmclnt_initdata nlm_init = {
  		.hostname	= clp->cl_hostname,
  		.address	= (struct sockaddr *)&clp->cl_addr,
  		.addrlen	= clp->cl_addrlen,
883bb163f   Chuck Lever   NLM: Introduce an...
528
  		.nfs_version	= clp->rpc_ops->version,
0cb2659b8   Chuck Lever   NLM: allow lockd ...
529
530
  		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?
  					1 : 0,
73ea666c2   Chuck Lever   NFS: Use proper n...
531
  		.net		= clp->cl_net,
b1ece737f   Benjamin Coddington   lockd: Introduce ...
532
  		.nlmclnt_ops 	= clp->cl_nfs_mod->rpc_ops->nlmclnt_ops,
883bb163f   Chuck Lever   NLM: Introduce an...
533
  	};
54ceac451   David Howells   NFS: Share NFS su...
534

883bb163f   Chuck Lever   NLM: Introduce an...
535
  	if (nlm_init.nfs_version > 3)
9289e7f91   Chuck Lever   NFS: Invoke nlmcl...
536
  		return 0;
5eebde232   Suresh Jayaraman   nfs: introduce mo...
537
538
  	if ((server->flags & NFS_MOUNT_LOCAL_FLOCK) &&
  			(server->flags & NFS_MOUNT_LOCAL_FCNTL))
9289e7f91   Chuck Lever   NFS: Invoke nlmcl...
539
  		return 0;
8a6e5deb8   Trond Myklebust   NFS: Get rid of t...
540
541
542
543
544
545
546
  	switch (clp->cl_proto) {
  		default:
  			nlm_init.protocol = IPPROTO_TCP;
  			break;
  		case XPRT_TRANSPORT_UDP:
  			nlm_init.protocol = IPPROTO_UDP;
  	}
883bb163f   Chuck Lever   NLM: Introduce an...
547
  	host = nlmclnt_init(&nlm_init);
9289e7f91   Chuck Lever   NFS: Invoke nlmcl...
548
549
550
551
552
553
  	if (IS_ERR(host))
  		return PTR_ERR(host);
  
  	server->nlm_host = host;
  	server->destroy = nfs_destroy_server;
  	return 0;
54ceac451   David Howells   NFS: Share NFS su...
554
555
556
  }
  
  /*
54ceac451   David Howells   NFS: Share NFS su...
557
558
   * Create a general RPC client
   */
fcf10398f   Bryan Schumaker   NFS: Split out NF...
559
  int nfs_init_server_rpcclient(struct nfs_server *server,
331702337   Trond Myklebust   NFS: Support per-...
560
561
  		const struct rpc_timeout *timeo,
  		rpc_authflavor_t pseudoflavour)
54ceac451   David Howells   NFS: Share NFS su...
562
563
  {
  	struct nfs_client *clp = server->nfs_client;
ba9b584c1   Chuck Lever   SUNRPC: Introduce...
564
565
  	server->client = rpc_clone_client_set_auth(clp->cl_rpcclient,
  							pseudoflavour);
54ceac451   David Howells   NFS: Share NFS su...
566
  	if (IS_ERR(server->client)) {
3110ff804   Harvey Harrison   nfs: replace rema...
567
568
  		dprintk("%s: couldn't create rpc_client!
  ", __func__);
54ceac451   David Howells   NFS: Share NFS su...
569
570
  		return PTR_ERR(server->client);
  	}
331702337   Trond Myklebust   NFS: Support per-...
571
572
573
574
  	memcpy(&server->client->cl_timeout_default,
  			timeo,
  			sizeof(server->client->cl_timeout_default));
  	server->client->cl_timeout = &server->client->cl_timeout_default;
54ceac451   David Howells   NFS: Share NFS su...
575
576
577
  	server->client->cl_softrtry = 0;
  	if (server->flags & NFS_MOUNT_SOFT)
  		server->client->cl_softrtry = 1;
54ceac451   David Howells   NFS: Share NFS su...
578
579
  	return 0;
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
580
  EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
54ceac451   David Howells   NFS: Share NFS su...
581

8cab4c390   Chuck Lever   NFS: Refactor nfs...
582
583
584
585
  /**
   * nfs_init_client - Initialise an NFS2 or NFS3 client
   *
   * @clp: nfs_client to initialise
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
586
   * @cl_init: Initialisation parameters
8cab4c390   Chuck Lever   NFS: Refactor nfs...
587
588
   *
   * Returns pointer to an NFS client, or an ERR_PTR value.
54ceac451   David Howells   NFS: Share NFS su...
589
   */
8cab4c390   Chuck Lever   NFS: Refactor nfs...
590
  struct nfs_client *nfs_init_client(struct nfs_client *clp,
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
591
  				   const struct nfs_client_initdata *cl_init)
54ceac451   David Howells   NFS: Share NFS su...
592
  {
54ceac451   David Howells   NFS: Share NFS su...
593
  	int error;
2844b6aec   Anna Schumaker   NFS: Clean up nfs...
594
595
  	/* the client is already initialised */
  	if (clp->cl_cons_state == NFS_CS_READY)
8cab4c390   Chuck Lever   NFS: Refactor nfs...
596
  		return clp;
54ceac451   David Howells   NFS: Share NFS su...
597

54ceac451   David Howells   NFS: Share NFS su...
598
599
600
601
  	/*
  	 * Create a client RPC handle for doing FSSTAT with UNIX auth only
  	 * - RFC 2623, sec 2.3.2
  	 */
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
602
  	error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
2844b6aec   Anna Schumaker   NFS: Clean up nfs...
603
604
605
606
607
  	nfs_mark_client_ready(clp, error == 0 ? NFS_CS_READY : error);
  	if (error < 0) {
  		nfs_put_client(clp);
  		clp = ERR_PTR(error);
  	}
8cab4c390   Chuck Lever   NFS: Refactor nfs...
608
  	return clp;
54ceac451   David Howells   NFS: Share NFS su...
609
  }
ddda8e0aa   Bryan Schumaker   NFS: Convert v2 i...
610
  EXPORT_SYMBOL_GPL(nfs_init_client);
54ceac451   David Howells   NFS: Share NFS su...
611
612
613
614
  
  /*
   * Create a version 2 or 3 client
   */
2283f8d6e   \"Talpey, Thomas\   NFS: use in-kerne...
615
  static int nfs_init_server(struct nfs_server *server,
ab7017a3a   Bryan Schumaker   NFS: Add version ...
616
617
  			   const struct nfs_parsed_mount_data *data,
  			   struct nfs_subversion *nfs_mod)
54ceac451   David Howells   NFS: Share NFS su...
618
  {
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
619
  	struct rpc_timeout timeparms;
3a498026e   Trond Myklebust   NFS: Clean up the...
620
621
  	struct nfs_client_initdata cl_init = {
  		.hostname = data->nfs_server.hostname,
d7422c472   Chuck Lever   NFS: Change nfs_g...
622
  		.addr = (const struct sockaddr *)&data->nfs_server.address,
4c5680177   Chuck Lever   NFS: Support non-...
623
  		.addrlen = data->nfs_server.addrlen,
ab7017a3a   Bryan Schumaker   NFS: Add version ...
624
  		.nfs_mod = nfs_mod,
59dca3b28   Trond Myklebust   NFS: Fix the 'pro...
625
  		.proto = data->nfs_server.protocol,
e50a7a1a4   Stanislav Kinsbursky   NFS: make NFS cli...
626
  		.net = data->net,
5c6e5b60a   Trond Myklebust   NFS: Fix an Oops ...
627
  		.timeparms = &timeparms,
3a498026e   Trond Myklebust   NFS: Clean up the...
628
  	};
54ceac451   David Howells   NFS: Share NFS su...
629
  	struct nfs_client *clp;
3a498026e   Trond Myklebust   NFS: Clean up the...
630
  	int error;
54ceac451   David Howells   NFS: Share NFS su...
631

45a52a020   Andy Adamson   NFS move nfs_clie...
632
633
  	nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
  			data->timeo, data->retrans);
4bf590e08   Chuck Lever   NFS: Add nfs_clie...
634
635
  	if (data->flags & NFS_MOUNT_NORESVPORT)
  		set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
45a52a020   Andy Adamson   NFS move nfs_clie...
636

54ceac451   David Howells   NFS: Share NFS su...
637
  	/* Allocate or find a client reference we can use */
7d38de3ff   Anna Schumaker   NFS: Remove unuse...
638
  	clp = nfs_get_client(&cl_init);
4cbb97682   Anna Schumaker   NFS: Clean up ext...
639
  	if (IS_ERR(clp))
54ceac451   David Howells   NFS: Share NFS su...
640
  		return PTR_ERR(clp);
54ceac451   David Howells   NFS: Share NFS su...
641

54ceac451   David Howells   NFS: Share NFS su...
642
643
644
  	server->nfs_client = clp;
  
  	/* Initialise the client representation from the mount data */
ff3525a53   Trond Myklebust   NFS: Don't apply ...
645
  	server->flags = data->flags;
b797cac74   David Howells   NFS: Add mount op...
646
  	server->options = data->options;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
647
648
  	server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
  		NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
cd8125997   Trond Myklebust   NFS: Remove the "...
649
  		NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
54ceac451   David Howells   NFS: Share NFS su...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  
  	if (data->rsize)
  		server->rsize = nfs_block_size(data->rsize, NULL);
  	if (data->wsize)
  		server->wsize = nfs_block_size(data->wsize, NULL);
  
  	server->acregmin = data->acregmin * HZ;
  	server->acregmax = data->acregmax * HZ;
  	server->acdirmin = data->acdirmin * HZ;
  	server->acdirmax = data->acdirmax * HZ;
  
  	/* Start lockd here, before we might error out */
  	error = nfs_start_lockd(server);
  	if (error < 0)
  		goto error;
f22d6d79f   Chuck Lever   NFS: Save the val...
665
  	server->port = data->nfs_server.port;
0f5f49b8b   Weston Andros Adamson   NFS: cache parsed...
666
  	server->auth_info = data->auth_info;
f22d6d79f   Chuck Lever   NFS: Save the val...
667

a3f73c27a   Weston Andros Adamson   NFS: separate pas...
668
669
  	error = nfs_init_server_rpcclient(server, &timeparms,
  					  data->selected_flavor);
54ceac451   David Howells   NFS: Share NFS su...
670
671
  	if (error < 0)
  		goto error;
3f8400d1f   Chuck Lever   NFS: Save the val...
672
673
674
675
676
677
678
679
680
  	/* Preserve the values of mount_server-related mount options */
  	if (data->mount_server.addrlen) {
  		memcpy(&server->mountd_address, &data->mount_server.address,
  			data->mount_server.addrlen);
  		server->mountd_addrlen = data->mount_server.addrlen;
  	}
  	server->mountd_version = data->mount_server.version;
  	server->mountd_port = data->mount_server.port;
  	server->mountd_protocol = data->mount_server.protocol;
54ceac451   David Howells   NFS: Share NFS su...
681
  	server->namelen  = data->namlen;
54ceac451   David Howells   NFS: Share NFS su...
682
683
684
685
686
  	return 0;
  
  error:
  	server->nfs_client = NULL;
  	nfs_put_client(clp);
54ceac451   David Howells   NFS: Share NFS su...
687
688
689
690
691
692
  	return error;
  }
  
  /*
   * Load up the server record from information gained in an fsinfo record
   */
738fd0f36   Benny Halevy   pnfs: add set-cle...
693
  static void nfs_server_set_fsinfo(struct nfs_server *server,
738fd0f36   Benny Halevy   pnfs: add set-cle...
694
  				  struct nfs_fsinfo *fsinfo)
54ceac451   David Howells   NFS: Share NFS su...
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
  {
  	unsigned long max_rpc_payload;
  
  	/* Work out a lot of parameters */
  	if (server->rsize == 0)
  		server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
  	if (server->wsize == 0)
  		server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
  
  	if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
  		server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
  	if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
  		server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
  
  	max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
  	if (server->rsize > max_rpc_payload)
  		server->rsize = max_rpc_payload;
  	if (server->rsize > NFS_MAX_FILE_IO_SIZE)
  		server->rsize = NFS_MAX_FILE_IO_SIZE;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
714
  	server->rpages = (server->rsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
e0bf68dde   Peter Zijlstra   mm: bdi init hooks
715

54ceac451   David Howells   NFS: Share NFS su...
716
717
718
719
  	if (server->wsize > max_rpc_payload)
  		server->wsize = max_rpc_payload;
  	if (server->wsize > NFS_MAX_FILE_IO_SIZE)
  		server->wsize = NFS_MAX_FILE_IO_SIZE;
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
720
  	server->wpages = (server->wsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
85e174ba6   Ricardo Labiaga   NFS: set layout d...
721

54ceac451   David Howells   NFS: Share NFS su...
722
723
724
  	server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
  
  	server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
725
726
  	if (server->dtsize > PAGE_SIZE * NFS_MAX_READDIR_PAGES)
  		server->dtsize = PAGE_SIZE * NFS_MAX_READDIR_PAGES;
54ceac451   David Howells   NFS: Share NFS su...
727
728
729
730
731
732
733
734
735
  	if (server->dtsize > server->rsize)
  		server->dtsize = server->rsize;
  
  	if (server->flags & NFS_MOUNT_NOAC) {
  		server->acregmin = server->acregmax = 0;
  		server->acdirmin = server->acdirmax = 0;
  	}
  
  	server->maxfilesize = fsinfo->maxfilesize;
6b96724e5   Ricardo Labiaga   Revalidate caches...
736
  	server->time_delta = fsinfo->time_delta;
2a92ee92d   Peng Tao   nfs: get clone_bl...
737
  	server->clone_blksize = fsinfo->clone_blksize;
54ceac451   David Howells   NFS: Share NFS su...
738
739
740
741
742
743
744
  	/* We're airborne Set socket buffersize */
  	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
  }
  
  /*
   * Probe filesystem information, including the FSID on v2/v3
   */
fcf10398f   Bryan Schumaker   NFS: Split out NF...
745
  int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
54ceac451   David Howells   NFS: Share NFS su...
746
747
748
749
  {
  	struct nfs_fsinfo fsinfo;
  	struct nfs_client *clp = server->nfs_client;
  	int error;
54ceac451   David Howells   NFS: Share NFS su...
750
751
752
  	if (clp->rpc_ops->set_capabilities != NULL) {
  		error = clp->rpc_ops->set_capabilities(server, mntfh);
  		if (error < 0)
4cbb97682   Anna Schumaker   NFS: Clean up ext...
753
  			return error;
54ceac451   David Howells   NFS: Share NFS su...
754
755
756
  	}
  
  	fsinfo.fattr = fattr;
ca440c383   Jeff Layton   pnfs: add a new m...
757
  	fsinfo.nlayouttypes = 0;
3132e49ec   Jeff Layton   pnfs: track multi...
758
  	memset(fsinfo.layouttype, 0, sizeof(fsinfo.layouttype));
54ceac451   David Howells   NFS: Share NFS su...
759
760
  	error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
  	if (error < 0)
4cbb97682   Anna Schumaker   NFS: Clean up ext...
761
  		return error;
54ceac451   David Howells   NFS: Share NFS su...
762

71f81e51e   Kinglong Mee   nfs: Remove unuse...
763
  	nfs_server_set_fsinfo(server, &fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
764
765
766
767
768
769
770
771
772
773
774
  
  	/* Get some general file system info */
  	if (server->namelen == 0) {
  		struct nfs_pathconf pathinfo;
  
  		pathinfo.fattr = fattr;
  		nfs_fattr_init(fattr);
  
  		if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
  			server->namelen = pathinfo.max_namelen;
  	}
54ceac451   David Howells   NFS: Share NFS su...
775
  	return 0;
54ceac451   David Howells   NFS: Share NFS su...
776
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
777
  EXPORT_SYMBOL_GPL(nfs_probe_fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
778
779
780
781
  
  /*
   * Copy useful information when duplicating a server record
   */
fcf10398f   Bryan Schumaker   NFS: Split out NF...
782
  void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
54ceac451   David Howells   NFS: Share NFS su...
783
784
  {
  	target->flags = source->flags;
356e76b85   Chuck Lever   NFS: rsize and ws...
785
786
  	target->rsize = source->rsize;
  	target->wsize = source->wsize;
54ceac451   David Howells   NFS: Share NFS su...
787
788
789
790
791
  	target->acregmin = source->acregmin;
  	target->acregmax = source->acregmax;
  	target->acdirmin = source->acdirmin;
  	target->acdirmax = source->acdirmax;
  	target->caps = source->caps;
2df548063   David Howells   NFS: Propagate 'f...
792
  	target->options = source->options;
0f5f49b8b   Weston Andros Adamson   NFS: cache parsed...
793
  	target->auth_info = source->auth_info;
89a6814d9   Steve Dickson   mount: copy the p...
794
  	target->port = source->port;
54ceac451   David Howells   NFS: Share NFS su...
795
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
796
  EXPORT_SYMBOL_GPL(nfs_server_copy_userdata);
54ceac451   David Howells   NFS: Share NFS su...
797

fcf10398f   Bryan Schumaker   NFS: Split out NF...
798
  void nfs_server_insert_lists(struct nfs_server *server)
fca5238ef   Chuck Lever   NFS: Allow walkin...
799
800
  {
  	struct nfs_client *clp = server->nfs_client;
73ea666c2   Chuck Lever   NFS: Use proper n...
801
  	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
fca5238ef   Chuck Lever   NFS: Allow walkin...
802

dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
803
  	spin_lock(&nn->nfs_client_lock);
fca5238ef   Chuck Lever   NFS: Allow walkin...
804
  	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks);
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
805
  	list_add_tail(&server->master_link, &nn->nfs_volume_list);
d3b4c9d76   Andy Adamson   NFSv4.1: new flag...
806
  	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
807
  	spin_unlock(&nn->nfs_client_lock);
fca5238ef   Chuck Lever   NFS: Allow walkin...
808
809
  
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
810
  EXPORT_SYMBOL_GPL(nfs_server_insert_lists);
fca5238ef   Chuck Lever   NFS: Allow walkin...
811

32e62b7c3   Chuck Lever   NFS: Add nfs4_upd...
812
  void nfs_server_remove_lists(struct nfs_server *server)
fca5238ef   Chuck Lever   NFS: Allow walkin...
813
  {
d3b4c9d76   Andy Adamson   NFSv4.1: new flag...
814
  	struct nfs_client *clp = server->nfs_client;
4c03ae4a8   Trond Myklebust   NFS: Initialise t...
815
  	struct nfs_net *nn;
d3b4c9d76   Andy Adamson   NFSv4.1: new flag...
816

4c03ae4a8   Trond Myklebust   NFS: Initialise t...
817
818
  	if (clp == NULL)
  		return;
73ea666c2   Chuck Lever   NFS: Use proper n...
819
  	nn = net_generic(clp->cl_net, nfs_net_id);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
820
  	spin_lock(&nn->nfs_client_lock);
fca5238ef   Chuck Lever   NFS: Allow walkin...
821
  	list_del_rcu(&server->client_link);
4c03ae4a8   Trond Myklebust   NFS: Initialise t...
822
  	if (list_empty(&clp->cl_superblocks))
d3b4c9d76   Andy Adamson   NFSv4.1: new flag...
823
  		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);
fca5238ef   Chuck Lever   NFS: Allow walkin...
824
  	list_del(&server->master_link);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
825
  	spin_unlock(&nn->nfs_client_lock);
fca5238ef   Chuck Lever   NFS: Allow walkin...
826
827
828
  
  	synchronize_rcu();
  }
32e62b7c3   Chuck Lever   NFS: Add nfs4_upd...
829
  EXPORT_SYMBOL_GPL(nfs_server_remove_lists);
fca5238ef   Chuck Lever   NFS: Allow walkin...
830

54ceac451   David Howells   NFS: Share NFS su...
831
832
833
  /*
   * Allocate and initialise a server record
   */
fcf10398f   Bryan Schumaker   NFS: Split out NF...
834
  struct nfs_server *nfs_alloc_server(void)
54ceac451   David Howells   NFS: Share NFS su...
835
836
837
838
839
840
841
842
843
844
845
846
  {
  	struct nfs_server *server;
  
  	server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
  	if (!server)
  		return NULL;
  
  	server->client = server->client_acl = ERR_PTR(-EINVAL);
  
  	/* Zero out the NFS state stuff */
  	INIT_LIST_HEAD(&server->client_link);
  	INIT_LIST_HEAD(&server->master_link);
d3978bb32   Chuck Lever   NFS: Move cl_dele...
847
  	INIT_LIST_HEAD(&server->delegations);
6382a4413   Weston Andros Adamson   NFS: move pnfs la...
848
  	INIT_LIST_HEAD(&server->layouts);
0aaaf5c42   Chuck Lever   NFS: Cache state ...
849
  	INIT_LIST_HEAD(&server->state_owners_lru);
54ceac451   David Howells   NFS: Share NFS su...
850

ef818a28f   Steve Dickson   NFS: Stop sillyna...
851
  	atomic_set(&server->active, 0);
54ceac451   David Howells   NFS: Share NFS su...
852
853
854
855
856
  	server->io_stats = nfs_alloc_iostats();
  	if (!server->io_stats) {
  		kfree(server);
  		return NULL;
  	}
9157c31dd   Trond Myklebust   NFSv4: Replace st...
857
  	ida_init(&server->openowner_id);
d2d7ce28a   Trond Myklebust   NFSv4: Replace lo...
858
  	ida_init(&server->lockowner_id);
f7e8917a6   Fred Isaman   pnfs: layout roc ...
859
  	pnfs_init_server(server);
68ebf8fe3   Benjamin Coddington   NFS: Fix uninitia...
860
  	rpc_init_wait_queue(&server->uoc_rpcwaitq, "NFS UOC");
f7e8917a6   Fred Isaman   pnfs: layout roc ...
861

54ceac451   David Howells   NFS: Share NFS su...
862
863
  	return server;
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
864
  EXPORT_SYMBOL_GPL(nfs_alloc_server);
54ceac451   David Howells   NFS: Share NFS su...
865
866
867
868
869
870
  
  /*
   * Free up a server record
   */
  void nfs_free_server(struct nfs_server *server)
  {
fca5238ef   Chuck Lever   NFS: Allow walkin...
871
  	nfs_server_remove_lists(server);
54ceac451   David Howells   NFS: Share NFS su...
872
873
874
  
  	if (server->destroy != NULL)
  		server->destroy(server);
5cef338b3   Trond Myklebust   NFSv2/v3: Fix a m...
875
876
877
  
  	if (!IS_ERR(server->client_acl))
  		rpc_shutdown_client(server->client_acl);
54ceac451   David Howells   NFS: Share NFS su...
878
879
880
881
  	if (!IS_ERR(server->client))
  		rpc_shutdown_client(server->client);
  
  	nfs_put_client(server->nfs_client);
d2d7ce28a   Trond Myklebust   NFSv4: Replace lo...
882
  	ida_destroy(&server->lockowner_id);
9157c31dd   Trond Myklebust   NFSv4: Replace st...
883
  	ida_destroy(&server->openowner_id);
54ceac451   David Howells   NFS: Share NFS su...
884
885
886
  	nfs_free_iostats(server->io_stats);
  	kfree(server);
  	nfs_release_automount_timer();
54ceac451   David Howells   NFS: Share NFS su...
887
  }
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
888
  EXPORT_SYMBOL_GPL(nfs_free_server);
54ceac451   David Howells   NFS: Share NFS su...
889
890
891
892
893
  
  /*
   * Create a version 2 or 3 volume record
   * - keyed on server and FSID
   */
1179acc6a   Bryan Schumaker   NFS: Only initial...
894
  struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info,
ab7017a3a   Bryan Schumaker   NFS: Add version ...
895
  				     struct nfs_subversion *nfs_mod)
54ceac451   David Howells   NFS: Share NFS su...
896
897
  {
  	struct nfs_server *server;
fbca779a8   Trond Myklebust   NFS: Reduce the s...
898
  	struct nfs_fattr *fattr;
54ceac451   David Howells   NFS: Share NFS su...
899
900
901
902
903
  	int error;
  
  	server = nfs_alloc_server();
  	if (!server)
  		return ERR_PTR(-ENOMEM);
fbca779a8   Trond Myklebust   NFS: Reduce the s...
904
905
906
907
  	error = -ENOMEM;
  	fattr = nfs_alloc_fattr();
  	if (fattr == NULL)
  		goto error;
54ceac451   David Howells   NFS: Share NFS su...
908
  	/* Get a client representation */
1179acc6a   Bryan Schumaker   NFS: Only initial...
909
  	error = nfs_init_server(server, mount_info->parsed, nfs_mod);
54ceac451   David Howells   NFS: Share NFS su...
910
911
  	if (error < 0)
  		goto error;
54ceac451   David Howells   NFS: Share NFS su...
912
  	/* Probe the root fh to retrieve its FSID */
1179acc6a   Bryan Schumaker   NFS: Only initial...
913
  	error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
54ceac451   David Howells   NFS: Share NFS su...
914
915
  	if (error < 0)
  		goto error;
54af3bb54   Trond Myklebust   NFS: Fix an Oops ...
916
917
918
  	if (server->nfs_client->rpc_ops->version == 3) {
  		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
  			server->namelen = NFS3_MAXNAMLEN;
1179acc6a   Bryan Schumaker   NFS: Only initial...
919
  		if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
54af3bb54   Trond Myklebust   NFS: Fix an Oops ...
920
921
922
923
924
  			server->caps |= NFS_CAP_READDIRPLUS;
  	} else {
  		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
  			server->namelen = NFS2_MAXNAMLEN;
  	}
fbca779a8   Trond Myklebust   NFS: Reduce the s...
925
  	if (!(fattr->valid & NFS_ATTR_FATTR)) {
1775fd3e8   David Quigley   NFS:Add labels to...
926
  		error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh, fattr, NULL);
54ceac451   David Howells   NFS: Share NFS su...
927
928
929
930
931
932
  		if (error < 0) {
  			dprintk("nfs_create_server: getattr error = %d
  ", -error);
  			goto error;
  		}
  	}
fbca779a8   Trond Myklebust   NFS: Reduce the s...
933
  	memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
54ceac451   David Howells   NFS: Share NFS su...
934

6daabf1b0   David Howells   NFS: Fix up compi...
935
936
937
938
  	dprintk("Server FSID: %llx:%llx
  ",
  		(unsigned long long) server->fsid.major,
  		(unsigned long long) server->fsid.minor);
54ceac451   David Howells   NFS: Share NFS su...
939

fca5238ef   Chuck Lever   NFS: Allow walkin...
940
  	nfs_server_insert_lists(server);
54ceac451   David Howells   NFS: Share NFS su...
941
  	server->mount_time = jiffies;
fbca779a8   Trond Myklebust   NFS: Reduce the s...
942
  	nfs_free_fattr(fattr);
54ceac451   David Howells   NFS: Share NFS su...
943
944
945
  	return server;
  
  error:
fbca779a8   Trond Myklebust   NFS: Reduce the s...
946
  	nfs_free_fattr(fattr);
54ceac451   David Howells   NFS: Share NFS su...
947
948
949
  	nfs_free_server(server);
  	return ERR_PTR(error);
  }
ddda8e0aa   Bryan Schumaker   NFS: Convert v2 i...
950
  EXPORT_SYMBOL_GPL(nfs_create_server);
54ceac451   David Howells   NFS: Share NFS su...
951

54ceac451   David Howells   NFS: Share NFS su...
952
953
954
955
956
  /*
   * Clone an NFS2, NFS3 or NFS4 server record
   */
  struct nfs_server *nfs_clone_server(struct nfs_server *source,
  				    struct nfs_fh *fh,
7e6eb683d   Bryan Schumaker   NFS: Honor the au...
957
958
  				    struct nfs_fattr *fattr,
  				    rpc_authflavor_t flavor)
54ceac451   David Howells   NFS: Share NFS su...
959
960
  {
  	struct nfs_server *server;
fbca779a8   Trond Myklebust   NFS: Reduce the s...
961
  	struct nfs_fattr *fattr_fsinfo;
54ceac451   David Howells   NFS: Share NFS su...
962
  	int error;
54ceac451   David Howells   NFS: Share NFS su...
963
964
965
  	server = nfs_alloc_server();
  	if (!server)
  		return ERR_PTR(-ENOMEM);
fbca779a8   Trond Myklebust   NFS: Reduce the s...
966
967
968
969
  	error = -ENOMEM;
  	fattr_fsinfo = nfs_alloc_fattr();
  	if (fattr_fsinfo == NULL)
  		goto out_free_server;
54ceac451   David Howells   NFS: Share NFS su...
970
971
  	/* Copy data from the source */
  	server->nfs_client = source->nfs_client;
0aaaf5c42   Chuck Lever   NFS: Cache state ...
972
  	server->destroy = source->destroy;
54ceac451   David Howells   NFS: Share NFS su...
973
974
975
976
  	atomic_inc(&server->nfs_client->cl_count);
  	nfs_server_copy_userdata(server, source);
  
  	server->fsid = fattr->fsid;
331702337   Trond Myklebust   NFS: Support per-...
977
978
  	error = nfs_init_server_rpcclient(server,
  			source->client->cl_timeout,
7e6eb683d   Bryan Schumaker   NFS: Honor the au...
979
  			flavor);
54ceac451   David Howells   NFS: Share NFS su...
980
981
  	if (error < 0)
  		goto out_free_server;
54ceac451   David Howells   NFS: Share NFS su...
982
983
  
  	/* probe the filesystem info for this server filesystem */
fbca779a8   Trond Myklebust   NFS: Reduce the s...
984
  	error = nfs_probe_fsinfo(server, fh, fattr_fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
985
986
  	if (error < 0)
  		goto out_free_server;
54af3bb54   Trond Myklebust   NFS: Fix an Oops ...
987
988
  	if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
  		server->namelen = NFS4_MAXNAMLEN;
54ceac451   David Howells   NFS: Share NFS su...
989
990
991
  	error = nfs_start_lockd(server);
  	if (error < 0)
  		goto out_free_server;
fca5238ef   Chuck Lever   NFS: Allow walkin...
992
  	nfs_server_insert_lists(server);
54ceac451   David Howells   NFS: Share NFS su...
993
  	server->mount_time = jiffies;
fbca779a8   Trond Myklebust   NFS: Reduce the s...
994
  	nfs_free_fattr(fattr_fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
995
996
997
  	return server;
  
  out_free_server:
fbca779a8   Trond Myklebust   NFS: Reduce the s...
998
  	nfs_free_fattr(fattr_fsinfo);
54ceac451   David Howells   NFS: Share NFS su...
999
  	nfs_free_server(server);
54ceac451   David Howells   NFS: Share NFS su...
1000
1001
  	return ERR_PTR(error);
  }
ddda8e0aa   Bryan Schumaker   NFS: Convert v2 i...
1002
  EXPORT_SYMBOL_GPL(nfs_clone_server);
6aaca5665   David Howells   NFS: Add server a...
1003

6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1004
1005
1006
1007
1008
  void nfs_clients_init(struct net *net)
  {
  	struct nfs_net *nn = net_generic(net, nfs_net_id);
  
  	INIT_LIST_HEAD(&nn->nfs_client_list);
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
1009
  	INIT_LIST_HEAD(&nn->nfs_volume_list);
89d77c8fa   Bryan Schumaker   NFS: Convert v4 i...
1010
  #if IS_ENABLED(CONFIG_NFS_V4)
28cd1b3f2   Stanislav Kinsbursky   NFS: make cb_iden...
1011
1012
  	idr_init(&nn->cb_ident_idr);
  #endif
4c03ae4a8   Trond Myklebust   NFS: Initialise t...
1013
  	spin_lock_init(&nn->nfs_client_lock);
2f86e0919   Deepa Dinamani   fs: nfs: Make nfs...
1014
  	nn->boot_time = ktime_get_real();
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1015
  }
6aaca5665   David Howells   NFS: Add server a...
1016
  #ifdef CONFIG_PROC_FS
6aaca5665   David Howells   NFS: Add server a...
1017
1018
1019
1020
1021
  static int nfs_server_list_open(struct inode *inode, struct file *file);
  static void *nfs_server_list_start(struct seq_file *p, loff_t *pos);
  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);
  static int nfs_server_list_show(struct seq_file *m, void *v);
88e9d34c7   James Morris   seq_file: constif...
1022
  static const struct seq_operations nfs_server_list_ops = {
6aaca5665   David Howells   NFS: Add server a...
1023
1024
1025
1026
1027
  	.start	= nfs_server_list_start,
  	.next	= nfs_server_list_next,
  	.stop	= nfs_server_list_stop,
  	.show	= nfs_server_list_show,
  };
00977a59b   Arjan van de Ven   [PATCH] mark stru...
1028
  static const struct file_operations nfs_server_list_fops = {
6aaca5665   David Howells   NFS: Add server a...
1029
1030
1031
  	.open		= nfs_server_list_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1032
  	.release	= seq_release_net,
6aaca5665   David Howells   NFS: Add server a...
1033
1034
1035
1036
1037
1038
1039
  };
  
  static int nfs_volume_list_open(struct inode *inode, struct file *file);
  static void *nfs_volume_list_start(struct seq_file *p, loff_t *pos);
  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);
  static int nfs_volume_list_show(struct seq_file *m, void *v);
88e9d34c7   James Morris   seq_file: constif...
1040
  static const struct seq_operations nfs_volume_list_ops = {
6aaca5665   David Howells   NFS: Add server a...
1041
1042
1043
1044
1045
  	.start	= nfs_volume_list_start,
  	.next	= nfs_volume_list_next,
  	.stop	= nfs_volume_list_stop,
  	.show	= nfs_volume_list_show,
  };
00977a59b   Arjan van de Ven   [PATCH] mark stru...
1046
  static const struct file_operations nfs_volume_list_fops = {
6aaca5665   David Howells   NFS: Add server a...
1047
1048
1049
  	.open		= nfs_volume_list_open,
  	.read		= seq_read,
  	.llseek		= seq_lseek,
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1050
  	.release	= seq_release_net,
6aaca5665   David Howells   NFS: Add server a...
1051
1052
1053
1054
1055
1056
1057
1058
  };
  
  /*
   * open "/proc/fs/nfsfs/servers" which provides a summary of servers with which
   * we're dealing
   */
  static int nfs_server_list_open(struct inode *inode, struct file *file)
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1059
1060
  	return seq_open_net(inode, file, &nfs_server_list_ops,
  			   sizeof(struct seq_net_private));
6aaca5665   David Howells   NFS: Add server a...
1061
1062
1063
1064
1065
1066
  }
  
  /*
   * set up the iterator to start reading from the server list and return the first item
   */
  static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
8d11620e1   Jeff Layton   nfs: add __acquir...
1067
  				__acquires(&nn->nfs_client_lock)
6aaca5665   David Howells   NFS: Add server a...
1068
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1069
  	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1070

6aaca5665   David Howells   NFS: Add server a...
1071
  	/* lock the list against modification */
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
1072
  	spin_lock(&nn->nfs_client_lock);
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1073
  	return seq_list_start_head(&nn->nfs_client_list, *_pos);
6aaca5665   David Howells   NFS: Add server a...
1074
1075
1076
1077
1078
1079
1080
  }
  
  /*
   * move to next server
   */
  static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1081
  	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1082
1083
  
  	return seq_list_next(v, &nn->nfs_client_list, pos);
6aaca5665   David Howells   NFS: Add server a...
1084
1085
1086
1087
1088
1089
  }
  
  /*
   * clean up after reading from the transports list
   */
  static void nfs_server_list_stop(struct seq_file *p, void *v)
8d11620e1   Jeff Layton   nfs: add __acquir...
1090
  				__releases(&nn->nfs_client_lock)
6aaca5665   David Howells   NFS: Add server a...
1091
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1092
  	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
1093
1094
  
  	spin_unlock(&nn->nfs_client_lock);
6aaca5665   David Howells   NFS: Add server a...
1095
1096
1097
1098
1099
1100
1101
1102
  }
  
  /*
   * display a header line followed by a load of call lines
   */
  static int nfs_server_list_show(struct seq_file *m, void *v)
  {
  	struct nfs_client *clp;
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1103
  	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
6aaca5665   David Howells   NFS: Add server a...
1104
1105
  
  	/* display header on line 1 */
6b13168b3   Stanislav Kinsbursky   NFS: make nfs_cli...
1106
  	if (v == &nn->nfs_client_list) {
6aaca5665   David Howells   NFS: Add server a...
1107
1108
1109
1110
1111
1112
1113
  		seq_puts(m, "NV SERVER   PORT USE HOSTNAME
  ");
  		return 0;
  	}
  
  	/* display one transport per line on subsequent lines */
  	clp = list_entry(v, struct nfs_client, cl_share_link);
940aab490   Malahal Naineni   Check validity of...
1114
1115
1116
  	/* Check if the client is initialized */
  	if (clp->cl_cons_state != NFS_CS_READY)
  		return 0;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1117
  	rcu_read_lock();
5d8515cae   Chuck Lever   NFS: eliminate NI...
1118
1119
  	seq_printf(m, "v%u %s %s %3d %s
  ",
40c553193   Trond Myklebust   NFS: Remove the r...
1120
  		   clp->rpc_ops->version,
5d8515cae   Chuck Lever   NFS: eliminate NI...
1121
1122
  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
6aaca5665   David Howells   NFS: Add server a...
1123
1124
  		   atomic_read(&clp->cl_count),
  		   clp->cl_hostname);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1125
  	rcu_read_unlock();
6aaca5665   David Howells   NFS: Add server a...
1126
1127
1128
1129
1130
1131
1132
1133
1134
  
  	return 0;
  }
  
  /*
   * open "/proc/fs/nfsfs/volumes" which provides a summary of extant volumes
   */
  static int nfs_volume_list_open(struct inode *inode, struct file *file)
  {
2f3169fb1   Fabian Frederick   nfs: fix duplicat...
1135
  	return seq_open_net(inode, file, &nfs_volume_list_ops,
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1136
  			   sizeof(struct seq_net_private));
6aaca5665   David Howells   NFS: Add server a...
1137
1138
1139
1140
1141
1142
  }
  
  /*
   * set up the iterator to start reading from the volume list and return the first item
   */
  static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
8d11620e1   Jeff Layton   nfs: add __acquir...
1143
  				__acquires(&nn->nfs_client_lock)
6aaca5665   David Howells   NFS: Add server a...
1144
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1145
  	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
1146

6aaca5665   David Howells   NFS: Add server a...
1147
  	/* lock the list against modification */
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
1148
  	spin_lock(&nn->nfs_client_lock);
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
1149
  	return seq_list_start_head(&nn->nfs_volume_list, *_pos);
6aaca5665   David Howells   NFS: Add server a...
1150
1151
1152
1153
1154
1155
1156
  }
  
  /*
   * move to next volume
   */
  static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1157
  	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
1158
1159
  
  	return seq_list_next(v, &nn->nfs_volume_list, pos);
6aaca5665   David Howells   NFS: Add server a...
1160
1161
1162
1163
1164
1165
  }
  
  /*
   * clean up after reading from the transports list
   */
  static void nfs_volume_list_stop(struct seq_file *p, void *v)
8d11620e1   Jeff Layton   nfs: add __acquir...
1166
  				__releases(&nn->nfs_client_lock)
6aaca5665   David Howells   NFS: Add server a...
1167
  {
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1168
  	struct nfs_net *nn = net_generic(seq_file_net(p), nfs_net_id);
dc0308583   Stanislav Kinsbursky   NFS: make nfs_cli...
1169
1170
  
  	spin_unlock(&nn->nfs_client_lock);
6aaca5665   David Howells   NFS: Add server a...
1171
1172
1173
1174
1175
1176
1177
1178
1179
  }
  
  /*
   * display a header line followed by a load of call lines
   */
  static int nfs_volume_list_show(struct seq_file *m, void *v)
  {
  	struct nfs_server *server;
  	struct nfs_client *clp;
df05a49f7   Kinglong Mee   nfs: Fix showing ...
1180
1181
  	char dev[13];	// 8 for 2^24, 1 for ':', 3 for 2^8, 1 for '\0'
  	char fsid[34];	// 2 * 16 for %llx, 1 for ':', 1 for '\0'
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1182
  	struct nfs_net *nn = net_generic(seq_file_net(m), nfs_net_id);
6aaca5665   David Howells   NFS: Add server a...
1183
1184
  
  	/* display header on line 1 */
c25d32b26   Stanislav Kinsbursky   NFS: make nfs_vol...
1185
  	if (v == &nn->nfs_volume_list) {
df05a49f7   Kinglong Mee   nfs: Fix showing ...
1186
1187
1188
  		seq_puts(m, "NV SERVER   PORT DEV          FSID"
  			    "                              FSC
  ");
6aaca5665   David Howells   NFS: Add server a...
1189
1190
1191
1192
1193
  		return 0;
  	}
  	/* display one transport per line on subsequent lines */
  	server = list_entry(v, struct nfs_server, master_link);
  	clp = server->nfs_client;
df05a49f7   Kinglong Mee   nfs: Fix showing ...
1194
  	snprintf(dev, sizeof(dev), "%u:%u",
6aaca5665   David Howells   NFS: Add server a...
1195
  		 MAJOR(server->s_dev), MINOR(server->s_dev));
df05a49f7   Kinglong Mee   nfs: Fix showing ...
1196
  	snprintf(fsid, sizeof(fsid), "%llx:%llx",
6daabf1b0   David Howells   NFS: Fix up compi...
1197
1198
  		 (unsigned long long) server->fsid.major,
  		 (unsigned long long) server->fsid.minor);
6aaca5665   David Howells   NFS: Add server a...
1199

2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1200
  	rcu_read_lock();
df05a49f7   Kinglong Mee   nfs: Fix showing ...
1201
1202
  	seq_printf(m, "v%u %s %s %-12s %-33s %s
  ",
40c553193   Trond Myklebust   NFS: Remove the r...
1203
  		   clp->rpc_ops->version,
5d8515cae   Chuck Lever   NFS: eliminate NI...
1204
1205
  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
6aaca5665   David Howells   NFS: Add server a...
1206
  		   dev,
5d1acff15   David Howells   NFS: Display loca...
1207
1208
  		   fsid,
  		   nfs_server_fscache_state(server));
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1209
  	rcu_read_unlock();
6aaca5665   David Howells   NFS: Add server a...
1210
1211
1212
  
  	return 0;
  }
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
  int nfs_fs_proc_net_init(struct net *net)
  {
  	struct nfs_net *nn = net_generic(net, nfs_net_id);
  	struct proc_dir_entry *p;
  
  	nn->proc_nfsfs = proc_net_mkdir(net, "nfsfs", net->proc_net);
  	if (!nn->proc_nfsfs)
  		goto error_0;
  
  	/* a file of servers with which we're dealing */
  	p = proc_create("servers", S_IFREG|S_IRUGO,
  			nn->proc_nfsfs, &nfs_server_list_fops);
  	if (!p)
  		goto error_1;
  
  	/* a file of volumes that we have mounted */
  	p = proc_create("volumes", S_IFREG|S_IRUGO,
  			nn->proc_nfsfs, &nfs_volume_list_fops);
  	if (!p)
21e81002f   Cong Wang   nfs: fix kernel w...
1232
  		goto error_1;
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1233
  	return 0;
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1234
  error_1:
21e81002f   Cong Wang   nfs: fix kernel w...
1235
  	remove_proc_subtree("nfsfs", net->proc_net);
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1236
1237
1238
1239
1240
1241
  error_0:
  	return -ENOMEM;
  }
  
  void nfs_fs_proc_net_exit(struct net *net)
  {
21e81002f   Cong Wang   nfs: fix kernel w...
1242
  	remove_proc_subtree("nfsfs", net->proc_net);
65b38851a   Eric W. Biederman   NFS: Fix /proc/fs...
1243
  }
6aaca5665   David Howells   NFS: Add server a...
1244
1245
1246
1247
1248
  /*
   * initialise the /proc/fs/nfsfs/ directory
   */
  int __init nfs_fs_proc_init(void)
  {
6a062a368   Kinglong Mee   nfs: Use remove_p...
1249
  	if (!proc_mkdir("fs/nfsfs", NULL))
6aaca5665   David Howells   NFS: Add server a...
1250
  		goto error_0;
6aaca5665   David Howells   NFS: Add server a...
1251
  	/* a file of servers with which we're dealing */
6a062a368   Kinglong Mee   nfs: Use remove_p...
1252
  	if (!proc_symlink("fs/nfsfs/servers", NULL, "../../net/nfsfs/servers"))
6aaca5665   David Howells   NFS: Add server a...
1253
  		goto error_1;
6aaca5665   David Howells   NFS: Add server a...
1254
  	/* a file of volumes that we have mounted */
6a062a368   Kinglong Mee   nfs: Use remove_p...
1255
1256
  	if (!proc_symlink("fs/nfsfs/volumes", NULL, "../../net/nfsfs/volumes"))
  		goto error_1;
6aaca5665   David Howells   NFS: Add server a...
1257

6a062a368   Kinglong Mee   nfs: Use remove_p...
1258
  	return 0;
6aaca5665   David Howells   NFS: Add server a...
1259
  error_1:
6a062a368   Kinglong Mee   nfs: Use remove_p...
1260
  	remove_proc_subtree("fs/nfsfs", NULL);
6aaca5665   David Howells   NFS: Add server a...
1261
1262
1263
1264
1265
1266
1267
1268
1269
  error_0:
  	return -ENOMEM;
  }
  
  /*
   * clean up the /proc/fs/nfsfs/ directory
   */
  void nfs_fs_proc_exit(void)
  {
6a062a368   Kinglong Mee   nfs: Use remove_p...
1270
  	remove_proc_subtree("fs/nfsfs", NULL);
6aaca5665   David Howells   NFS: Add server a...
1271
1272
1273
  }
  
  #endif /* CONFIG_PROC_FS */