Blame view

net/sunrpc/clnt.c 68.9 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
55aa4f58a   Chuck Lever   [PATCH] RPC: clie...
2
   *  linux/net/sunrpc/clnt.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
   *
   *  This file contains the high-level RPC interface.
   *  It is modeled as a finite state machine to support both synchronous
   *  and asynchronous requests.
   *
   *  -	RPC header generation and argument serialization.
   *  -	Credential refresh.
   *  -	TCP connect handling.
   *  -	Retry of operation when it is suspected the operation failed because
   *	of uid squashing on the server, or when the credentials were stale
   *	and need to be refreshed, or when a packet was damaged in transit.
   *	This may be have to be moved to the VFS layer.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
   *  Copyright (C) 1992,1993 Rick Sladkey <jrs@world.std.com>
   *  Copyright (C) 1995,1996 Olaf Kirch <okir@monad.swb.de>
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
  
  #include <linux/module.h>
  #include <linux/types.h>
cb3997b5a   Chuck Lever   SUNRPC: Display s...
22
  #include <linux/kallsyms.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/mm.h>
23ac65817   Trond Myklebust   SUNRPC: clean up ...
24
25
  #include <linux/namei.h>
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include <linux/slab.h>
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
27
  #include <linux/rcupdate.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include <linux/utsname.h>
11c556b3d   Chuck Lever   SUNRPC: provide a...
29
  #include <linux/workqueue.h>
176e21ee2   Chuck Lever   SUNRPC: Support f...
30
  #include <linux/in.h>
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
31
  #include <linux/in6.h>
176e21ee2   Chuck Lever   SUNRPC: Support f...
32
  #include <linux/un.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  
  #include <linux/sunrpc/clnt.h>
5976687a2   Jeff Layton   sunrpc: move addr...
35
  #include <linux/sunrpc/addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include <linux/sunrpc/rpc_pipe_fs.h>
11c556b3d   Chuck Lever   SUNRPC: provide a...
37
  #include <linux/sunrpc/metrics.h>
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
38
  #include <linux/sunrpc/bc_xprt.h>
5753cba17   Steve Dickson   SUNRPC: Adding st...
39
  #include <trace/events/sunrpc.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40

55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
41
  #include "sunrpc.h"
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
42
  #include "netns.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

f895b252d   Jeff Layton   sunrpc: eliminate...
44
  #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  # define RPCDBG_FACILITY	RPCDBG_CALL
  #endif
46121cf7d   Chuck Lever   SUNRPC: fix print...
47
48
49
  #define dprint_status(t)					\
  	dprintk("RPC: %5u %s (status %d)
  ", t->tk_pid,		\
0dc47877a   Harvey Harrison   net: replace rema...
50
  			__func__, t->tk_status)
46121cf7d   Chuck Lever   SUNRPC: fix print...
51

188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
52
53
54
  /*
   * All RPC clients are linked into this list
   */
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
55

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
61
62
  static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
  
  
  static void	call_start(struct rpc_task *task);
  static void	call_reserve(struct rpc_task *task);
  static void	call_reserveresult(struct rpc_task *task);
  static void	call_allocate(struct rpc_task *task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  static void	call_decode(struct rpc_task *task);
  static void	call_bind(struct rpc_task *task);
da3518780   Chuck Lever   [PATCH] RPC: prop...
65
  static void	call_bind_status(struct rpc_task *task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  static void	call_transmit(struct rpc_task *task);
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
67
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
68
  static void	call_bc_transmit(struct rpc_task *task);
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
69
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  static void	call_status(struct rpc_task *task);
940e3318c   Trond Myklebust   [PATCH] SUNRPC: d...
71
  static void	call_transmit_status(struct rpc_task *task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
  static void	call_refresh(struct rpc_task *task);
  static void	call_refreshresult(struct rpc_task *task);
  static void	call_timeout(struct rpc_task *task);
  static void	call_connect(struct rpc_task *task);
  static void	call_connect_status(struct rpc_task *task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
78
79
  static __be32	*rpc_encode_header(struct rpc_task *task);
  static __be32	*rpc_verify_header(struct rpc_task *task);
caabea8a5   Chuck Lever   SUNRPC: Use soft ...
80
  static int	rpc_ping(struct rpc_clnt *clnt);
64c91a1f1   Trond Myklebust   SUNRPC: Make rpc_...
81

188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
82
83
  static void rpc_register_client(struct rpc_clnt *clnt)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
84
85
  	struct net *net = rpc_net_ns(clnt);
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
86
87
88
89
  
  	spin_lock(&sn->rpc_client_lock);
  	list_add(&clnt->cl_clients, &sn->all_clients);
  	spin_unlock(&sn->rpc_client_lock);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
90
91
92
93
  }
  
  static void rpc_unregister_client(struct rpc_clnt *clnt)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
94
95
  	struct net *net = rpc_net_ns(clnt);
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
96
97
  
  	spin_lock(&sn->rpc_client_lock);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
98
  	list_del(&clnt->cl_clients);
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
99
  	spin_unlock(&sn->rpc_client_lock);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
100
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101

0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
102
103
  static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
  {
c36dcfe1f   Trond Myklebust   SUNRPC: Remove th...
104
  	rpc_remove_client_dir(clnt);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
105
106
107
108
  }
  
  static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
109
  	struct net *net = rpc_net_ns(clnt);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
110
  	struct super_block *pipefs_sb;
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
111

2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
112
  	pipefs_sb = rpc_get_sb_net(net);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
113
  	if (pipefs_sb) {
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
114
  		__rpc_clnt_remove_pipedir(clnt);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
115
  		rpc_put_sb_net(net);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
116
  	}
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
117
118
119
  }
  
  static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
120
  				    struct rpc_clnt *clnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  {
f134585a7   Trond Myklebust   Revert "[PATCH] R...
122
  	static uint32_t clntid;
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
123
  	const char *dir_name = clnt->cl_program->pipe_dir_name;
23ac65817   Trond Myklebust   SUNRPC: clean up ...
124
  	char name[15];
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
125
  	struct dentry *dir, *dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
127
  	dir = rpc_d_lookup_sb(sb, dir_name);
922eeac30   Weston Andros Adamson   SUNRPC: remove BU...
128
129
130
  	if (dir == NULL) {
  		pr_info("RPC: pipefs directory doesn't exist: %s
  ", dir_name);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
131
  		return dir;
922eeac30   Weston Andros Adamson   SUNRPC: remove BU...
132
  	}
f134585a7   Trond Myklebust   Revert "[PATCH] R...
133
  	for (;;) {
a95e691f9   Al Viro   rpc_create_*_dir:...
134
  		snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
23ac65817   Trond Myklebust   SUNRPC: clean up ...
135
  		name[sizeof(name) - 1] = '\0';
a95e691f9   Al Viro   rpc_create_*_dir:...
136
  		dentry = rpc_create_client_dir(dir, name, clnt);
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
137
  		if (!IS_ERR(dentry))
23ac65817   Trond Myklebust   SUNRPC: clean up ...
138
  			break;
a95e691f9   Al Viro   rpc_create_*_dir:...
139
140
141
142
143
144
145
  		if (dentry == ERR_PTR(-EEXIST))
  			continue;
  		printk(KERN_INFO "RPC: Couldn't create pipefs entry"
  				" %s/%s, error %ld
  ",
  				dir_name, name, PTR_ERR(dentry));
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	}
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
147
148
149
150
151
  	dput(dir);
  	return dentry;
  }
  
  static int
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
152
  rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
153
  {
30507f58c   Stanislav Kinsbursky   SUNRPC: remove RP...
154
  	struct dentry *dentry;
0157d021d   Stanislav Kinsbursky   SUNRPC: handle RP...
155

c36dcfe1f   Trond Myklebust   SUNRPC: Remove th...
156
157
158
159
160
  	if (clnt->cl_program->pipe_dir_name != NULL) {
  		dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
  		if (IS_ERR(dentry))
  			return PTR_ERR(dentry);
  	}
23ac65817   Trond Myklebust   SUNRPC: clean up ...
161
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  }
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
163
  static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
ea8cfa067   Stanislav Kinsbursky   SUNRPC: traverse ...
164
  {
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
165
  	if (clnt->cl_program->pipe_dir_name == NULL)
4f6bb246f   Stanislav Kinsbursky   SUNRPC: PipeFS MO...
166
  		return 1;
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
167

c36dcfe1f   Trond Myklebust   SUNRPC: Remove th...
168
169
170
171
172
173
174
175
176
177
178
179
  	switch (event) {
  	case RPC_PIPEFS_MOUNT:
  		if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
  			return 1;
  		if (atomic_read(&clnt->cl_count) == 0)
  			return 1;
  		break;
  	case RPC_PIPEFS_UMOUNT:
  		if (clnt->cl_pipedir_objects.pdh_dentry == NULL)
  			return 1;
  		break;
  	}
ea8cfa067   Stanislav Kinsbursky   SUNRPC: traverse ...
180
181
182
183
184
  	return 0;
  }
  
  static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
  				   struct super_block *sb)
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
185
186
  {
  	struct dentry *dentry;
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
187
188
189
  
  	switch (event) {
  	case RPC_PIPEFS_MOUNT:
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
190
  		dentry = rpc_setup_pipedir_sb(sb, clnt);
922eeac30   Weston Andros Adamson   SUNRPC: remove BU...
191
192
  		if (!dentry)
  			return -ENOENT;
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
193
194
  		if (IS_ERR(dentry))
  			return PTR_ERR(dentry);
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
195
196
197
198
199
200
201
202
203
  		break;
  	case RPC_PIPEFS_UMOUNT:
  		__rpc_clnt_remove_pipedir(clnt);
  		break;
  	default:
  		printk(KERN_ERR "%s: unknown event: %ld
  ", __func__, event);
  		return -ENOTSUPP;
  	}
2813b626e   Amitoj Kaur Chawla   sunrpc: Remove un...
204
  	return 0;
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
205
  }
ea8cfa067   Stanislav Kinsbursky   SUNRPC: traverse ...
206
207
208
209
210
211
212
213
214
215
216
217
218
  static int __rpc_pipefs_event(struct rpc_clnt *clnt, unsigned long event,
  				struct super_block *sb)
  {
  	int error = 0;
  
  	for (;; clnt = clnt->cl_parent) {
  		if (!rpc_clnt_skip_event(clnt, event))
  			error = __rpc_clnt_handle_event(clnt, event, sb);
  		if (error || clnt == clnt->cl_parent)
  			break;
  	}
  	return error;
  }
da3b46229   Stanislav Kinsbursky   SUNRPC: release p...
219
220
221
222
223
224
225
  static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
  {
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
  	struct rpc_clnt *clnt;
  
  	spin_lock(&sn->rpc_client_lock);
  	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
ea8cfa067   Stanislav Kinsbursky   SUNRPC: traverse ...
226
  		if (rpc_clnt_skip_event(clnt, event))
da3b46229   Stanislav Kinsbursky   SUNRPC: release p...
227
  			continue;
da3b46229   Stanislav Kinsbursky   SUNRPC: release p...
228
229
230
231
232
233
  		spin_unlock(&sn->rpc_client_lock);
  		return clnt;
  	}
  	spin_unlock(&sn->rpc_client_lock);
  	return NULL;
  }
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
234
235
236
237
238
239
  static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
  			    void *ptr)
  {
  	struct super_block *sb = ptr;
  	struct rpc_clnt *clnt;
  	int error = 0;
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
240

da3b46229   Stanislav Kinsbursky   SUNRPC: release p...
241
  	while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
242
243
244
245
  		error = __rpc_pipefs_event(clnt, event, sb);
  		if (error)
  			break;
  	}
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
246
247
248
249
250
  	return error;
  }
  
  static struct notifier_block rpc_clients_block = {
  	.notifier_call	= rpc_pipefs_event,
eee17325f   Stanislav Kinsbursky   NFS: idmap PipeFS...
251
  	.priority	= SUNRPC_PIPEFS_RPC_PRIO,
80df9d202   Stanislav Kinsbursky   SUNRPC: subscribe...
252
253
254
255
256
257
258
259
260
261
262
  };
  
  int rpc_clients_notifier_register(void)
  {
  	return rpc_pipefs_notifier_register(&rpc_clients_block);
  }
  
  void rpc_clients_notifier_unregister(void)
  {
  	return rpc_pipefs_notifier_unregister(&rpc_clients_block);
  }
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
263
264
265
266
267
268
269
  static struct rpc_xprt *rpc_clnt_set_transport(struct rpc_clnt *clnt,
  		struct rpc_xprt *xprt,
  		const struct rpc_timeout *timeout)
  {
  	struct rpc_xprt *old;
  
  	spin_lock(&clnt->cl_lock);
34751b9d0   Trond Myklebust   SUNRPC: Add corre...
270
271
  	old = rcu_dereference_protected(clnt->cl_xprt,
  			lockdep_is_held(&clnt->cl_lock));
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
272
273
274
275
276
277
278
279
280
281
  
  	if (!xprt_bound(xprt))
  		clnt->cl_autobind = 1;
  
  	clnt->cl_timeout = timeout;
  	rcu_assign_pointer(clnt->cl_xprt, xprt);
  	spin_unlock(&clnt->cl_lock);
  
  	return old;
  }
cbbb34498   Trond Myklebust   SUNRPC: RPC clien...
282
283
  static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
  {
03a9a42a1   Trond Myklebust   SUNRPC: NULL utsn...
284
285
  	clnt->cl_nodelen = strlcpy(clnt->cl_nodename,
  			nodename, sizeof(clnt->cl_nodename));
cbbb34498   Trond Myklebust   SUNRPC: RPC clien...
286
  }
d746e5452   Chuck Lever   SUNRPC: Modify sy...
287
288
289
  static int rpc_client_register(struct rpc_clnt *clnt,
  			       rpc_authflavor_t pseudoflavor,
  			       const char *client_name)
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
290
  {
c21906610   Trond Myklebust   SUNRPC: Replace c...
291
  	struct rpc_auth_create_args auth_args = {
d746e5452   Chuck Lever   SUNRPC: Modify sy...
292
293
  		.pseudoflavor = pseudoflavor,
  		.target_name = client_name,
c21906610   Trond Myklebust   SUNRPC: Replace c...
294
  	};
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
295
296
297
  	struct rpc_auth *auth;
  	struct net *net = rpc_net_ns(clnt);
  	struct super_block *pipefs_sb;
eeee24526   Trond Myklebust   SUNRPC: Fix a dea...
298
  	int err;
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
299

f9c72d10d   Jeff Layton   sunrpc: make debu...
300
  	rpc_clnt_debugfs_register(clnt);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
301

e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
302
303
  	pipefs_sb = rpc_get_sb_net(net);
  	if (pipefs_sb) {
41b6b4d0b   Trond Myklebust   SUNRPC: Cleanup r...
304
  		err = rpc_setup_pipedir(pipefs_sb, clnt);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
305
306
307
  		if (err)
  			goto out;
  	}
eeee24526   Trond Myklebust   SUNRPC: Fix a dea...
308
309
310
  	rpc_register_client(clnt);
  	if (pipefs_sb)
  		rpc_put_sb_net(net);
c21906610   Trond Myklebust   SUNRPC: Replace c...
311
  	auth = rpcauth_create(&auth_args, clnt);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
312
313
314
  	if (IS_ERR(auth)) {
  		dprintk("RPC:       Couldn't create auth handle (flavor %u)
  ",
d746e5452   Chuck Lever   SUNRPC: Modify sy...
315
  				pseudoflavor);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
316
317
318
  		err = PTR_ERR(auth);
  		goto err_auth;
  	}
eeee24526   Trond Myklebust   SUNRPC: Fix a dea...
319
320
321
  	return 0;
  err_auth:
  	pipefs_sb = rpc_get_sb_net(net);
1540c5d3c   Trond Myklebust   SUNRPC: Fix anoth...
322
  	rpc_unregister_client(clnt);
eeee24526   Trond Myklebust   SUNRPC: Fix a dea...
323
  	__rpc_clnt_remove_pipedir(clnt);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
324
325
326
  out:
  	if (pipefs_sb)
  		rpc_put_sb_net(net);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
327
  	rpc_clnt_debugfs_unregister(clnt);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
328
  	return err;
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
329
  }
2f048db46   Trond Myklebust   SUNRPC: Add an id...
330
  static DEFINE_IDA(rpc_clids);
c929ea0b9   Kinglong Mee   SUNRPC: cleanup i...
331
332
333
334
  void rpc_cleanup_clids(void)
  {
  	ida_destroy(&rpc_clids);
  }
2f048db46   Trond Myklebust   SUNRPC: Add an id...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  static int rpc_alloc_clid(struct rpc_clnt *clnt)
  {
  	int clid;
  
  	clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL);
  	if (clid < 0)
  		return clid;
  	clnt->cl_clid = clid;
  	return 0;
  }
  
  static void rpc_free_clid(struct rpc_clnt *clnt)
  {
  	ida_simple_remove(&rpc_clids, clnt->cl_clid);
  }
280ebcf97   Trond Myklebust   SUNRPC: rpcauth_c...
350
  static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
351
  		struct rpc_xprt_switch *xps,
280ebcf97   Trond Myklebust   SUNRPC: rpcauth_c...
352
353
  		struct rpc_xprt *xprt,
  		struct rpc_clnt *parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
354
  {
a613fa168   Trond Myklebust   SUNRPC: constify ...
355
356
  	const struct rpc_program *program = args->program;
  	const struct rpc_version *version;
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
357
358
  	struct rpc_clnt *clnt = NULL;
  	const struct rpc_timeout *timeout;
03a9a42a1   Trond Myklebust   SUNRPC: NULL utsn...
359
  	const char *nodename = args->nodename;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  	int err;
06b8d2552   Chuck Lever   SUNRPC: Make sure...
361
362
  
  	/* sanity check the name before trying to print it */
46121cf7d   Chuck Lever   SUNRPC: fix print...
363
364
  	dprintk("RPC:       creating %s client for %s (xprt %p)
  ",
698b6d088   Trond Myklebust   SUNRPC: cleanup f...
365
  			program->name, args->servername, xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366

4ada539ed   Trond Myklebust   SUNRPC: Make crea...
367
368
369
  	err = rpciod_up();
  	if (err)
  		goto out_no_rpciod;
698b6d088   Trond Myklebust   SUNRPC: cleanup f...
370

f05c124a7   Trond Myklebust   SUNRPC: Fix a pot...
371
  	err = -EINVAL;
698b6d088   Trond Myklebust   SUNRPC: cleanup f...
372
373
374
375
  	if (args->version >= program->nrvers)
  		goto out_err;
  	version = program->version[args->version];
  	if (version == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
  		goto out_err;
  
  	err = -ENOMEM;
0da974f4f   Panagiotis Issaris   [NET]: Conversion...
379
  	clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
  	if (!clnt)
  		goto out_err;
280ebcf97   Trond Myklebust   SUNRPC: rpcauth_c...
382
  	clnt->cl_parent = parent ? : clnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

2f048db46   Trond Myklebust   SUNRPC: Add an id...
384
385
386
  	err = rpc_alloc_clid(clnt);
  	if (err)
  		goto out_no_clid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  	clnt->cl_procinfo = version->procs;
  	clnt->cl_maxproc  = version->nrprocs;
d5b337b48   Benny Halevy   nfsd: use nfs cli...
390
  	clnt->cl_prog     = args->prognumber ? : program->number;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	clnt->cl_vers     = version->number;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  	clnt->cl_stats    = program->stats;
11c556b3d   Chuck Lever   SUNRPC: provide a...
393
  	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
6739ffb75   Trond Myklebust   SUNRPC: Add a fra...
394
  	rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
23bf85ba4   Trond Myklebust   SUNRPC: Handle th...
395
396
397
  	err = -ENOMEM;
  	if (clnt->cl_metrics == NULL)
  		goto out_no_stats;
3e32a5d99   Trond Myklebust   SUNRPC: Give clon...
398
  	clnt->cl_program  = program;
6529eba08   Trond Myklebust   SUNRPC: Move rpc_...
399
  	INIT_LIST_HEAD(&clnt->cl_tasks);
4bef61ff7   Trond Myklebust   SUNRPC: Add a per...
400
  	spin_lock_init(&clnt->cl_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401

40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
402
  	timeout = xprt->timeout;
ba7392bb3   Trond Myklebust   SUNRPC: Add suppo...
403
404
405
  	if (args->timeout != NULL) {
  		memcpy(&clnt->cl_timeout_default, args->timeout,
  				sizeof(clnt->cl_timeout_default));
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
406
  		timeout = &clnt->cl_timeout_default;
ba7392bb3   Trond Myklebust   SUNRPC: Add suppo...
407
  	}
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
408
  	rpc_clnt_set_transport(clnt, xprt, timeout);
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
409
410
  	xprt_iter_init(&clnt->cl_xpi, xps);
  	xprt_switch_put(xps);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
411

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  	clnt->cl_rtt = &clnt->cl_rtt_default;
ba7392bb3   Trond Myklebust   SUNRPC: Add suppo...
413
  	rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414

006abe887   Trond Myklebust   SUNRPC: Fix a rac...
415
  	atomic_set(&clnt->cl_count, 1);
34f52e359   Trond Myklebust   SUNRPC: Convert r...
416

03a9a42a1   Trond Myklebust   SUNRPC: NULL utsn...
417
418
  	if (nodename == NULL)
  		nodename = utsname()->nodename;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
  	/* save the nodename */
03a9a42a1   Trond Myklebust   SUNRPC: NULL utsn...
420
  	rpc_clnt_set_nodename(clnt, nodename);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
421

d746e5452   Chuck Lever   SUNRPC: Modify sy...
422
  	err = rpc_client_register(clnt, args->authflavor, args->client_name);
e73f4cc05   Stanislav Kinsbursky   SUNRPC: split cli...
423
424
  	if (err)
  		goto out_no_path;
280ebcf97   Trond Myklebust   SUNRPC: rpcauth_c...
425
426
  	if (parent)
  		atomic_inc(&parent->cl_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  	return clnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  out_no_path:
23bf85ba4   Trond Myklebust   SUNRPC: Handle th...
429
430
  	rpc_free_iostats(clnt->cl_metrics);
  out_no_stats:
2f048db46   Trond Myklebust   SUNRPC: Add an id...
431
432
  	rpc_free_clid(clnt);
  out_no_clid:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  	kfree(clnt);
  out_err:
4ada539ed   Trond Myklebust   SUNRPC: Make crea...
435
436
  	rpciod_down();
  out_no_rpciod:
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
437
  	xprt_switch_put(xps);
f05c124a7   Trond Myklebust   SUNRPC: Fix a pot...
438
  	xprt_put(xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	return ERR_PTR(err);
  }
d50039ea5   J. Bruce Fields   nfsd4/rpc: move b...
441
  static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
442
443
444
  					struct rpc_xprt *xprt)
  {
  	struct rpc_clnt *clnt = NULL;
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
445
  	struct rpc_xprt_switch *xps;
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
446

39a9beab5   J. Bruce Fields   rpc: share one xp...
447
  	if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) {
16590a228   Chuck Lever   SUNRPC: Silence W...
448
  		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
39a9beab5   J. Bruce Fields   rpc: share one xp...
449
450
451
452
453
454
455
456
457
458
459
460
  		xps = args->bc_xprt->xpt_bc_xps;
  		xprt_switch_get(xps);
  	} else {
  		xps = xprt_switch_alloc(xprt, GFP_KERNEL);
  		if (xps == NULL) {
  			xprt_put(xprt);
  			return ERR_PTR(-ENOMEM);
  		}
  		if (xprt->bc_xprt) {
  			xprt_switch_get(xps);
  			xprt->bc_xprt->xpt_bc_xps = xps;
  		}
1208fd569   J. Bruce Fields   SUNRPC: fix xprt ...
461
  	}
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
462
  	clnt = rpc_new_client(args, xps, xprt, NULL);
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
  	if (IS_ERR(clnt))
  		return clnt;
  
  	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
  		int err = rpc_ping(clnt);
  		if (err != 0) {
  			rpc_shutdown_client(clnt);
  			return ERR_PTR(err);
  		}
  	}
  
  	clnt->cl_softrtry = 1;
  	if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
  		clnt->cl_softrtry = 0;
  
  	if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
  		clnt->cl_autobind = 1;
2aca5b869   Trond Myklebust   SUNRPC: Add missi...
480
481
  	if (args->flags & RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT)
  		clnt->cl_noretranstimeo = 1;
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
482
483
484
485
486
487
488
  	if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
  		clnt->cl_discrtry = 1;
  	if (!(args->flags & RPC_CLNT_CREATE_QUIET))
  		clnt->cl_chatty = 1;
  
  	return clnt;
  }
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
489

2c53040f0   Ben Hutchings   net: Fix (nearly-...
490
  /**
c2866763b   Chuck Lever   SUNRPC: use socka...
491
492
493
494
495
496
497
498
499
500
501
502
   * rpc_create - create an RPC client and transport with one call
   * @args: rpc_clnt create argument structure
   *
   * Creates and initializes an RPC transport and an RPC client.
   *
   * It can ping the server in order to determine if it is up, and to see if
   * it supports this program and version.  RPC_CLNT_CREATE_NOPING disables
   * this behavior so asynchronous tasks can also use rpc_create.
   */
  struct rpc_clnt *rpc_create(struct rpc_create_args *args)
  {
  	struct rpc_xprt *xprt;
3c341b0b9   \"Talpey, Thomas\   SUNRPC: rename th...
503
  	struct xprt_create xprtargs = {
9a23e332e   Pavel Emelyanov   sunrpc: Add net t...
504
  		.net = args->net,
4fa016eb2   \"Talpey, Thomas\   NFS/SUNRPC: suppo...
505
  		.ident = args->protocol,
d3bc9a1de   Frank van Maarseveen   SUNRPC client: ad...
506
  		.srcaddr = args->saddress,
96802a095   Frank van Maarseveen   SUNRPC: cleanup t...
507
508
  		.dstaddr = args->address,
  		.addrlen = args->addrsize,
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
509
  		.servername = args->servername,
f300baba5   Alexandros Batsakis   nfsd41: sunrpc: a...
510
  		.bc_xprt = args->bc_xprt,
96802a095   Frank van Maarseveen   SUNRPC: cleanup t...
511
  	};
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
512
  	char servername[48];
c2866763b   Chuck Lever   SUNRPC: use socka...
513

d50039ea5   J. Bruce Fields   nfsd4/rpc: move b...
514
  	if (args->bc_xprt) {
16590a228   Chuck Lever   SUNRPC: Silence W...
515
  		WARN_ON_ONCE(!(args->protocol & XPRT_TRANSPORT_BC));
d50039ea5   J. Bruce Fields   nfsd4/rpc: move b...
516
517
518
519
520
521
  		xprt = args->bc_xprt->xpt_bc_xprt;
  		if (xprt) {
  			xprt_get(xprt);
  			return rpc_create_xprt(args, xprt);
  		}
  	}
b7993cebb   Trond Myklebust   SUNRPC: Allow rpc...
522
523
  	if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
  		xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
33d90ac05   J. Bruce Fields   SUNRPC: allow dis...
524
525
  	if (args->flags & RPC_CLNT_CREATE_NO_IDLE_TIMEOUT)
  		xprtargs.flags |= XPRT_CREATE_NO_IDLE_TIMEOUT;
c2866763b   Chuck Lever   SUNRPC: use socka...
526
  	/*
43780b87f   Chuck Lever   SUNRPC: Add a con...
527
528
529
  	 * If the caller chooses not to specify a hostname, whip
  	 * up a string representation of the passed-in address.
  	 */
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
530
  	if (xprtargs.servername == NULL) {
176e21ee2   Chuck Lever   SUNRPC: Support f...
531
532
  		struct sockaddr_un *sun =
  				(struct sockaddr_un *)args->address;
da09eb930   Chuck Lever   SUNRPC: Clean up ...
533
534
535
536
  		struct sockaddr_in *sin =
  				(struct sockaddr_in *)args->address;
  		struct sockaddr_in6 *sin6 =
  				(struct sockaddr_in6 *)args->address;
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
537
538
  		servername[0] = '\0';
  		switch (args->address->sa_family) {
176e21ee2   Chuck Lever   SUNRPC: Support f...
539
540
541
542
  		case AF_LOCAL:
  			snprintf(servername, sizeof(servername), "%s",
  				 sun->sun_path);
  			break;
da09eb930   Chuck Lever   SUNRPC: Clean up ...
543
  		case AF_INET:
21454aaad   Harvey Harrison   net: replace NIPQ...
544
545
  			snprintf(servername, sizeof(servername), "%pI4",
  				 &sin->sin_addr.s_addr);
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
546
  			break;
da09eb930   Chuck Lever   SUNRPC: Clean up ...
547
  		case AF_INET6:
5b095d989   Harvey Harrison   net: replace %p6 ...
548
  			snprintf(servername, sizeof(servername), "%pI6",
da09eb930   Chuck Lever   SUNRPC: Clean up ...
549
  				 &sin6->sin6_addr);
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
550
  			break;
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
551
552
553
554
555
  		default:
  			/* caller wants default server name, but
  			 * address family isn't recognized. */
  			return ERR_PTR(-EINVAL);
  		}
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
556
  		xprtargs.servername = servername;
43780b87f   Chuck Lever   SUNRPC: Add a con...
557
  	}
510deb0d7   Chuck Lever   SUNRPC: rpc_creat...
558
559
560
  	xprt = xprt_create_transport(&xprtargs);
  	if (IS_ERR(xprt))
  		return (struct rpc_clnt *)xprt;
43780b87f   Chuck Lever   SUNRPC: Add a con...
561
  	/*
c2866763b   Chuck Lever   SUNRPC: use socka...
562
563
564
565
566
567
568
569
  	 * By default, kernel RPC client connects from a reserved port.
  	 * CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
  	 * but it is always enabled for rpciod, which handles the connect
  	 * operation.
  	 */
  	xprt->resvport = 1;
  	if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
  		xprt->resvport = 0;
83ddfebdd   Kinglong Mee   SUNRPC: New helpe...
570
  	return rpc_create_xprt(args, xprt);
c2866763b   Chuck Lever   SUNRPC: use socka...
571
  }
b86acd501   Chuck Lever   SUNRPC: export ne...
572
  EXPORT_SYMBOL_GPL(rpc_create);
c2866763b   Chuck Lever   SUNRPC: use socka...
573

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
  /*
   * This function clones the RPC client structure. It allows us to share the
   * same transport while varying parameters such as the authentication
   * flavour.
   */
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
579
580
  static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
  					   struct rpc_clnt *clnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581
  {
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
582
  	struct rpc_xprt_switch *xps;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
583
  	struct rpc_xprt *xprt;
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
584
585
  	struct rpc_clnt *new;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586

1b63a7518   Chuck Lever   SUNRPC: Refactor ...
587
  	err = -ENOMEM;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
588
589
  	rcu_read_lock();
  	xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
590
  	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
591
  	rcu_read_unlock();
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
592
593
594
  	if (xprt == NULL || xps == NULL) {
  		xprt_put(xprt);
  		xprt_switch_put(xps);
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
595
  		goto out_err;
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
596
  	}
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
597
  	args->servername = xprt->servername;
03a9a42a1   Trond Myklebust   SUNRPC: NULL utsn...
598
  	args->nodename = clnt->cl_nodename;
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
599

ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
600
  	new = rpc_new_client(args, xps, xprt, clnt);
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
601
602
  	if (IS_ERR(new)) {
  		err = PTR_ERR(new);
a58e0be6f   Chuck Lever   SUNRPC: Remove ex...
603
  		goto out_err;
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
604
  	}
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
605
606
607
  	/* Turn off autobind on clones */
  	new->cl_autobind = 0;
  	new->cl_softrtry = clnt->cl_softrtry;
2aca5b869   Trond Myklebust   SUNRPC: Add missi...
608
  	new->cl_noretranstimeo = clnt->cl_noretranstimeo;
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
609
610
  	new->cl_discrtry = clnt->cl_discrtry;
  	new->cl_chatty = clnt->cl_chatty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  	return new;
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
612

1b63a7518   Chuck Lever   SUNRPC: Refactor ...
613
  out_err:
0dc47877a   Harvey Harrison   net: replace rema...
614
615
  	dprintk("RPC:       %s: returned error %d
  ", __func__, err);
3e32a5d99   Trond Myklebust   SUNRPC: Give clon...
616
  	return ERR_PTR(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  }
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  
  /**
   * rpc_clone_client - Clone an RPC client structure
   *
   * @clnt: RPC client whose parameters are copied
   *
   * Returns a fresh RPC client or an ERR_PTR.
   */
  struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
  {
  	struct rpc_create_args args = {
  		.program	= clnt->cl_program,
  		.prognumber	= clnt->cl_prog,
  		.version	= clnt->cl_vers,
  		.authflavor	= clnt->cl_auth->au_flavor,
1b63a7518   Chuck Lever   SUNRPC: Refactor ...
633
634
635
  	};
  	return __rpc_clone_client(&args, clnt);
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
636
  EXPORT_SYMBOL_GPL(rpc_clone_client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637

ba9b584c1   Chuck Lever   SUNRPC: Introduce...
638
639
640
641
  /**
   * rpc_clone_client_set_auth - Clone an RPC client structure and set its auth
   *
   * @clnt: RPC client whose parameters are copied
7144bca68   Randy Dunlap   nfs: fix sunrpc/c...
642
   * @flavor: security flavor for new client
ba9b584c1   Chuck Lever   SUNRPC: Introduce...
643
644
645
646
647
648
649
650
651
652
653
   *
   * Returns a fresh RPC client or an ERR_PTR.
   */
  struct rpc_clnt *
  rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
  {
  	struct rpc_create_args args = {
  		.program	= clnt->cl_program,
  		.prognumber	= clnt->cl_prog,
  		.version	= clnt->cl_vers,
  		.authflavor	= flavor,
ba9b584c1   Chuck Lever   SUNRPC: Introduce...
654
655
656
657
  	};
  	return __rpc_clone_client(&args, clnt);
  }
  EXPORT_SYMBOL_GPL(rpc_clone_client_set_auth);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
  /**
   * rpc_switch_client_transport: switch the RPC transport on the fly
   * @clnt: pointer to a struct rpc_clnt
   * @args: pointer to the new transport arguments
   * @timeout: pointer to the new timeout parameters
   *
   * This function allows the caller to switch the RPC transport for the
   * rpc_clnt structure 'clnt' to allow it to connect to a mirrored NFS
   * server, for instance.  It assumes that the caller has ensured that
   * there are no active RPC tasks by using some form of locking.
   *
   * Returns zero if "clnt" is now using the new xprt.  Otherwise a
   * negative errno is returned, and "clnt" continues to use the old
   * xprt.
   */
  int rpc_switch_client_transport(struct rpc_clnt *clnt,
  		struct xprt_create *args,
  		const struct rpc_timeout *timeout)
  {
  	const struct rpc_timeout *old_timeo;
  	rpc_authflavor_t pseudoflavor;
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
679
  	struct rpc_xprt_switch *xps, *oldxps;
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
680
681
682
683
684
685
686
687
688
689
690
  	struct rpc_xprt *xprt, *old;
  	struct rpc_clnt *parent;
  	int err;
  
  	xprt = xprt_create_transport(args);
  	if (IS_ERR(xprt)) {
  		dprintk("RPC:       failed to create new xprt for clnt %p
  ",
  			clnt);
  		return PTR_ERR(xprt);
  	}
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
691
692
693
694
695
  	xps = xprt_switch_alloc(xprt, GFP_KERNEL);
  	if (xps == NULL) {
  		xprt_put(xprt);
  		return -ENOMEM;
  	}
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
696
697
698
699
  	pseudoflavor = clnt->cl_auth->au_flavor;
  
  	old_timeo = clnt->cl_timeout;
  	old = rpc_clnt_set_transport(clnt, xprt, timeout);
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
700
  	oldxps = xprt_iter_xchg_switch(&clnt->cl_xpi, xps);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
701
702
703
  
  	rpc_unregister_client(clnt);
  	__rpc_clnt_remove_pipedir(clnt);
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
704
  	rpc_clnt_debugfs_unregister(clnt);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  
  	/*
  	 * A new transport was created.  "clnt" therefore
  	 * becomes the root of a new cl_parent tree.  clnt's
  	 * children, if it has any, still point to the old xprt.
  	 */
  	parent = clnt->cl_parent;
  	clnt->cl_parent = clnt;
  
  	/*
  	 * The old rpc_auth cache cannot be re-used.  GSS
  	 * contexts in particular are between a single
  	 * client and server.
  	 */
  	err = rpc_client_register(clnt, pseudoflavor, NULL);
  	if (err)
  		goto out_revert;
  
  	synchronize_rcu();
  	if (parent != clnt)
  		rpc_release_client(parent);
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
726
  	xprt_switch_put(oldxps);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
727
728
729
730
731
732
  	xprt_put(old);
  	dprintk("RPC:       replaced xprt for clnt %p
  ", clnt);
  	return 0;
  
  out_revert:
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
733
  	xps = xprt_iter_xchg_switch(&clnt->cl_xpi, oldxps);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
734
735
736
  	rpc_clnt_set_transport(clnt, old, old_timeo);
  	clnt->cl_parent = parent;
  	rpc_client_register(clnt, pseudoflavor, NULL);
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
737
  	xprt_switch_put(xps);
40b00b6b1   Trond Myklebust   SUNRPC: Add a hel...
738
739
740
741
742
743
  	xprt_put(xprt);
  	dprintk("RPC:       failed to switch xprt for clnt %p
  ", clnt);
  	return err;
  }
  EXPORT_SYMBOL_GPL(rpc_switch_client_transport);
3227886c6   Trond Myklebust   SUNRPC: Add a hel...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
  static
  int rpc_clnt_xprt_iter_init(struct rpc_clnt *clnt, struct rpc_xprt_iter *xpi)
  {
  	struct rpc_xprt_switch *xps;
  
  	rcu_read_lock();
  	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
  	rcu_read_unlock();
  	if (xps == NULL)
  		return -EAGAIN;
  	xprt_iter_init_listall(xpi, xps);
  	xprt_switch_put(xps);
  	return 0;
  }
  
  /**
   * rpc_clnt_iterate_for_each_xprt - Apply a function to all transports
   * @clnt: pointer to client
   * @fn: function to apply
   * @data: void pointer to function data
   *
   * Iterates through the list of RPC transports currently attached to the
   * client and applies the function fn(clnt, xprt, data).
   *
   * On error, the iteration stops, and the function returns the error value.
   */
  int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt,
  		int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *),
  		void *data)
  {
  	struct rpc_xprt_iter xpi;
  	int ret;
  
  	ret = rpc_clnt_xprt_iter_init(clnt, &xpi);
  	if (ret)
  		return ret;
  	for (;;) {
  		struct rpc_xprt *xprt = xprt_iter_get_next(&xpi);
  
  		if (!xprt)
  			break;
  		ret = fn(clnt, xprt, data);
  		xprt_put(xprt);
  		if (ret < 0)
  			break;
  	}
  	xprt_iter_destroy(&xpi);
  	return ret;
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_iterate_for_each_xprt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  /*
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
   * Kill all tasks for the given client.
   * XXX: kill their descendants as well?
   */
  void rpc_killall_tasks(struct rpc_clnt *clnt)
  {
  	struct rpc_task	*rovr;
  
  
  	if (list_empty(&clnt->cl_tasks))
  		return;
  	dprintk("RPC:       killing all tasks for client %p
  ", clnt);
  	/*
  	 * Spin lock all_tasks to prevent changes...
  	 */
  	spin_lock(&clnt->cl_lock);
  	list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) {
  		if (!RPC_IS_ACTIVATED(rovr))
  			continue;
  		if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
  			rovr->tk_flags |= RPC_TASK_KILLED;
  			rpc_exit(rovr, -EIO);
8e26de238   Stanislav Kinsbursky   RPC: killing RPC ...
817
818
819
  			if (RPC_IS_QUEUED(rovr))
  				rpc_wake_up_queued_task(rovr->tk_waitqueue,
  							rovr);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
820
821
822
823
824
825
826
  		}
  	}
  	spin_unlock(&clnt->cl_lock);
  }
  EXPORT_SYMBOL_GPL(rpc_killall_tasks);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
   * Properly shut down an RPC client, terminating all outstanding
90c5755ff   Trond Myklebust   SUNRPC: Kill rpc_...
828
   * requests.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
   */
4c402b409   Trond Myklebust   SUNRPC: Remove rp...
830
  void rpc_shutdown_client(struct rpc_clnt *clnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  {
168e4b39d   Weston Andros Adamson   SUNRPC: add WARN_...
832
  	might_sleep();
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
833
834
  	dprintk_rcu("RPC:       shutting down %s client for %s
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
835
  			clnt->cl_program->name,
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
836
  			rcu_dereference(clnt->cl_xprt)->servername);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837

34f52e359   Trond Myklebust   SUNRPC: Convert r...
838
  	while (!list_empty(&clnt->cl_tasks)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  		rpc_killall_tasks(clnt);
532347e2b   Ingo Molnar   [PATCH] nfs: slee...
840
  		wait_event_timeout(destroy_wait,
34f52e359   Trond Myklebust   SUNRPC: Convert r...
841
  			list_empty(&clnt->cl_tasks), 1*HZ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  	}
4c402b409   Trond Myklebust   SUNRPC: Remove rp...
843
  	rpc_release_client(clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
845
  EXPORT_SYMBOL_GPL(rpc_shutdown_client);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
  
  /*
34f52e359   Trond Myklebust   SUNRPC: Convert r...
848
   * Free an RPC client
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
   */
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
850
  static struct rpc_clnt *
006abe887   Trond Myklebust   SUNRPC: Fix a rac...
851
  rpc_free_client(struct rpc_clnt *clnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  {
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
853
  	struct rpc_clnt *parent = NULL;
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
854
855
  	dprintk_rcu("RPC:       destroying %s client for %s
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
856
  			clnt->cl_program->name,
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
857
  			rcu_dereference(clnt->cl_xprt)->servername);
6eac7d3f4   Trond Myklebust   SUNRPC: constify ...
858
  	if (clnt->cl_parent != clnt)
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
859
  		parent = clnt->cl_parent;
b4b9d2ccf   Jeff Layton   sunrpc: add debug...
860
  	rpc_clnt_debugfs_unregister(clnt);
f5131257f   Stanislav Kinsbursky   SUNRPC: remove RP...
861
  	rpc_clnt_remove_pipedir(clnt);
adb6fa7ff   Stanislav Kinsbursky   SUNRPC: fix races...
862
  	rpc_unregister_client(clnt);
11c556b3d   Chuck Lever   SUNRPC: provide a...
863
864
  	rpc_free_iostats(clnt->cl_metrics);
  	clnt->cl_metrics = NULL;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
865
  	xprt_put(rcu_dereference_raw(clnt->cl_xprt));
ad01b2c68   Trond Myklebust   SUNRPC: Make rpc_...
866
  	xprt_iter_destroy(&clnt->cl_xpi);
4ada539ed   Trond Myklebust   SUNRPC: Make crea...
867
  	rpciod_down();
2f048db46   Trond Myklebust   SUNRPC: Add an id...
868
  	rpc_free_clid(clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  	kfree(clnt);
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
870
  	return parent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
  }
  
  /*
1dd17ec69   Trond Myklebust   SUNRPC: Allow rpc...
874
875
   * Free an RPC client
   */
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
876
  static struct rpc_clnt * 
006abe887   Trond Myklebust   SUNRPC: Fix a rac...
877
  rpc_free_auth(struct rpc_clnt *clnt)
1dd17ec69   Trond Myklebust   SUNRPC: Allow rpc...
878
  {
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
879
880
  	if (clnt->cl_auth == NULL)
  		return rpc_free_client(clnt);
1dd17ec69   Trond Myklebust   SUNRPC: Allow rpc...
881
882
883
884
885
886
  
  	/*
  	 * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
  	 *       release remaining GSS contexts. This mechanism ensures
  	 *       that it can do so safely.
  	 */
006abe887   Trond Myklebust   SUNRPC: Fix a rac...
887
  	atomic_inc(&clnt->cl_count);
1dd17ec69   Trond Myklebust   SUNRPC: Allow rpc...
888
889
  	rpcauth_release(clnt->cl_auth);
  	clnt->cl_auth = NULL;
006abe887   Trond Myklebust   SUNRPC: Fix a rac...
890
  	if (atomic_dec_and_test(&clnt->cl_count))
d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
891
892
  		return rpc_free_client(clnt);
  	return NULL;
1dd17ec69   Trond Myklebust   SUNRPC: Allow rpc...
893
894
895
  }
  
  /*
34f52e359   Trond Myklebust   SUNRPC: Convert r...
896
   * Release reference to the RPC client
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
   */
  void
  rpc_release_client(struct rpc_clnt *clnt)
  {
34f52e359   Trond Myklebust   SUNRPC: Convert r...
901
902
  	dprintk("RPC:       rpc_release_client(%p)
  ", clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903

d07ba8422   Trond Myklebust   SUNRPC: Avoid dee...
904
905
906
907
908
909
910
  	do {
  		if (list_empty(&clnt->cl_tasks))
  			wake_up(&destroy_wait);
  		if (!atomic_dec_and_test(&clnt->cl_count))
  			break;
  		clnt = rpc_free_auth(clnt);
  	} while (clnt != NULL);
34f52e359   Trond Myklebust   SUNRPC: Convert r...
911
  }
1d658336b   Simo Sorce   SUNRPC: Add RPC b...
912
  EXPORT_SYMBOL_GPL(rpc_release_client);
34f52e359   Trond Myklebust   SUNRPC: Convert r...
913

007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
914
915
  /**
   * rpc_bind_new_program - bind a new RPC program to an existing client
65b6e42cd   Randy Dunlap   docbook: sunrpc f...
916
917
918
   * @old: old rpc_client
   * @program: rpc program to set
   * @vers: rpc program version
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
919
920
921
922
923
924
   *
   * Clones the rpc client and sets up a new RPC program. This is mainly
   * of use for enabling different RPC programs to share the same transport.
   * The Sun NFSv2/v3 ACL protocol can do this.
   */
  struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
a613fa168   Trond Myklebust   SUNRPC: constify ...
925
  				      const struct rpc_program *program,
89eb21c35   Chuck Lever   SUNRPC: fix a sig...
926
  				      u32 vers)
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
927
  {
f994c43d1   Trond Myklebust   SUNRPC: Clean up ...
928
929
930
931
932
  	struct rpc_create_args args = {
  		.program	= program,
  		.prognumber	= program->number,
  		.version	= vers,
  		.authflavor	= old->cl_auth->au_flavor,
f994c43d1   Trond Myklebust   SUNRPC: Clean up ...
933
  	};
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
934
  	struct rpc_clnt *clnt;
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
935
  	int err;
f994c43d1   Trond Myklebust   SUNRPC: Clean up ...
936
  	clnt = __rpc_clone_client(&args, old);
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
937
938
  	if (IS_ERR(clnt))
  		goto out;
caabea8a5   Chuck Lever   SUNRPC: Use soft ...
939
  	err = rpc_ping(clnt);
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
940
941
942
943
  	if (err != 0) {
  		rpc_shutdown_client(clnt);
  		clnt = ERR_PTR(err);
  	}
cca5172a7   YOSHIFUJI Hideaki   [NET] SUNRPC: Fix...
944
  out:
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
945
946
  	return clnt;
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
947
  EXPORT_SYMBOL_GPL(rpc_bind_new_program);
007e251f2   Andreas Gruenbacher   [PATCH] RPC: Allo...
948

58f9612c6   Trond Myklebust   SUNRPC: Move rema...
949
950
951
  void rpc_task_release_client(struct rpc_task *task)
  {
  	struct rpc_clnt *clnt = task->tk_client;
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
952
  	struct rpc_xprt *xprt = task->tk_xprt;
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
953
954
955
956
957
958
959
960
961
962
  
  	if (clnt != NULL) {
  		/* Remove from client task list */
  		spin_lock(&clnt->cl_lock);
  		list_del(&task->tk_task);
  		spin_unlock(&clnt->cl_lock);
  		task->tk_client = NULL;
  
  		rpc_release_client(clnt);
  	}
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
963
964
965
966
967
968
  
  	if (xprt != NULL) {
  		task->tk_xprt = NULL;
  
  		xprt_put(xprt);
  	}
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
969
970
971
972
973
  }
  
  static
  void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
  {
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
974

58f9612c6   Trond Myklebust   SUNRPC: Move rema...
975
  	if (clnt != NULL) {
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
976
977
  		if (task->tk_xprt == NULL)
  			task->tk_xprt = xprt_iter_get_next(&clnt->cl_xpi);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
978
  		task->tk_client = clnt;
006abe887   Trond Myklebust   SUNRPC: Fix a rac...
979
  		atomic_inc(&clnt->cl_count);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
980
981
  		if (clnt->cl_softrtry)
  			task->tk_flags |= RPC_TASK_SOFT;
8a19a0b6c   Trond Myklebust   SUNRPC: Add RPC t...
982
983
  		if (clnt->cl_noretranstimeo)
  			task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
984
985
  		if (atomic_read(&clnt->cl_swapper))
  			task->tk_flags |= RPC_TASK_SWAPPER;
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
986
987
988
989
990
991
992
993
994
995
996
997
998
999
  		/* Add to the client's list of all tasks */
  		spin_lock(&clnt->cl_lock);
  		list_add_tail(&task->tk_task, &clnt->cl_tasks);
  		spin_unlock(&clnt->cl_lock);
  	}
  }
  
  static void
  rpc_task_set_rpc_message(struct rpc_task *task, const struct rpc_message *msg)
  {
  	if (msg != NULL) {
  		task->tk_msg.rpc_proc = msg->rpc_proc;
  		task->tk_msg.rpc_argp = msg->rpc_argp;
  		task->tk_msg.rpc_resp = msg->rpc_resp;
a17c2153d   Trond Myklebust   SUNRPC: Move the ...
1000
1001
  		if (msg->rpc_cred != NULL)
  			task->tk_msg.rpc_cred = get_rpccred(msg->rpc_cred);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
1002
1003
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
1007
  /*
   * Default callback for async RPC calls
   */
  static void
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1008
  rpc_default_callback(struct rpc_task *task, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1009
1010
  {
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1011
1012
1013
  static const struct rpc_call_ops rpc_default_ops = {
  	.rpc_call_done = rpc_default_callback,
  };
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1014
1015
1016
1017
1018
  /**
   * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
   * @task_setup_data: pointer to task initialisation data
   */
  struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1019
  {
19445b99b   Trond Myklebust   SUNRPC: Cleanup -...
1020
  	struct rpc_task *task;
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1021

84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1022
  	task = rpc_new_task(task_setup_data);
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1023

58f9612c6   Trond Myklebust   SUNRPC: Move rema...
1024
1025
  	rpc_task_set_client(task, task_setup_data->rpc_client);
  	rpc_task_set_rpc_message(task, task_setup_data->rpc_message);
58f9612c6   Trond Myklebust   SUNRPC: Move rema...
1026
1027
  	if (task->tk_action == NULL)
  		rpc_call_start(task);
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1028
1029
  	atomic_inc(&task->tk_count);
  	rpc_execute(task);
19445b99b   Trond Myklebust   SUNRPC: Cleanup -...
1030
  	return task;
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1031
  }
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1032
  EXPORT_SYMBOL_GPL(rpc_run_task);
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1033
1034
1035
1036
1037
1038
  
  /**
   * rpc_call_sync - Perform a synchronous RPC call
   * @clnt: pointer to RPC client
   * @msg: RPC call parameters
   * @flags: RPC call flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
   */
cbc200592   Trond Myklebust   SUNRPC: Declare a...
1040
  int rpc_call_sync(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
  {
  	struct rpc_task	*task;
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1043
1044
1045
1046
1047
1048
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clnt,
  		.rpc_message = msg,
  		.callback_ops = &rpc_default_ops,
  		.flags = flags,
  	};
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1049
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050

50d2bdb19   Weston Andros Adamson   SUNRPC: remove BU...
1051
1052
1053
1054
1055
1056
  	WARN_ON_ONCE(flags & RPC_TASK_ASYNC);
  	if (flags & RPC_TASK_ASYNC) {
  		rpc_release_calldata(task_setup_data.callback_ops,
  			task_setup_data.callback_data);
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057

c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1058
  	task = rpc_run_task(&task_setup_data);
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1059
1060
  	if (IS_ERR(task))
  		return PTR_ERR(task);
e60859ac0   Trond Myklebust   SUNRPC: rpc_execu...
1061
  	status = task->tk_status;
bde8f00ce   Trond Myklebust   [PATCH] NFS: Fix ...
1062
  	rpc_put_task(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
1064
  	return status;
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
1065
  EXPORT_SYMBOL_GPL(rpc_call_sync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066

6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1067
1068
1069
1070
1071
  /**
   * rpc_call_async - Perform an asynchronous RPC call
   * @clnt: pointer to RPC client
   * @msg: RPC call parameters
   * @flags: RPC call flags
65b6e42cd   Randy Dunlap   docbook: sunrpc f...
1072
   * @tk_ops: RPC call ops
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1073
   * @data: user call data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
   */
  int
cbc200592   Trond Myklebust   SUNRPC: Declare a...
1076
  rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1077
  	       const struct rpc_call_ops *tk_ops, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
1079
  {
  	struct rpc_task	*task;
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
1080
1081
1082
1083
1084
1085
1086
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clnt,
  		.rpc_message = msg,
  		.callback_ops = tk_ops,
  		.callback_data = data,
  		.flags = flags|RPC_TASK_ASYNC,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087

c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1088
  	task = rpc_run_task(&task_setup_data);
6e5b70e9d   Trond Myklebust   SUNRPC: clean up ...
1089
1090
1091
1092
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	rpc_put_task(task);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
1094
  EXPORT_SYMBOL_GPL(rpc_call_async);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095

9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1096
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1097
1098
1099
  /**
   * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run
   * rpc_execute against it
7a73fdde3   Jaswinder Singh Rajput   net: fix htmldocs...
1100
   * @req: RPC request
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1101
   */
0f4197916   Trond Myklebust   SUNRPC: Remove un...
1102
  struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1103
1104
1105
1106
  {
  	struct rpc_task *task;
  	struct xdr_buf *xbufp = &req->rq_snd_buf;
  	struct rpc_task_setup task_setup_data = {
0f4197916   Trond Myklebust   SUNRPC: Remove un...
1107
  		.callback_ops = &rpc_default_ops,
3832591e6   Trond Myklebust   SUNRPC: Handle co...
1108
  		.flags = RPC_TASK_SOFTCONN,
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1109
1110
1111
1112
1113
1114
1115
1116
  	};
  
  	dprintk("RPC: rpc_run_bc_task req= %p
  ", req);
  	/*
  	 * Create an rpc_task to send the data
  	 */
  	task = rpc_new_task(&task_setup_data);
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  	task->tk_rqstp = req;
  
  	/*
  	 * Set up the xdr_buf length.
  	 * This also indicates that the buffer is XDR encoded already.
  	 */
  	xbufp->len = xbufp->head[0].iov_len + xbufp->page_len +
  			xbufp->tail[0].iov_len;
  
  	task->tk_action = call_bc_transmit;
  	atomic_inc(&task->tk_count);
9a6478f6c   Weston Andros Adamson   SUNRPC: remove BU...
1128
  	WARN_ON_ONCE(atomic_read(&task->tk_count) != 2);
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1129
  	rpc_execute(task);
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1130
1131
1132
1133
  	dprintk("RPC: rpc_run_bc_task: task= %p
  ", task);
  	return task;
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
1134
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1135

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  void
77de2c590   Trond Myklebust   SUNRPC: Add a hel...
1137
1138
1139
1140
1141
  rpc_call_start(struct rpc_task *task)
  {
  	task->tk_action = call_start;
  }
  EXPORT_SYMBOL_GPL(rpc_call_start);
ed39440a2   Chuck Lever   SUNRPC: create AP...
1142
1143
1144
1145
  /**
   * rpc_peeraddr - extract remote peer address from clnt's xprt
   * @clnt: RPC client structure
   * @buf: target buffer
65b6e42cd   Randy Dunlap   docbook: sunrpc f...
1146
   * @bufsize: length of target buffer
ed39440a2   Chuck Lever   SUNRPC: create AP...
1147
1148
1149
1150
1151
1152
   *
   * Returns the number of bytes that are actually in the stored address.
   */
  size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
  {
  	size_t bytes;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1153
1154
1155
1156
  	struct rpc_xprt *xprt;
  
  	rcu_read_lock();
  	xprt = rcu_dereference(clnt->cl_xprt);
ed39440a2   Chuck Lever   SUNRPC: create AP...
1157

2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1158
  	bytes = xprt->addrlen;
ed39440a2   Chuck Lever   SUNRPC: create AP...
1159
1160
  	if (bytes > bufsize)
  		bytes = bufsize;
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1161
1162
1163
1164
  	memcpy(buf, &xprt->addr, bytes);
  	rcu_read_unlock();
  
  	return bytes;
ed39440a2   Chuck Lever   SUNRPC: create AP...
1165
  }
b86acd501   Chuck Lever   SUNRPC: export ne...
1166
  EXPORT_SYMBOL_GPL(rpc_peeraddr);
ed39440a2   Chuck Lever   SUNRPC: create AP...
1167

f425eba43   Chuck Lever   SUNRPC: Create AP...
1168
1169
1170
1171
1172
  /**
   * rpc_peeraddr2str - return remote peer address in printable format
   * @clnt: RPC client structure
   * @format: address format
   *
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1173
1174
1175
   * NB: the lifetime of the memory referenced by the returned pointer is
   * the same as the rpc_xprt itself.  As long as the caller uses this
   * pointer, it must hold the RCU read lock.
f425eba43   Chuck Lever   SUNRPC: Create AP...
1176
   */
b454ae906   Chuck Lever   SUNRPC: fewer con...
1177
1178
  const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
  			     enum rpc_display_format_t format)
f425eba43   Chuck Lever   SUNRPC: Create AP...
1179
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1180
1181
1182
  	struct rpc_xprt *xprt;
  
  	xprt = rcu_dereference(clnt->cl_xprt);
7559c7a28   Chuck Lever   SUNRPC: Make addr...
1183
1184
1185
1186
1187
  
  	if (xprt->address_strings[format] != NULL)
  		return xprt->address_strings[format];
  	else
  		return "unprintable";
f425eba43   Chuck Lever   SUNRPC: Create AP...
1188
  }
b86acd501   Chuck Lever   SUNRPC: export ne...
1189
  EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
f425eba43   Chuck Lever   SUNRPC: Create AP...
1190

2e738fdce   Chuck Lever   SUNRPC: Add API t...
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
  static const struct sockaddr_in rpc_inaddr_loopback = {
  	.sin_family		= AF_INET,
  	.sin_addr.s_addr	= htonl(INADDR_ANY),
  };
  
  static const struct sockaddr_in6 rpc_in6addr_loopback = {
  	.sin6_family		= AF_INET6,
  	.sin6_addr		= IN6ADDR_ANY_INIT,
  };
  
  /*
   * Try a getsockname() on a connected datagram socket.  Using a
   * connected datagram socket prevents leaving a socket in TIME_WAIT.
   * This conserves the ephemeral port number space.
   *
   * Returns zero and fills in "buf" if successful; otherwise, a
   * negative errno is returned.
   */
  static int rpc_sockname(struct net *net, struct sockaddr *sap, size_t salen,
  			struct sockaddr *buf, int buflen)
  {
  	struct socket *sock;
  	int err;
  
  	err = __sock_create(net, sap->sa_family,
  				SOCK_DGRAM, IPPROTO_UDP, &sock, 1);
  	if (err < 0) {
  		dprintk("RPC:       can't create UDP socket (%d)
  ", err);
  		goto out;
  	}
  
  	switch (sap->sa_family) {
  	case AF_INET:
  		err = kernel_bind(sock,
  				(struct sockaddr *)&rpc_inaddr_loopback,
  				sizeof(rpc_inaddr_loopback));
  		break;
  	case AF_INET6:
  		err = kernel_bind(sock,
  				(struct sockaddr *)&rpc_in6addr_loopback,
  				sizeof(rpc_in6addr_loopback));
  		break;
  	default:
  		err = -EAFNOSUPPORT;
  		goto out;
  	}
  	if (err < 0) {
  		dprintk("RPC:       can't bind UDP socket (%d)
  ", err);
  		goto out_release;
  	}
  
  	err = kernel_connect(sock, sap, salen, 0);
  	if (err < 0) {
  		dprintk("RPC:       can't connect UDP socket (%d)
  ", err);
  		goto out_release;
  	}
  
  	err = kernel_getsockname(sock, buf, &buflen);
  	if (err < 0) {
  		dprintk("RPC:       getsockname failed (%d)
  ", err);
  		goto out_release;
  	}
  
  	err = 0;
  	if (buf->sa_family == AF_INET6) {
  		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)buf;
  		sin6->sin6_scope_id = 0;
  	}
  	dprintk("RPC:       %s succeeded
  ", __func__);
  
  out_release:
  	sock_release(sock);
  out:
  	return err;
  }
  
  /*
   * Scraping a connected socket failed, so we don't have a useable
   * local address.  Fallback: generate an address that will prevent
   * the server from calling us back.
   *
   * Returns zero and fills in "buf" if successful; otherwise, a
   * negative errno is returned.
   */
  static int rpc_anyaddr(int family, struct sockaddr *buf, size_t buflen)
  {
  	switch (family) {
  	case AF_INET:
  		if (buflen < sizeof(rpc_inaddr_loopback))
  			return -EINVAL;
  		memcpy(buf, &rpc_inaddr_loopback,
  				sizeof(rpc_inaddr_loopback));
  		break;
  	case AF_INET6:
  		if (buflen < sizeof(rpc_in6addr_loopback))
  			return -EINVAL;
  		memcpy(buf, &rpc_in6addr_loopback,
  				sizeof(rpc_in6addr_loopback));
0b161e633   Trond Myklebust   SUNRPC: Fix a mis...
1294
  		break;
2e738fdce   Chuck Lever   SUNRPC: Add API t...
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
  	default:
  		dprintk("RPC:       %s: address family not supported
  ",
  			__func__);
  		return -EAFNOSUPPORT;
  	}
  	dprintk("RPC:       %s: succeeded
  ", __func__);
  	return 0;
  }
  
  /**
   * rpc_localaddr - discover local endpoint address for an RPC client
   * @clnt: RPC client structure
   * @buf: target buffer
   * @buflen: size of target buffer, in bytes
   *
   * Returns zero and fills in "buf" and "buflen" if successful;
   * otherwise, a negative errno is returned.
   *
   * This works even if the underlying transport is not currently connected,
   * or if the upper layer never previously provided a source address.
   *
   * The result of this function call is transient: multiple calls in
   * succession may give different results, depending on how local
   * networking configuration changes over time.
   */
  int rpc_localaddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t buflen)
  {
  	struct sockaddr_storage address;
  	struct sockaddr *sap = (struct sockaddr *)&address;
  	struct rpc_xprt *xprt;
  	struct net *net;
  	size_t salen;
  	int err;
  
  	rcu_read_lock();
  	xprt = rcu_dereference(clnt->cl_xprt);
  	salen = xprt->addrlen;
  	memcpy(sap, &xprt->addr, salen);
  	net = get_net(xprt->xprt_net);
  	rcu_read_unlock();
  
  	rpc_set_port(sap, 0);
  	err = rpc_sockname(net, sap, salen, buf, buflen);
  	put_net(net);
  	if (err != 0)
  		/* Couldn't discover local address, return ANYADDR */
  		return rpc_anyaddr(sap->sa_family, buf, buflen);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(rpc_localaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
1349
  void
  rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1350
1351
1352
1353
  	struct rpc_xprt *xprt;
  
  	rcu_read_lock();
  	xprt = rcu_dereference(clnt->cl_xprt);
470056c28   Chuck Lever   [PATCH] RPC: rati...
1354
1355
  	if (xprt->ops->set_buffer_size)
  		xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1356
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1357
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
1358
  EXPORT_SYMBOL_GPL(rpc_setbufsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1359

2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
  /**
   * rpc_protocol - Get transport protocol number for an RPC client
   * @clnt: RPC client to query
   *
   */
  int rpc_protocol(struct rpc_clnt *clnt)
  {
  	int protocol;
  
  	rcu_read_lock();
  	protocol = rcu_dereference(clnt->cl_xprt)->prot;
  	rcu_read_unlock();
  	return protocol;
  }
  EXPORT_SYMBOL_GPL(rpc_protocol);
  
  /**
   * rpc_net_ns - Get the network namespace for this RPC client
   * @clnt: RPC client to query
   *
   */
  struct net *rpc_net_ns(struct rpc_clnt *clnt)
  {
  	struct net *ret;
  
  	rcu_read_lock();
  	ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(rpc_net_ns);
  
  /**
   * rpc_max_payload - Get maximum payload size for a transport, in bytes
   * @clnt: RPC client to query
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
1396
1397
1398
1399
1400
1401
1402
   *
   * For stream transports, this is one RPC record fragment (see RFC
   * 1831), as we don't support multi-record requests yet.  For datagram
   * transports, this is the size of an IP packet minus the IP, UDP, and
   * RPC header sizes.
   */
  size_t rpc_max_payload(struct rpc_clnt *clnt)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1403
1404
1405
1406
1407
1408
  	size_t ret;
  
  	rcu_read_lock();
  	ret = rcu_dereference(clnt->cl_xprt)->max_payload;
  	rcu_read_unlock();
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  }
b86acd501   Chuck Lever   SUNRPC: export ne...
1410
  EXPORT_SYMBOL_GPL(rpc_max_payload);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411

35f5a422c   Chuck Lever   SUNRPC: new inter...
1412
  /**
6b26cc8c8   Chuck Lever   sunrpc: Advertise...
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
   * rpc_max_bc_payload - Get maximum backchannel payload size, in bytes
   * @clnt: RPC client to query
   */
  size_t rpc_max_bc_payload(struct rpc_clnt *clnt)
  {
  	struct rpc_xprt *xprt;
  	size_t ret;
  
  	rcu_read_lock();
  	xprt = rcu_dereference(clnt->cl_xprt);
  	ret = xprt->ops->bc_maxpayload(xprt);
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(rpc_max_bc_payload);
  
  /**
35f5a422c   Chuck Lever   SUNRPC: new inter...
1430
1431
1432
1433
1434
1435
   * rpc_force_rebind - force transport to check that remote port is unchanged
   * @clnt: client to rebind
   *
   */
  void rpc_force_rebind(struct rpc_clnt *clnt)
  {
2446ab607   Trond Myklebust   SUNRPC: Use RCU t...
1436
1437
1438
1439
1440
  	if (clnt->cl_autobind) {
  		rcu_read_lock();
  		xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
  		rcu_read_unlock();
  	}
35f5a422c   Chuck Lever   SUNRPC: new inter...
1441
  }
b86acd501   Chuck Lever   SUNRPC: export ne...
1442
  EXPORT_SYMBOL_GPL(rpc_force_rebind);
35f5a422c   Chuck Lever   SUNRPC: new inter...
1443

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1444
  /*
aae2006e9   Andy Adamson   nfs41: sunrpc: Ex...
1445
1446
1447
   * Restart an (async) RPC call from the call_prepare state.
   * Usually called from within the exit handler.
   */
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1448
  int
aae2006e9   Andy Adamson   nfs41: sunrpc: Ex...
1449
1450
1451
  rpc_restart_call_prepare(struct rpc_task *task)
  {
  	if (RPC_ASSASSINATED(task))
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1452
  		return 0;
d00c5d438   Trond Myklebust   NFS: Get rid of n...
1453
  	task->tk_action = call_start;
494314c41   Trond Myklebust   SUNRPC: rpc_resta...
1454
  	task->tk_status = 0;
d00c5d438   Trond Myklebust   NFS: Get rid of n...
1455
1456
  	if (task->tk_ops->rpc_call_prepare != NULL)
  		task->tk_action = rpc_prepare_task;
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1457
  	return 1;
aae2006e9   Andy Adamson   nfs41: sunrpc: Ex...
1458
1459
1460
1461
  }
  EXPORT_SYMBOL_GPL(rpc_restart_call_prepare);
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1462
1463
1464
   * Restart an (async) RPC call. Usually called from within the
   * exit handler.
   */
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1465
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
1467
1468
  rpc_restart_call(struct rpc_task *task)
  {
  	if (RPC_ASSASSINATED(task))
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1469
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
  	task->tk_action = call_start;
494314c41   Trond Myklebust   SUNRPC: rpc_resta...
1471
  	task->tk_status = 0;
f1f88fc7e   Trond Myklebust   SUNRPC: The funct...
1472
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
1474
  EXPORT_SYMBOL_GPL(rpc_restart_call);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1475

b4b9d2ccf   Jeff Layton   sunrpc: add debug...
1476
1477
  const char
  *rpc_proc_name(const struct rpc_task *task)
3748f1e44   Chuck Lever   SUNRPC: Add a fun...
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
  {
  	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
  
  	if (proc) {
  		if (proc->p_name)
  			return proc->p_name;
  		else
  			return "NULL";
  	} else
  		return "no proc";
  }
3748f1e44   Chuck Lever   SUNRPC: Add a fun...
1489

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  /*
   * 0.  Initial state
   *
   *     Other FSM states can be visited zero or more times, but
   *     this state is visited exactly once for each RPC.
   */
  static void
  call_start(struct rpc_task *task)
  {
  	struct rpc_clnt	*clnt = task->tk_client;
1c5876ddb   Christoph Hellwig   sunrpc: move p_co...
1500
  	int idx = task->tk_msg.rpc_proc->p_statidx;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501

c435da68b   Chuck Lever   sunrpc: Add rpc_r...
1502
  	trace_rpc_request(task);
3748f1e44   Chuck Lever   SUNRPC: Add a fun...
1503
1504
  	dprintk("RPC: %5u call_start %s%d proc %s (%s)
  ", task->tk_pid,
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
1505
  			clnt->cl_program->name, clnt->cl_vers,
3748f1e44   Chuck Lever   SUNRPC: Add a fun...
1506
  			rpc_proc_name(task),
46121cf7d   Chuck Lever   SUNRPC: fix print...
1507
  			(RPC_IS_ASYNC(task) ? "async" : "sync"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508

1c5876ddb   Christoph Hellwig   sunrpc: move p_co...
1509
1510
1511
  	/* Increment call count (version might not be valid for ping) */
  	if (clnt->cl_program->version[clnt->cl_vers])
  		clnt->cl_program->version[clnt->cl_vers]->counts[idx]++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
  	clnt->cl_stats->rpccnt++;
  	task->tk_action = call_reserve;
  }
  
  /*
   * 1.	Reserve an RPC call slot
   */
  static void
  call_reserve(struct rpc_task *task)
  {
46121cf7d   Chuck Lever   SUNRPC: fix print...
1522
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1524
1525
1526
1527
  	task->tk_status  = 0;
  	task->tk_action  = call_reserveresult;
  	xprt_reserve(task);
  }
ba60eb25f   Trond Myklebust   SUNRPC: Fix a liv...
1528
  static void call_retry_reserve(struct rpc_task *task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
1533
1534
1535
  /*
   * 1b.	Grok the result of xprt_reserve()
   */
  static void
  call_reserveresult(struct rpc_task *task)
  {
  	int status = task->tk_status;
46121cf7d   Chuck Lever   SUNRPC: fix print...
1536
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
1540
1541
1542
1543
1544
  
  	/*
  	 * After a call to xprt_reserve(), we must have either
  	 * a request slot or else an error status.
  	 */
  	task->tk_status = 0;
  	if (status >= 0) {
  		if (task->tk_rqstp) {
f2d47d02f   J. Bruce Fields   Fix null derefere...
1545
  			task->tk_action = call_refresh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546
1547
1548
1549
1550
  			return;
  		}
  
  		printk(KERN_ERR "%s: status=%d, but no request slot, exiting
  ",
0dc47877a   Harvey Harrison   net: replace rema...
1551
  				__func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
  		rpc_exit(task, -EIO);
  		return;
  	}
  
  	/*
  	 * Even though there was an error, we may have acquired
  	 * a request slot somehow.  Make sure not to leak it.
  	 */
  	if (task->tk_rqstp) {
  		printk(KERN_ERR "%s: status=%d, request allocated anyway
  ",
0dc47877a   Harvey Harrison   net: replace rema...
1563
  				__func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
1565
1566
1567
  		xprt_release(task);
  	}
  
  	switch (status) {
1afeaf5c2   Trond Myklebust   sunrpc: fix loss ...
1568
1569
  	case -ENOMEM:
  		rpc_delay(task, HZ >> 2);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1570
  		/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
  	case -EAGAIN:	/* woken up; retry */
ba60eb25f   Trond Myklebust   SUNRPC: Fix a liv...
1572
  		task->tk_action = call_retry_reserve;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
1574
1575
1576
1577
1578
  		return;
  	case -EIO:	/* probably a shutdown */
  		break;
  	default:
  		printk(KERN_ERR "%s: unrecognized error %d, exiting
  ",
0dc47877a   Harvey Harrison   net: replace rema...
1579
  				__func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1580
1581
1582
1583
1584
1585
  		break;
  	}
  	rpc_exit(task, status);
  }
  
  /*
ba60eb25f   Trond Myklebust   SUNRPC: Fix a liv...
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
   * 1c.	Retry reserving an RPC call slot
   */
  static void
  call_retry_reserve(struct rpc_task *task)
  {
  	dprint_status(task);
  
  	task->tk_status  = 0;
  	task->tk_action  = call_reserveresult;
  	xprt_retry_reserve(task);
  }
  
  /*
55576244e   J. Bruce Fields   SUNRPC: cleanup s...
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
   * 2.	Bind and/or refresh the credentials
   */
  static void
  call_refresh(struct rpc_task *task)
  {
  	dprint_status(task);
  
  	task->tk_action = call_refreshresult;
  	task->tk_status = 0;
  	task->tk_client->cl_stats->rpcauthrefresh++;
  	rpcauth_refreshcred(task);
  }
  
  /*
   * 2a.	Process the results of a credential refresh
   */
  static void
  call_refreshresult(struct rpc_task *task)
  {
  	int status = task->tk_status;
  
  	dprint_status(task);
  
  	task->tk_status = 0;
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1623
  	task->tk_action = call_refresh;
55576244e   J. Bruce Fields   SUNRPC: cleanup s...
1624
  	switch (status) {
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1625
  	case 0:
6ff33b7dd   Weston Andros Adamson   sunrpc: Fix infin...
1626
  		if (rpcauth_uptodatecred(task)) {
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1627
  			task->tk_action = call_allocate;
6ff33b7dd   Weston Andros Adamson   sunrpc: Fix infin...
1628
1629
1630
1631
1632
  			return;
  		}
  		/* Use rate-limiting and a max number of retries if refresh
  		 * had status 0 but failed to update the cred.
  		 */
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1633
  		/* fall through */
55576244e   J. Bruce Fields   SUNRPC: cleanup s...
1634
1635
  	case -ETIMEDOUT:
  		rpc_delay(task, 3*HZ);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1636
  		/* fall through */
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1637
1638
  	case -EAGAIN:
  		status = -EACCES;
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1639
  		/* fall through */
f1ff0c27f   Andy Adamson   SUNRPC: don't map...
1640
  	case -EKEYEXPIRED:
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1641
1642
1643
1644
1645
1646
1647
  		if (!task->tk_cred_retry)
  			break;
  		task->tk_cred_retry--;
  		dprintk("RPC: %5u %s: retry refresh creds
  ",
  				task->tk_pid, __func__);
  		return;
55576244e   J. Bruce Fields   SUNRPC: cleanup s...
1648
  	}
5fc43978a   Trond Myklebust   SUNRPC: Fix an in...
1649
1650
1651
1652
  	dprintk("RPC: %5u %s: refresh creds failed with error %d
  ",
  				task->tk_pid, __func__, status);
  	rpc_exit(task, status);
55576244e   J. Bruce Fields   SUNRPC: cleanup s...
1653
1654
1655
1656
  }
  
  /*
   * 2b.	Allocate the buffer. For details, see sched.c:rpc_malloc.
021071483   Chuck Lever   SUNRPC: switchabl...
1657
   *	(Note: buffer memory is freed in xprt_release).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1658
1659
1660
1661
   */
  static void
  call_allocate(struct rpc_task *task)
  {
f2d47d02f   J. Bruce Fields   Fix null derefere...
1662
  	unsigned int slack = task->tk_rqstp->rq_cred->cr_auth->au_cslack;
021071483   Chuck Lever   SUNRPC: switchabl...
1663
  	struct rpc_rqst *req = task->tk_rqstp;
a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
1664
  	struct rpc_xprt *xprt = req->rq_xprt;
499b49881   Christoph Hellwig   sunrpc: mark all ...
1665
  	const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
1666
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667

46121cf7d   Chuck Lever   SUNRPC: fix print...
1668
  	dprint_status(task);
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
1669
  	task->tk_status = 0;
f2d47d02f   J. Bruce Fields   Fix null derefere...
1670
  	task->tk_action = call_bind;
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
1671

021071483   Chuck Lever   SUNRPC: switchabl...
1672
  	if (req->rq_buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
  		return;
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
1674
1675
1676
1677
1678
  	if (proc->p_proc != 0) {
  		BUG_ON(proc->p_arglen == 0);
  		if (proc->p_decode != NULL)
  			BUG_ON(proc->p_replen == 0);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1679

2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
1680
1681
1682
1683
1684
1685
1686
1687
1688
  	/*
  	 * Calculate the size (in quads) of the RPC call
  	 * and reply headers, and convert both values
  	 * to byte sizes.
  	 */
  	req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
  	req->rq_callsize <<= 2;
  	req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
  	req->rq_rcvsize <<= 2;
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
1689
  	status = xprt->ops->buf_alloc(task);
4a0682583   Chuck Lever   SUNRPC: Transport...
1690
  	xprt_inject_disconnect(xprt);
5fe6eaa1f   Chuck Lever   SUNRPC: Generaliz...
1691
1692
1693
1694
1695
1696
  	if (status == 0)
  		return;
  	if (status != -ENOMEM) {
  		rpc_exit(task, status);
  		return;
  	}
46121cf7d   Chuck Lever   SUNRPC: fix print...
1697
1698
1699
  
  	dprintk("RPC: %5u rpc_buffer allocation failed
  ", task->tk_pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1700

5afa9133c   Trond Myklebust   SUNRPC: Ensure th...
1701
  	if (RPC_IS_ASYNC(task) || !fatal_signal_pending(current)) {
b6e9c713f   Trond Myklebust   SUNRPC: Don't cal...
1702
  		task->tk_action = call_allocate;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1703
1704
1705
1706
1707
1708
  		rpc_delay(task, HZ>>4);
  		return;
  	}
  
  	rpc_exit(task, -ERESTARTSYS);
  }
940e3318c   Trond Myklebust   [PATCH] SUNRPC: d...
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
  static inline int
  rpc_task_need_encode(struct rpc_task *task)
  {
  	return task->tk_rqstp->rq_snd_buf.len == 0;
  }
  
  static inline void
  rpc_task_force_reencode(struct rpc_task *task)
  {
  	task->tk_rqstp->rq_snd_buf.len = 0;
2574cc9f4   Trond Myklebust   SUNRPC: Fix rpc_t...
1719
  	task->tk_rqstp->rq_bytes_sent = 0;
940e3318c   Trond Myklebust   [PATCH] SUNRPC: d...
1720
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1721
1722
1723
1724
  /*
   * 3.	Encode arguments of an RPC call
   */
  static void
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
1725
  rpc_xdr_encode(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1727
  	struct rpc_rqst	*req = task->tk_rqstp;
9f06c719f   Chuck Lever   SUNRPC: New xdr_s...
1728
  	kxdreproc_t	encode;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
1729
  	__be32		*p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730

46121cf7d   Chuck Lever   SUNRPC: fix print...
1731
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1732

b9c5bc03b   Chuck Lever   SUNRPC: Refactor ...
1733
1734
1735
1736
  	xdr_buf_init(&req->rq_snd_buf,
  		     req->rq_buffer,
  		     req->rq_callsize);
  	xdr_buf_init(&req->rq_rcv_buf,
68778945e   Chuck Lever   SUNRPC: Separate ...
1737
  		     req->rq_rbuffer,
b9c5bc03b   Chuck Lever   SUNRPC: Refactor ...
1738
  		     req->rq_rcvsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739

b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
1740
1741
1742
1743
  	p = rpc_encode_header(task);
  	if (p == NULL) {
  		printk(KERN_INFO "RPC: couldn't encode RPC header, exit EIO
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1744
1745
1746
  		rpc_exit(task, -EIO);
  		return;
  	}
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
1747
1748
  
  	encode = task->tk_msg.rpc_proc->p_encode;
f3680312a   J. Bruce Fields   SUNRPC: Retry wra...
1749
1750
1751
1752
1753
  	if (encode == NULL)
  		return;
  
  	task->tk_status = rpcauth_wrap_req(task, encode, req, p,
  			task->tk_msg.rpc_argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1754
1755
1756
1757
1758
1759
1760
1761
  }
  
  /*
   * 4.	Get the server port number if not yet set
   */
  static void
  call_bind(struct rpc_task *task)
  {
ad2368d6f   Trond Myklebust   SUNRPC: Avoid RCU...
1762
  	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763

46121cf7d   Chuck Lever   SUNRPC: fix print...
1764
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765

da3518780   Chuck Lever   [PATCH] RPC: prop...
1766
  	task->tk_action = call_connect;
ec739ef03   Chuck Lever   SUNRPC: Create a ...
1767
  	if (!xprt_bound(xprt)) {
da3518780   Chuck Lever   [PATCH] RPC: prop...
1768
  		task->tk_action = call_bind_status;
ec739ef03   Chuck Lever   SUNRPC: Create a ...
1769
  		task->tk_timeout = xprt->bind_timeout;
bbf7c1dd2   Chuck Lever   SUNRPC: Introduce...
1770
  		xprt->ops->rpcbind(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1771
1772
1773
1774
  	}
  }
  
  /*
da3518780   Chuck Lever   [PATCH] RPC: prop...
1775
1776
1777
1778
1779
   * 4a.	Sort out bind result
   */
  static void
  call_bind_status(struct rpc_task *task)
  {
906462af4   Chuck Lever   SUNRPC: Split ano...
1780
  	int status = -EIO;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1781
1782
  
  	if (task->tk_status >= 0) {
46121cf7d   Chuck Lever   SUNRPC: fix print...
1783
  		dprint_status(task);
da3518780   Chuck Lever   [PATCH] RPC: prop...
1784
1785
1786
1787
  		task->tk_status = 0;
  		task->tk_action = call_connect;
  		return;
  	}
5753cba17   Steve Dickson   SUNRPC: Adding st...
1788
  	trace_rpc_bind_status(task);
da3518780   Chuck Lever   [PATCH] RPC: prop...
1789
  	switch (task->tk_status) {
381ba74af   Trond Myklebust   SUNRPC: Ensure ou...
1790
1791
1792
1793
  	case -ENOMEM:
  		dprintk("RPC: %5u rpcbind out of memory
  ", task->tk_pid);
  		rpc_delay(task, HZ >> 2);
2429cbf6a   Chuck Lever   SUNRPC: Add a new...
1794
  		goto retry_timeout;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1795
  	case -EACCES:
46121cf7d   Chuck Lever   SUNRPC: fix print...
1796
1797
1798
  		dprintk("RPC: %5u remote rpcbind: RPC program/version "
  				"unavailable
  ", task->tk_pid);
b79dc8ced   Chuck Lever   SUNRPC: RPC bind ...
1799
1800
1801
1802
1803
  		/* fail immediately if this is an RPC ping */
  		if (task->tk_msg.rpc_proc->p_proc == 0) {
  			status = -EOPNOTSUPP;
  			break;
  		}
0b760113a   Trond Myklebust   NLM: Don't hang f...
1804
1805
1806
  		if (task->tk_rebind_retry == 0)
  			break;
  		task->tk_rebind_retry--;
ea635a517   Chuck Lever   SUNRPC: Retry rpc...
1807
  		rpc_delay(task, 3*HZ);
da45828e2   Trond Myklebust   SUNRPC: Clean up ...
1808
  		goto retry_timeout;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1809
  	case -ETIMEDOUT:
46121cf7d   Chuck Lever   SUNRPC: fix print...
1810
1811
  		dprintk("RPC: %5u rpcbind request timed out
  ",
da3518780   Chuck Lever   [PATCH] RPC: prop...
1812
  				task->tk_pid);
da45828e2   Trond Myklebust   SUNRPC: Clean up ...
1813
  		goto retry_timeout;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1814
  	case -EPFNOSUPPORT:
906462af4   Chuck Lever   SUNRPC: Split ano...
1815
  		/* server doesn't support any rpcbind version we know of */
012da158f   Chuck Lever   SUNRPC: Use soft ...
1816
1817
  		dprintk("RPC: %5u unrecognized remote rpcbind service
  ",
da3518780   Chuck Lever   [PATCH] RPC: prop...
1818
1819
1820
  				task->tk_pid);
  		break;
  	case -EPROTONOSUPPORT:
00a6e7bbf   Chuck Lever   SUNRPC: RPC clien...
1821
1822
  		dprintk("RPC: %5u remote rpcbind version unavailable, retrying
  ",
da3518780   Chuck Lever   [PATCH] RPC: prop...
1823
  				task->tk_pid);
fdb63dcdb   Trond Myklebust   SUNRPC: Ensure th...
1824
  		goto retry_timeout;
012da158f   Chuck Lever   SUNRPC: Use soft ...
1825
1826
  	case -ECONNREFUSED:		/* connection problems */
  	case -ECONNRESET:
df2772700   Trond Myklebust   SUNRPC: Handle co...
1827
  	case -ECONNABORTED:
012da158f   Chuck Lever   SUNRPC: Use soft ...
1828
1829
  	case -ENOTCONN:
  	case -EHOSTDOWN:
eb5b46faa   Trond Myklebust   SUNRPC: Handle EN...
1830
  	case -ENETDOWN:
012da158f   Chuck Lever   SUNRPC: Use soft ...
1831
1832
  	case -EHOSTUNREACH:
  	case -ENETUNREACH:
3601c4a91   Trond Myklebust   SUNRPC: Ensure th...
1833
  	case -ENOBUFS:
012da158f   Chuck Lever   SUNRPC: Use soft ...
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  	case -EPIPE:
  		dprintk("RPC: %5u remote rpcbind unreachable: %d
  ",
  				task->tk_pid, task->tk_status);
  		if (!RPC_IS_SOFTCONN(task)) {
  			rpc_delay(task, 5*HZ);
  			goto retry_timeout;
  		}
  		status = task->tk_status;
  		break;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1844
  	default:
46121cf7d   Chuck Lever   SUNRPC: fix print...
1845
1846
  		dprintk("RPC: %5u unrecognized rpcbind error (%d)
  ",
da3518780   Chuck Lever   [PATCH] RPC: prop...
1847
  				task->tk_pid, -task->tk_status);
da3518780   Chuck Lever   [PATCH] RPC: prop...
1848
1849
1850
1851
  	}
  
  	rpc_exit(task, status);
  	return;
da45828e2   Trond Myklebust   SUNRPC: Clean up ...
1852
  retry_timeout:
fdb63dcdb   Trond Myklebust   SUNRPC: Ensure th...
1853
  	task->tk_status = 0;
da45828e2   Trond Myklebust   SUNRPC: Clean up ...
1854
  	task->tk_action = call_timeout;
da3518780   Chuck Lever   [PATCH] RPC: prop...
1855
1856
1857
1858
  }
  
  /*
   * 4b.	Connect to the RPC server
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
1862
   */
  static void
  call_connect(struct rpc_task *task)
  {
ad2368d6f   Trond Myklebust   SUNRPC: Avoid RCU...
1863
  	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1864

46121cf7d   Chuck Lever   SUNRPC: fix print...
1865
1866
  	dprintk("RPC: %5u call_connect xprt %p %s connected
  ",
da3518780   Chuck Lever   [PATCH] RPC: prop...
1867
1868
  			task->tk_pid, xprt,
  			(xprt_connected(xprt) ? "is" : "is not"));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869

da3518780   Chuck Lever   [PATCH] RPC: prop...
1870
1871
1872
1873
1874
  	task->tk_action = call_transmit;
  	if (!xprt_connected(xprt)) {
  		task->tk_action = call_connect_status;
  		if (task->tk_status < 0)
  			return;
786615bc1   Trond Myklebust   SUNRPC: If the rp...
1875
1876
1877
1878
  		if (task->tk_flags & RPC_TASK_NOCONNECT) {
  			rpc_exit(task, -ENOTCONN);
  			return;
  		}
da3518780   Chuck Lever   [PATCH] RPC: prop...
1879
  		xprt_connect(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1880
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1881
1882
1883
  }
  
  /*
da3518780   Chuck Lever   [PATCH] RPC: prop...
1884
   * 4c.	Sort out connect result
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1885
1886
1887
1888
1889
1890
   */
  static void
  call_connect_status(struct rpc_task *task)
  {
  	struct rpc_clnt *clnt = task->tk_client;
  	int status = task->tk_status;
46121cf7d   Chuck Lever   SUNRPC: fix print...
1891
  	dprint_status(task);
da3518780   Chuck Lever   [PATCH] RPC: prop...
1892

5753cba17   Steve Dickson   SUNRPC: Adding st...
1893
  	trace_rpc_connect_status(task, status);
561ec1603   Trond Myklebust   SUNRPC: call_conn...
1894
  	task->tk_status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
  	switch (status) {
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1896
  	case -ECONNREFUSED:
fd01b2597   NeilBrown   SUNRPC: ECONNREFU...
1897
1898
1899
1900
1901
1902
1903
1904
  		/* A positive refusal suggests a rebind is needed. */
  		if (RPC_IS_SOFTCONN(task))
  			break;
  		if (clnt->cl_autobind) {
  			rpc_force_rebind(clnt);
  			task->tk_action = call_bind;
  			return;
  		}
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1905
  		/* fall through */
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1906
  	case -ECONNRESET:
df2772700   Trond Myklebust   SUNRPC: Handle co...
1907
  	case -ECONNABORTED:
eb5b46faa   Trond Myklebust   SUNRPC: Handle EN...
1908
  	case -ENETDOWN:
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1909
  	case -ENETUNREACH:
df2772700   Trond Myklebust   SUNRPC: Handle co...
1910
  	case -EHOSTUNREACH:
3913c78c3   Trond Myklebust   SUNRPC: Handle EA...
1911
  	case -EADDRINUSE:
3601c4a91   Trond Myklebust   SUNRPC: Ensure th...
1912
  	case -ENOBUFS:
2fc193cf9   Trond Myklebust   SUNRPC: Handle EP...
1913
  	case -EPIPE:
2c2ee6d20   NeilBrown   sunrpc: Don't eng...
1914
1915
  		xprt_conditional_disconnect(task->tk_rqstp->rq_xprt,
  					    task->tk_rqstp->rq_connect_cookie);
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1916
1917
  		if (RPC_IS_SOFTCONN(task))
  			break;
1fa3e2eb9   Steve Dickson   SUNRPC: Ensure ca...
1918
1919
  		/* retry with existing socket, after a delay */
  		rpc_delay(task, 3*HZ);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
1920
  		/* fall through */
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1921
  	case -EAGAIN:
485f22517   Trond Myklebust   SUNRPC: Ensure th...
1922
1923
1924
  		/* Check for timeouts before looping back to call_bind */
  	case -ETIMEDOUT:
  		task->tk_action = call_timeout;
561ec1603   Trond Myklebust   SUNRPC: call_conn...
1925
1926
  		return;
  	case 0:
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1927
1928
1929
  		clnt->cl_stats->netreconn++;
  		task->tk_action = call_transmit;
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
  	}
3ed5e2a2c   Trond Myklebust   SUNRPC: Report ne...
1931
  	rpc_exit(task, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932
1933
1934
1935
1936
1937
1938
1939
  }
  
  /*
   * 5.	Transmit the RPC request, and wait for reply
   */
  static void
  call_transmit(struct rpc_task *task)
  {
ca7f33aa5   Trond Myklebust   SUNRPC: Fix RPC c...
1940
  	int is_retrans = RPC_WAS_SENT(task);
46121cf7d   Chuck Lever   SUNRPC: fix print...
1941
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1942
1943
1944
1945
  
  	task->tk_action = call_status;
  	if (task->tk_status < 0)
  		return;
90051ea77   Trond Myklebust   SUNRPC: Clean up ...
1946
  	if (!xprt_prepare_transmit(task))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947
  		return;
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
1948
  	task->tk_action = call_transmit_status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1949
  	/* Encode here so that rpcsec_gss can use correct sequence number. */
940e3318c   Trond Myklebust   [PATCH] SUNRPC: d...
1950
  	if (rpc_task_need_encode(task)) {
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
1951
  		rpc_xdr_encode(task);
5e5ce5be6   Trond Myklebust   RPC: allow call_e...
1952
  		/* Did the encode result in an error condition? */
8b39f2b41   Trond Myklebust   SUNRPC: Ensure we...
1953
1954
1955
1956
1957
1958
  		if (task->tk_status != 0) {
  			/* Was the error nonfatal? */
  			if (task->tk_status == -EAGAIN)
  				rpc_delay(task, HZ >> 4);
  			else
  				rpc_exit(task, task->tk_status);
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
1959
  			return;
8b39f2b41   Trond Myklebust   SUNRPC: Ensure we...
1960
  		}
5e5ce5be6   Trond Myklebust   RPC: allow call_e...
1961
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1962
1963
1964
  	xprt_transmit(task);
  	if (task->tk_status < 0)
  		return;
ca7f33aa5   Trond Myklebust   SUNRPC: Fix RPC c...
1965
1966
  	if (is_retrans)
  		task->tk_client->cl_stats->rpcretrans++;
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
1967
1968
1969
1970
1971
  	/*
  	 * On success, ensure that we call xprt_end_transmit() before sleeping
  	 * in order to allow access to the socket to other RPC requests.
  	 */
  	call_transmit_status(task);
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
1972
  	if (rpc_reply_expected(task))
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
1973
1974
  		return;
  	task->tk_action = rpc_exit_task;
a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
1975
  	rpc_wake_up_queued_task(&task->tk_rqstp->rq_xprt->pending, task);
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
1976
1977
1978
1979
1980
1981
1982
1983
1984
  }
  
  /*
   * 5a.	Handle cleanup after a transmission
   */
  static void
  call_transmit_status(struct rpc_task *task)
  {
  	task->tk_action = call_status;
206a134b4   Chuck Lever   SUNRPC: Check exp...
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
  
  	/*
  	 * Common case: success.  Force the compiler to put this
  	 * test first.
  	 */
  	if (task->tk_status == 0) {
  		xprt_end_transmit(task);
  		rpc_task_force_reencode(task);
  		return;
  	}
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
1995
1996
  	switch (task->tk_status) {
  	case -EAGAIN:
93aa6c7bb   Trond Myklebust   SUNRPC: Don't ree...
1997
  	case -ENOBUFS:
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
1998
1999
  		break;
  	default:
206a134b4   Chuck Lever   SUNRPC: Check exp...
2000
  		dprint_status(task);
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
2001
  		xprt_end_transmit(task);
09a21c410   Chuck Lever   SUNRPC: Allow RPC...
2002
2003
  		rpc_task_force_reencode(task);
  		break;
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
2004
2005
2006
2007
2008
2009
2010
  		/*
  		 * Special cases: if we've been waiting on the
  		 * socket's write_space() callback, or if the
  		 * socket just returned a connection error,
  		 * then hold onto the transport lock.
  		 */
  	case -ECONNREFUSED:
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
2011
  	case -EHOSTDOWN:
eb5b46faa   Trond Myklebust   SUNRPC: Handle EN...
2012
  	case -ENETDOWN:
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
2013
2014
  	case -EHOSTUNREACH:
  	case -ENETUNREACH:
3dedbb5ca   Jason Baron   rpc: Add -EPERM p...
2015
  	case -EPERM:
09a21c410   Chuck Lever   SUNRPC: Allow RPC...
2016
2017
2018
2019
2020
  		if (RPC_IS_SOFTCONN(task)) {
  			xprt_end_transmit(task);
  			rpc_exit(task, task->tk_status);
  			break;
  		}
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
2021
  		/* fall through */
09a21c410   Chuck Lever   SUNRPC: Allow RPC...
2022
  	case -ECONNRESET:
df2772700   Trond Myklebust   SUNRPC: Handle co...
2023
  	case -ECONNABORTED:
3913c78c3   Trond Myklebust   SUNRPC: Handle EA...
2024
  	case -EADDRINUSE:
09a21c410   Chuck Lever   SUNRPC: Allow RPC...
2025
  	case -ENOTCONN:
c8485e4d6   Trond Myklebust   SUNRPC: Handle EC...
2026
  	case -EPIPE:
15f081ca8   Trond Myklebust   SUNRPC: Avoid an ...
2027
2028
  		rpc_task_force_reencode(task);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2029
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
2030
  #if defined(CONFIG_SUNRPC_BACKCHANNEL)
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2031
2032
2033
2034
2035
2036
2037
2038
  /*
   * 5b.	Send the backchannel RPC reply.  On error, drop the reply.  In
   * addition, disconnect on connectivity errors.
   */
  static void
  call_bc_transmit(struct rpc_task *task)
  {
  	struct rpc_rqst *req = task->tk_rqstp;
1193d58f7   Trond Myklebust   SUNRPC: Backchann...
2039
2040
  	if (!xprt_prepare_transmit(task))
  		goto out_retry;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2041

55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2042
2043
2044
2045
  	if (task->tk_status < 0) {
  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
  			"error: %d
  ", task->tk_status);
1193d58f7   Trond Myklebust   SUNRPC: Backchann...
2046
  		goto out_done;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2047
  	}
1193d58f7   Trond Myklebust   SUNRPC: Backchann...
2048
2049
  	if (req->rq_connect_cookie != req->rq_xprt->connect_cookie)
  		req->rq_bytes_sent = 0;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2050
2051
  
  	xprt_transmit(task);
1193d58f7   Trond Myklebust   SUNRPC: Backchann...
2052
2053
2054
  
  	if (task->tk_status == -EAGAIN)
  		goto out_nospace;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2055
2056
2057
2058
2059
  	xprt_end_transmit(task);
  	dprint_status(task);
  	switch (task->tk_status) {
  	case 0:
  		/* Success */
eb5b46faa   Trond Myklebust   SUNRPC: Handle EN...
2060
  	case -ENETDOWN:
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2061
2062
2063
  	case -EHOSTDOWN:
  	case -EHOSTUNREACH:
  	case -ENETUNREACH:
3832591e6   Trond Myklebust   SUNRPC: Handle co...
2064
2065
2066
2067
2068
2069
  	case -ECONNRESET:
  	case -ECONNREFUSED:
  	case -EADDRINUSE:
  	case -ENOTCONN:
  	case -EPIPE:
  		break;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
  	case -ETIMEDOUT:
  		/*
  		 * Problem reaching the server.  Disconnect and let the
  		 * forechannel reestablish the connection.  The server will
  		 * have to retransmit the backchannel request and we'll
  		 * reprocess it.  Since these ops are idempotent, there's no
  		 * need to cache our reply at this time.
  		 */
  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
  			"error: %d
  ", task->tk_status);
a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
2081
  		xprt_conditional_disconnect(req->rq_xprt,
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2082
2083
2084
2085
2086
2087
2088
  			req->rq_connect_cookie);
  		break;
  	default:
  		/*
  		 * We were unable to reply and will have to drop the
  		 * request.  The server should reconnect and retransmit.
  		 */
1facf4c4a   Weston Andros Adamson   SUNRPC: remove BU...
2089
  		WARN_ON_ONCE(task->tk_status == -EAGAIN);
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2090
2091
2092
2093
2094
2095
  		printk(KERN_NOTICE "RPC: Could not send backchannel reply "
  			"error: %d
  ", task->tk_status);
  		break;
  	}
  	rpc_wake_up_queued_task(&req->rq_xprt->pending, task);
1193d58f7   Trond Myklebust   SUNRPC: Backchann...
2096
2097
2098
2099
2100
2101
2102
  out_done:
  	task->tk_action = rpc_exit_task;
  	return;
  out_nospace:
  	req->rq_connect_cookie = req->rq_xprt->connect_cookie;
  out_retry:
  	task->tk_status = 0;
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2103
  }
9e00abc3c   Trond Myklebust   SUNRPC: sunrpc sh...
2104
  #endif /* CONFIG_SUNRPC_BACKCHANNEL */
55ae1aabf   Ricardo Labiaga   nfs41: Add backch...
2105

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2106
2107
2108
2109
2110
2111
2112
2113
2114
  /*
   * 6.	Sort out the RPC call status
   */
  static void
  call_status(struct rpc_task *task)
  {
  	struct rpc_clnt	*clnt = task->tk_client;
  	struct rpc_rqst	*req = task->tk_rqstp;
  	int		status;
dd2b63d04   Ricardo Labiaga   nfs41: Rename rq_...
2115
2116
  	if (req->rq_reply_bytes_recvd > 0 && !req->rq_bytes_sent)
  		task->tk_status = req->rq_reply_bytes_recvd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117

46121cf7d   Chuck Lever   SUNRPC: fix print...
2118
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
2120
2121
2122
2123
2124
  
  	status = task->tk_status;
  	if (status >= 0) {
  		task->tk_action = call_decode;
  		return;
  	}
5753cba17   Steve Dickson   SUNRPC: Adding st...
2125
  	trace_rpc_call_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126
2127
  	task->tk_status = 0;
  	switch(status) {
76303992b   Trond Myklebust   SUNRPC: Handle EN...
2128
  	case -EHOSTDOWN:
eb5b46faa   Trond Myklebust   SUNRPC: Handle EN...
2129
  	case -ENETDOWN:
76303992b   Trond Myklebust   SUNRPC: Handle EN...
2130
2131
  	case -EHOSTUNREACH:
  	case -ENETUNREACH:
3dedbb5ca   Jason Baron   rpc: Add -EPERM p...
2132
  	case -EPERM:
9455e3f43   Trond Myklebust   SUNRPC: Ensure ca...
2133
2134
2135
2136
  		if (RPC_IS_SOFTCONN(task)) {
  			rpc_exit(task, status);
  			break;
  		}
76303992b   Trond Myklebust   SUNRPC: Handle EN...
2137
2138
2139
2140
2141
  		/*
  		 * Delay any retries for 3 seconds, then handle as if it
  		 * were a timeout.
  		 */
  		rpc_delay(task, 3*HZ);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
2142
  		/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
2146
  	case -ETIMEDOUT:
  		task->tk_action = call_timeout;
  		break;
  	case -ECONNREFUSED:
df2772700   Trond Myklebust   SUNRPC: Handle co...
2147
2148
  	case -ECONNRESET:
  	case -ECONNABORTED:
35f5a422c   Chuck Lever   SUNRPC: new inter...
2149
  		rpc_force_rebind(clnt);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
2150
  		/* fall through */
3913c78c3   Trond Myklebust   SUNRPC: Handle EA...
2151
  	case -EADDRINUSE:
c8485e4d6   Trond Myklebust   SUNRPC: Handle EC...
2152
  		rpc_delay(task, 3*HZ);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
2153
  		/* fall through */
c8485e4d6   Trond Myklebust   SUNRPC: Handle EC...
2154
2155
  	case -EPIPE:
  	case -ENOTCONN:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
2157
  		task->tk_action = call_bind;
  		break;
93aa6c7bb   Trond Myklebust   SUNRPC: Don't ree...
2158
2159
  	case -ENOBUFS:
  		rpc_delay(task, HZ>>2);
e9d476393   Gustavo A. R. Silva   net: sunrpc: mark...
2160
  		/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161
2162
2163
2164
2165
2166
2167
2168
  	case -EAGAIN:
  		task->tk_action = call_transmit;
  		break;
  	case -EIO:
  		/* shutdown or soft timeout */
  		rpc_exit(task, status);
  		break;
  	default:
b6b6152c4   Olga Kornievskaia   rpc: bring back c...
2169
2170
2171
  		if (clnt->cl_chatty)
  			printk("%s: RPC call returned error %d
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2172
  			       clnt->cl_program->name, -status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
  		rpc_exit(task, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2174
2175
2176
2177
  	}
  }
  
  /*
e0ab53dea   Trond Myklebust   RPC: Ensure that ...
2178
   * 6a.	Handle RPC timeout
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2179
2180
2181
2182
2183
2184
2185
2186
2187
   * 	We do not release the request slot, so we keep using the
   *	same XID for all retransmits.
   */
  static void
  call_timeout(struct rpc_task *task)
  {
  	struct rpc_clnt	*clnt = task->tk_client;
  
  	if (xprt_adjust_timeout(task->tk_rqstp) == 0) {
46121cf7d   Chuck Lever   SUNRPC: fix print...
2188
2189
  		dprintk("RPC: %5u call_timeout (minor)
  ", task->tk_pid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2190
2191
  		goto retry;
  	}
46121cf7d   Chuck Lever   SUNRPC: fix print...
2192
2193
  	dprintk("RPC: %5u call_timeout (major)
  ", task->tk_pid);
ef759a2e5   Chuck Lever   SUNRPC: introduce...
2194
  	task->tk_timeouts++;
3a28becc3   Chuck Lever   SUNRPC: soft conn...
2195
2196
2197
2198
  	if (RPC_IS_SOFTCONN(task)) {
  		rpc_exit(task, -ETIMEDOUT);
  		return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
  	if (RPC_IS_SOFT(task)) {
cac5d07e3   Joe Perches   sunrpc: clnt: Add...
2200
  		if (clnt->cl_chatty) {
b6b6152c4   Olga Kornievskaia   rpc: bring back c...
2201
2202
  			printk(KERN_NOTICE "%s: server %s not responding, timed out
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2203
  				clnt->cl_program->name,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2204
  				task->tk_xprt->servername);
cac5d07e3   Joe Perches   sunrpc: clnt: Add...
2205
  		}
7494d00c7   Trond Myklebust   SUNRPC: Allow RPC...
2206
2207
2208
2209
  		if (task->tk_flags & RPC_TASK_TIMEOUT)
  			rpc_exit(task, -ETIMEDOUT);
  		else
  			rpc_exit(task, -EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
2211
  		return;
  	}
f518e35ae   Chuck Lever   SUNRPC: get rid o...
2212
  	if (!(task->tk_flags & RPC_CALL_MAJORSEEN)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2213
  		task->tk_flags |= RPC_CALL_MAJORSEEN;
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2214
  		if (clnt->cl_chatty) {
b6b6152c4   Olga Kornievskaia   rpc: bring back c...
2215
2216
  			printk(KERN_NOTICE "%s: server %s not responding, still trying
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2217
  			clnt->cl_program->name,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2218
  			task->tk_xprt->servername);
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2219
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2220
  	}
35f5a422c   Chuck Lever   SUNRPC: new inter...
2221
  	rpc_force_rebind(clnt);
b48633bd0   Trond Myklebust   SUNRPC: Invalidat...
2222
2223
2224
2225
2226
  	/*
  	 * Did our request time out due to an RPCSEC_GSS out-of-sequence
  	 * event? RFC2203 requires the server to drop all such requests.
  	 */
  	rpcauth_invalcred(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227
2228
  
  retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
  	task->tk_action = call_bind;
  	task->tk_status = 0;
  }
  
  /*
   * 7.	Decode the RPC reply
   */
  static void
  call_decode(struct rpc_task *task)
  {
  	struct rpc_clnt	*clnt = task->tk_client;
  	struct rpc_rqst	*req = task->tk_rqstp;
bf2695516   Chuck Lever   SUNRPC: New xdr_s...
2241
  	kxdrdproc_t	decode = task->tk_msg.rpc_proc->p_decode;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2242
  	__be32		*p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2243

726fd6ad5   Vasily Averin   sunrpc: use dprin...
2244
  	dprint_status(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2245

f518e35ae   Chuck Lever   SUNRPC: get rid o...
2246
  	if (task->tk_flags & RPC_CALL_MAJORSEEN) {
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2247
  		if (clnt->cl_chatty) {
b6b6152c4   Olga Kornievskaia   rpc: bring back c...
2248
2249
  			printk(KERN_NOTICE "%s: server %s OK
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2250
  				clnt->cl_program->name,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2251
  				task->tk_xprt->servername);
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2252
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2253
2254
  		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
  	}
43ac3f296   Trond Myklebust   SUNRPC: Fix memor...
2255
2256
  	/*
  	 * Ensure that we see all writes made by xprt_complete_rqst()
dd2b63d04   Ricardo Labiaga   nfs41: Rename rq_...
2257
  	 * before it changed req->rq_reply_bytes_recvd.
43ac3f296   Trond Myklebust   SUNRPC: Fix memor...
2258
2259
  	 */
  	smp_rmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2260
2261
2262
2263
2264
  	req->rq_rcv_buf.len = req->rq_private_buf.len;
  
  	/* Check that the softirq receive buffer is valid */
  	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
  				sizeof(req->rq_rcv_buf)) != 0);
1e799b673   Trond Myklebust   SUNRPC: Fix read ...
2265
2266
2267
  	if (req->rq_rcv_buf.len < 12) {
  		if (!RPC_IS_SOFT(task)) {
  			task->tk_action = call_bind;
1e799b673   Trond Myklebust   SUNRPC: Fix read ...
2268
2269
2270
2271
  			goto out_retry;
  		}
  		dprintk("RPC:       %s: too small RPC reply size (%d bytes)
  ",
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2272
  				clnt->cl_program->name, task->tk_status);
1e799b673   Trond Myklebust   SUNRPC: Fix read ...
2273
2274
2275
  		task->tk_action = call_timeout;
  		goto out_retry;
  	}
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
2276
  	p = rpc_verify_header(task);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2277
2278
2279
2280
  	if (IS_ERR(p)) {
  		if (p == ERR_PTR(-EAGAIN))
  			goto out_retry;
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2281
  	}
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2282
  	task->tk_action = rpc_exit_task;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283

6d5fcb5a5   Trond Myklebust   SUNRPC: Remove BK...
2284
  	if (decode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
  		task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
  						      task->tk_msg.rpc_resp);
6d5fcb5a5   Trond Myklebust   SUNRPC: Remove BK...
2287
  	}
46121cf7d   Chuck Lever   SUNRPC: fix print...
2288
2289
2290
  	dprintk("RPC: %5u call_decode result %d
  ", task->tk_pid,
  			task->tk_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2291
2292
  	return;
  out_retry:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2293
  	task->tk_status = 0;
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
2294
  	/* Note: rpc_verify_header() may have freed the RPC slot */
24b74bf0c   Trond Myklebust   SUNRPC: Fix a bug...
2295
  	if (task->tk_rqstp == req) {
dd2b63d04   Ricardo Labiaga   nfs41: Rename rq_...
2296
  		req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
24b74bf0c   Trond Myklebust   SUNRPC: Fix a bug...
2297
  		if (task->tk_client->cl_discrtry)
a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
2298
  			xprt_conditional_disconnect(req->rq_xprt,
7c1d71cf5   Trond Myklebust   SUNRPC: Don't dis...
2299
  					req->rq_connect_cookie);
24b74bf0c   Trond Myklebust   SUNRPC: Fix a bug...
2300
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2301
  }
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2302
  static __be32 *
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
2303
  rpc_encode_header(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2304
2305
  {
  	struct rpc_clnt *clnt = task->tk_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2306
  	struct rpc_rqst	*req = task->tk_rqstp;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2307
  	__be32		*p = req->rq_svec[0].iov_base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2308
2309
  
  	/* FIXME: check buffer size? */
808012fbb   Chuck Lever   [PATCH] RPC: skip...
2310

a4f0835c6   Trond Myklebust   SUNRPC: Eliminate...
2311
  	p = xprt_skip_transport_header(req->rq_xprt, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2312
2313
2314
2315
2316
2317
  	*p++ = req->rq_xid;		/* XID */
  	*p++ = htonl(RPC_CALL);		/* CALL */
  	*p++ = htonl(RPC_VERSION);	/* RPC version */
  	*p++ = htonl(clnt->cl_prog);	/* program number */
  	*p++ = htonl(clnt->cl_vers);	/* program version */
  	*p++ = htonl(task->tk_msg.rpc_proc->p_proc);	/* procedure */
334ccfd54   Trond Myklebust   [PATCH] RPC: Ensu...
2318
2319
2320
  	p = rpcauth_marshcred(task, p);
  	req->rq_slen = xdr_adjust_iovec(&req->rq_svec[0], p);
  	return p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2321
  }
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2322
  static __be32 *
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
2323
  rpc_verify_header(struct rpc_task *task)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2324
  {
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2325
  	struct rpc_clnt *clnt = task->tk_client;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
  	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
  	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2328
2329
  	__be32	*p = iov->iov_base;
  	u32 n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2330
  	int error = -EACCES;
e8896495b   David Howells   NFS: Check length...
2331
2332
2333
2334
2335
2336
  	if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
  		/* RFC-1014 says that the representation of XDR data must be a
  		 * multiple of four bytes
  		 * - if it isn't pointer subtraction in the NFS client may give
  		 *   undefined results
  		 */
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2337
  		dprintk("RPC: %5u %s: XDR representation not a multiple of"
0dc47877a   Harvey Harrison   net: replace rema...
2338
2339
  		       " 4 bytes: 0x%x
  ", task->tk_pid, __func__,
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2340
  		       task->tk_rqstp->rq_rcv_buf.len);
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
2341
2342
  		error = -EIO;
  		goto out_err;
e8896495b   David Howells   NFS: Check length...
2343
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2344
2345
  	if ((len -= 3) < 0)
  		goto out_overflow;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346

f4a2e418b   Ricardo Labiaga   nfs41: Process th...
2347
  	p += 1; /* skip XID */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2348
  	if ((n = ntohl(*p++)) != RPC_REPLY) {
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2349
2350
  		dprintk("RPC: %5u %s: not an RPC reply: %x
  ",
f4a2e418b   Ricardo Labiaga   nfs41: Process th...
2351
  			task->tk_pid, __func__, n);
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
2352
  		error = -EIO;
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2353
  		goto out_garbage;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
  	}
f4a2e418b   Ricardo Labiaga   nfs41: Process th...
2355

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356
2357
2358
2359
  	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
  		if (--len < 0)
  			goto out_overflow;
  		switch ((n = ntohl(*p++))) {
89f0e4fea   Joe Perches   sunrpc: Reduce sw...
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
  		case RPC_AUTH_ERROR:
  			break;
  		case RPC_MISMATCH:
  			dprintk("RPC: %5u %s: RPC call version mismatch!
  ",
  				task->tk_pid, __func__);
  			error = -EPROTONOSUPPORT;
  			goto out_err;
  		default:
  			dprintk("RPC: %5u %s: RPC call rejected, "
  				"unknown error: %x
  ",
  				task->tk_pid, __func__, n);
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
2373
2374
  			error = -EIO;
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
  		}
  		if (--len < 0)
  			goto out_overflow;
  		switch ((n = ntohl(*p++))) {
  		case RPC_AUTH_REJECTEDCRED:
  		case RPC_AUTH_REJECTEDVERF:
  		case RPCSEC_GSS_CREDPROBLEM:
  		case RPCSEC_GSS_CTXPROBLEM:
  			if (!task->tk_cred_retry)
  				break;
  			task->tk_cred_retry--;
46121cf7d   Chuck Lever   SUNRPC: fix print...
2386
2387
  			dprintk("RPC: %5u %s: retry stale creds
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2388
  					task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2389
  			rpcauth_invalcred(task);
220bcc2af   Trond Myklebust   SUNRPC: Don't cal...
2390
2391
  			/* Ensure we obtain a new XID! */
  			xprt_release(task);
118df3d17   Trond Myklebust   SUNRPC: After cal...
2392
  			task->tk_action = call_reserve;
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2393
  			goto out_retry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2394
2395
2396
2397
2398
2399
  		case RPC_AUTH_BADCRED:
  		case RPC_AUTH_BADVERF:
  			/* possibly garbled cred/verf? */
  			if (!task->tk_garb_retry)
  				break;
  			task->tk_garb_retry--;
46121cf7d   Chuck Lever   SUNRPC: fix print...
2400
2401
  			dprintk("RPC: %5u %s: retry garbled creds
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2402
  					task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2403
  			task->tk_action = call_bind;
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2404
  			goto out_retry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2405
  		case RPC_AUTH_TOOWEAK:
b0e1c57ea   Chuck Lever   SUNRPC: Rename "c...
2406
  			printk(KERN_NOTICE "RPC: server %s requires stronger "
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2407
2408
  			       "authentication.
  ",
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2409
  			       task->tk_xprt->servername);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2410
2411
  			break;
  		default:
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2412
2413
  			dprintk("RPC: %5u %s: unknown auth error: %x
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2414
  					task->tk_pid, __func__, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2415
2416
  			error = -EIO;
  		}
46121cf7d   Chuck Lever   SUNRPC: fix print...
2417
2418
  		dprintk("RPC: %5u %s: call rejected %d
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2419
  				task->tk_pid, __func__, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2420
2421
  		goto out_err;
  	}
35fa5f7b3   Andy Adamson   SUNRPC refactor r...
2422
2423
2424
2425
2426
2427
  	p = rpcauth_checkverf(task, p);
  	if (IS_ERR(p)) {
  		error = PTR_ERR(p);
  		dprintk("RPC: %5u %s: auth check failed with %d
  ",
  				task->tk_pid, __func__, error);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2428
  		goto out_garbage;		/* bad verifier, retry */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2429
  	}
d8ed029d6   Alexey Dobriyan   [SUNRPC]: trivial...
2430
  	len = p - (__be32 *)iov->iov_base - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2431
2432
2433
2434
2435
2436
  	if (len < 0)
  		goto out_overflow;
  	switch ((n = ntohl(*p++))) {
  	case RPC_SUCCESS:
  		return p;
  	case RPC_PROG_UNAVAIL:
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2437
  		dprintk("RPC: %5u %s: program %u is unsupported "
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2438
2439
2440
  				"by server %s
  ", task->tk_pid, __func__,
  				(unsigned int)clnt->cl_prog,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2441
  				task->tk_xprt->servername);
cdf477068   Andreas Gruenbacher   [PATCH] RPC: Retu...
2442
2443
  		error = -EPFNOSUPPORT;
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444
  	case RPC_PROG_MISMATCH:
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2445
  		dprintk("RPC: %5u %s: program %u, version %u unsupported "
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2446
2447
2448
2449
  				"by server %s
  ", task->tk_pid, __func__,
  				(unsigned int)clnt->cl_prog,
  				(unsigned int)clnt->cl_vers,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2450
  				task->tk_xprt->servername);
cdf477068   Andreas Gruenbacher   [PATCH] RPC: Retu...
2451
2452
  		error = -EPROTONOSUPPORT;
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2453
  	case RPC_PROC_UNAVAIL:
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2454
  		dprintk("RPC: %5u %s: proc %s unsupported by program %u, "
46121cf7d   Chuck Lever   SUNRPC: fix print...
2455
2456
  				"version %u on server %s
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2457
  				task->tk_pid, __func__,
3748f1e44   Chuck Lever   SUNRPC: Add a fun...
2458
  				rpc_proc_name(task),
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2459
  				clnt->cl_prog, clnt->cl_vers,
fb43d1721   Trond Myklebust   SUNRPC: Use the m...
2460
  				task->tk_xprt->servername);
cdf477068   Andreas Gruenbacher   [PATCH] RPC: Retu...
2461
2462
  		error = -EOPNOTSUPP;
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463
  	case RPC_GARBAGE_ARGS:
46121cf7d   Chuck Lever   SUNRPC: fix print...
2464
2465
  		dprintk("RPC: %5u %s: server saw garbage
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2466
  				task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
2468
  		break;			/* retry */
  	default:
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2469
2470
  		dprintk("RPC: %5u %s: server accept status: %x
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2471
  				task->tk_pid, __func__, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2472
2473
  		/* Also retry */
  	}
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2474
  out_garbage:
4e0038b6b   Trond Myklebust   SUNRPC: Move clnt...
2475
  	clnt->cl_stats->rpcgarbage++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2476
2477
  	if (task->tk_garb_retry) {
  		task->tk_garb_retry--;
46121cf7d   Chuck Lever   SUNRPC: fix print...
2478
2479
  		dprintk("RPC: %5u %s: retrying
  ",
0dc47877a   Harvey Harrison   net: replace rema...
2480
  				task->tk_pid, __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2481
  		task->tk_action = call_bind;
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2482
2483
  out_retry:
  		return ERR_PTR(-EAGAIN);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2484
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2485
2486
  out_err:
  	rpc_exit(task, error);
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2487
2488
  	dprintk("RPC: %5u %s: call failed with error %d
  ", task->tk_pid,
0dc47877a   Harvey Harrison   net: replace rema...
2489
  			__func__, error);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2490
  	return ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
  out_overflow:
8a702bbb7   Trond Myklebust   SUNRPC: Suppress ...
2492
2493
  	dprintk("RPC: %5u %s: server reply was truncated.
  ", task->tk_pid,
0dc47877a   Harvey Harrison   net: replace rema...
2494
  			__func__);
abbcf28f2   Trond Myklebust   SUNRPC: Yet more ...
2495
  	goto out_garbage;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
  }
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2497

c512f36b5   Christoph Hellwig   sunrpc: properly ...
2498
2499
  static void rpcproc_encode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
  		const void *obj)
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2500
  {
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2501
  }
73c8dc133   Christoph Hellwig   sunrpc: properly ...
2502
2503
  static int rpcproc_decode_null(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
  		void *obj)
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2504
2505
2506
  {
  	return 0;
  }
499b49881   Christoph Hellwig   sunrpc: mark all ...
2507
  static const struct rpc_procinfo rpcproc_null = {
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2508
2509
2510
  	.p_encode = rpcproc_encode_null,
  	.p_decode = rpcproc_decode_null,
  };
caabea8a5   Chuck Lever   SUNRPC: Use soft ...
2511
  static int rpc_ping(struct rpc_clnt *clnt)
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2512
2513
2514
2515
2516
2517
  {
  	struct rpc_message msg = {
  		.rpc_proc = &rpcproc_null,
  	};
  	int err;
  	msg.rpc_cred = authnull_ops.lookup_cred(NULL, NULL, 0);
caabea8a5   Chuck Lever   SUNRPC: Use soft ...
2518
  	err = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN);
5ee0ed7d3   Trond Myklebust   [PATCH] RPC: Make...
2519
2520
2521
  	put_rpccred(msg.rpc_cred);
  	return err;
  }
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2522

7f5548905   Trond Myklebust   SUNRPC: Allow add...
2523
2524
2525
2526
  static
  struct rpc_task *rpc_call_null_helper(struct rpc_clnt *clnt,
  		struct rpc_xprt *xprt, struct rpc_cred *cred, int flags,
  		const struct rpc_call_ops *ops, void *data)
5e1550d6a   Trond Myklebust   SUNRPC: Add the h...
2527
2528
2529
2530
2531
  {
  	struct rpc_message msg = {
  		.rpc_proc = &rpcproc_null,
  		.rpc_cred = cred,
  	};
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
2532
2533
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clnt,
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2534
  		.rpc_xprt = xprt,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
2535
  		.rpc_message = &msg,
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2536
2537
  		.callback_ops = (ops != NULL) ? ops : &rpc_default_ops,
  		.callback_data = data,
84115e1cd   Trond Myklebust   SUNRPC: Cleanup o...
2538
2539
  		.flags = flags,
  	};
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2540

c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
2541
  	return rpc_run_task(&task_setup_data);
5e1550d6a   Trond Myklebust   SUNRPC: Add the h...
2542
  }
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2543
2544
2545
2546
2547
  
  struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
  {
  	return rpc_call_null_helper(clnt, NULL, cred, flags, NULL, NULL);
  }
e8914c65f   Trond Myklebust   SUNRPC: Restrict ...
2548
  EXPORT_SYMBOL_GPL(rpc_call_null);
5e1550d6a   Trond Myklebust   SUNRPC: Add the h...
2549

7f5548905   Trond Myklebust   SUNRPC: Allow add...
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
  struct rpc_cb_add_xprt_calldata {
  	struct rpc_xprt_switch *xps;
  	struct rpc_xprt *xprt;
  };
  
  static void rpc_cb_add_xprt_done(struct rpc_task *task, void *calldata)
  {
  	struct rpc_cb_add_xprt_calldata *data = calldata;
  
  	if (task->tk_status == 0)
  		rpc_xprt_switch_add_xprt(data->xps, data->xprt);
  }
  
  static void rpc_cb_add_xprt_release(void *calldata)
  {
  	struct rpc_cb_add_xprt_calldata *data = calldata;
  
  	xprt_put(data->xprt);
  	xprt_switch_put(data->xps);
  	kfree(data);
  }
ce272302d   Trond Myklebust   SUNRPC: Fix a com...
2571
  static const struct rpc_call_ops rpc_cb_add_xprt_call_ops = {
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
  	.rpc_call_done = rpc_cb_add_xprt_done,
  	.rpc_release = rpc_cb_add_xprt_release,
  };
  
  /**
   * rpc_clnt_test_and_add_xprt - Test and add a new transport to a rpc_clnt
   * @clnt: pointer to struct rpc_clnt
   * @xps: pointer to struct rpc_xprt_switch,
   * @xprt: pointer struct rpc_xprt
   * @dummy: unused
   */
  int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt,
  		struct rpc_xprt_switch *xps, struct rpc_xprt *xprt,
  		void *dummy)
  {
  	struct rpc_cb_add_xprt_calldata *data;
  	struct rpc_cred *cred;
  	struct rpc_task *task;
  
  	data = kmalloc(sizeof(*data), GFP_NOFS);
  	if (!data)
  		return -ENOMEM;
  	data->xps = xprt_switch_get(xps);
  	data->xprt = xprt_get(xprt);
  
  	cred = authnull_ops.lookup_cred(NULL, NULL, 0);
  	task = rpc_call_null_helper(clnt, xprt, cred,
  			RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC,
  			&rpc_cb_add_xprt_call_ops, data);
  	put_rpccred(cred);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	rpc_put_task(task);
  	return 1;
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_test_and_add_xprt);
  
  /**
fda0ab411   Andy Adamson   SUNRPC: rpc_clnt_...
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
   * rpc_clnt_setup_test_and_add_xprt()
   *
   * This is an rpc_clnt_add_xprt setup() function which returns 1 so:
   *   1) caller of the test function must dereference the rpc_xprt_switch
   *   and the rpc_xprt.
   *   2) test function must call rpc_xprt_switch_add_xprt, usually in
   *   the rpc_call_done routine.
   *
   * Upon success (return of 1), the test function adds the new
   * transport to the rpc_clnt xprt switch
   *
   * @clnt: struct rpc_clnt to get the new transport
   * @xps:  the rpc_xprt_switch to hold the new transport
   * @xprt: the rpc_xprt to test
   * @data: a struct rpc_add_xprt_test pointer that holds the test function
   *        and test function call data
   */
  int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt,
  				     struct rpc_xprt_switch *xps,
  				     struct rpc_xprt *xprt,
  				     void *data)
  {
  	struct rpc_cred *cred;
  	struct rpc_task *task;
  	struct rpc_add_xprt_test *xtest = (struct rpc_add_xprt_test *)data;
  	int status = -EADDRINUSE;
  
  	xprt = xprt_get(xprt);
  	xprt_switch_get(xps);
  
  	if (rpc_xprt_switch_has_addr(xps, (struct sockaddr *)&xprt->addr))
  		goto out_err;
  
  	/* Test the connection */
  	cred = authnull_ops.lookup_cred(NULL, NULL, 0);
  	task = rpc_call_null_helper(clnt, xprt, cred,
  				    RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
  				    NULL, NULL);
  	put_rpccred(cred);
  	if (IS_ERR(task)) {
  		status = PTR_ERR(task);
  		goto out_err;
  	}
  	status = task->tk_status;
  	rpc_put_task(task);
  
  	if (status < 0)
  		goto out_err;
  
  	/* rpc_xprt_switch and rpc_xprt are deferrenced by add_xprt_test() */
  	xtest->add_xprt_test(clnt, xprt, xtest->data);
  
  	/* so that rpc_clnt_add_xprt does not call rpc_xprt_switch_add_xprt */
  	return 1;
  out_err:
  	xprt_put(xprt);
  	xprt_switch_put(xps);
  	pr_info("RPC:   rpc_clnt_test_xprt failed: %d addr %s not added
  ",
  		status, xprt->address_strings[RPC_DISPLAY_ADDR]);
  	return status;
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_setup_test_and_add_xprt);
  
  /**
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
   * rpc_clnt_add_xprt - Add a new transport to a rpc_clnt
   * @clnt: pointer to struct rpc_clnt
   * @xprtargs: pointer to struct xprt_create
   * @setup: callback to test and/or set up the connection
   * @data: pointer to setup function data
   *
   * Creates a new transport using the parameters set in args and
   * adds it to clnt.
   * If ping is set, then test that connectivity succeeds before
   * adding the new transport.
   *
   */
  int rpc_clnt_add_xprt(struct rpc_clnt *clnt,
  		struct xprt_create *xprtargs,
  		int (*setup)(struct rpc_clnt *,
  			struct rpc_xprt_switch *,
  			struct rpc_xprt *,
  			void *),
  		void *data)
  {
  	struct rpc_xprt_switch *xps;
  	struct rpc_xprt *xprt;
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2697
  	unsigned long connect_timeout;
3851f1cdb   Trond Myklebust   SUNRPC: Limit the...
2698
  	unsigned long reconnect_timeout;
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
  	unsigned char resvport;
  	int ret = 0;
  
  	rcu_read_lock();
  	xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
  	xprt = xprt_iter_xprt(&clnt->cl_xpi);
  	if (xps == NULL || xprt == NULL) {
  		rcu_read_unlock();
  		return -EAGAIN;
  	}
  	resvport = xprt->resvport;
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2710
  	connect_timeout = xprt->connect_timeout;
3851f1cdb   Trond Myklebust   SUNRPC: Limit the...
2711
  	reconnect_timeout = xprt->max_reconnect_timeout;
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2712
2713
2714
2715
2716
2717
2718
2719
  	rcu_read_unlock();
  
  	xprt = xprt_create_transport(xprtargs);
  	if (IS_ERR(xprt)) {
  		ret = PTR_ERR(xprt);
  		goto out_put_switch;
  	}
  	xprt->resvport = resvport;
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2720
2721
2722
2723
  	if (xprt->ops->set_connect_timeout != NULL)
  		xprt->ops->set_connect_timeout(xprt,
  				connect_timeout,
  				reconnect_timeout);
7f5548905   Trond Myklebust   SUNRPC: Allow add...
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
  
  	rpc_xprt_switch_set_roundrobin(xps);
  	if (setup) {
  		ret = setup(clnt, xps, xprt, data);
  		if (ret != 0)
  			goto out_put_xprt;
  	}
  	rpc_xprt_switch_add_xprt(xps, xprt);
  out_put_xprt:
  	xprt_put(xprt);
  out_put_switch:
  	xprt_switch_put(xps);
  	return ret;
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt);
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2739
2740
2741
2742
  struct connect_timeout_data {
  	unsigned long connect_timeout;
  	unsigned long reconnect_timeout;
  };
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2743
  static int
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2744
  rpc_xprt_set_connect_timeout(struct rpc_clnt *clnt,
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2745
2746
2747
  		struct rpc_xprt *xprt,
  		void *data)
  {
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2748
  	struct connect_timeout_data *timeo = data;
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2749

7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2750
2751
2752
2753
  	if (xprt->ops->set_connect_timeout)
  		xprt->ops->set_connect_timeout(xprt,
  				timeo->connect_timeout,
  				timeo->reconnect_timeout);
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2754
2755
2756
2757
  	return 0;
  }
  
  void
26ae102f2   Trond Myklebust   NFSv4: Set the co...
2758
2759
2760
  rpc_set_connect_timeout(struct rpc_clnt *clnt,
  		unsigned long connect_timeout,
  		unsigned long reconnect_timeout)
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2761
  {
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2762
  	struct connect_timeout_data timeout = {
26ae102f2   Trond Myklebust   NFSv4: Set the co...
2763
2764
  		.connect_timeout = connect_timeout,
  		.reconnect_timeout = reconnect_timeout,
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2765
  	};
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2766
  	rpc_clnt_iterate_for_each_xprt(clnt,
7196dbb02   Trond Myklebust   SUNRPC: Allow cha...
2767
2768
  			rpc_xprt_set_connect_timeout,
  			&timeout);
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2769
  }
26ae102f2   Trond Myklebust   NFSv4: Set the co...
2770
  EXPORT_SYMBOL_GPL(rpc_set_connect_timeout);
8d480326c   Trond Myklebust   NFSv4: Cap the tr...
2771

3b58a8a90   Andy Adamson   SUNRPC rpc_clnt_x...
2772
2773
  void rpc_clnt_xprt_switch_put(struct rpc_clnt *clnt)
  {
bb29dd843   Anna Schumaker   SUNRPC: Fix suspi...
2774
  	rcu_read_lock();
3b58a8a90   Andy Adamson   SUNRPC rpc_clnt_x...
2775
  	xprt_switch_put(rcu_dereference(clnt->cl_xpi.xpi_xpswitch));
bb29dd843   Anna Schumaker   SUNRPC: Fix suspi...
2776
  	rcu_read_unlock();
3b58a8a90   Andy Adamson   SUNRPC rpc_clnt_x...
2777
2778
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_put);
dd6917176   Andy Adamson   SUNRPC rpc_clnt_x...
2779
2780
  void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt)
  {
bb29dd843   Anna Schumaker   SUNRPC: Fix suspi...
2781
  	rcu_read_lock();
dd6917176   Andy Adamson   SUNRPC rpc_clnt_x...
2782
2783
  	rpc_xprt_switch_add_xprt(rcu_dereference(clnt->cl_xpi.xpi_xpswitch),
  				 xprt);
bb29dd843   Anna Schumaker   SUNRPC: Fix suspi...
2784
  	rcu_read_unlock();
dd6917176   Andy Adamson   SUNRPC rpc_clnt_x...
2785
2786
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_add_xprt);
39e5d2df9   Andy Adamson   SUNRPC search xpr...
2787
2788
2789
2790
2791
  bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
  				   const struct sockaddr *sap)
  {
  	struct rpc_xprt_switch *xps;
  	bool ret;
39e5d2df9   Andy Adamson   SUNRPC search xpr...
2792
  	rcu_read_lock();
bb29dd843   Anna Schumaker   SUNRPC: Fix suspi...
2793
  	xps = rcu_dereference(clnt->cl_xpi.xpi_xpswitch);
39e5d2df9   Andy Adamson   SUNRPC search xpr...
2794
2795
2796
2797
2798
  	ret = rpc_xprt_switch_has_addr(xps, sap);
  	rcu_read_unlock();
  	return ret;
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_xprt_switch_has_addr);
f895b252d   Jeff Layton   sunrpc: eliminate...
2799
  #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
68a23ee94   Chuck Lever   SUNRPC: Don't dis...
2800
2801
  static void rpc_show_header(void)
  {
cb3997b5a   Chuck Lever   SUNRPC: Display s...
2802
2803
2804
  	printk(KERN_INFO "-pid- flgs status -client- --rqstp- "
  		"-timeout ---ops--
  ");
68a23ee94   Chuck Lever   SUNRPC: Don't dis...
2805
  }
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2806
2807
2808
2809
  static void rpc_show_task(const struct rpc_clnt *clnt,
  			  const struct rpc_task *task)
  {
  	const char *rpc_waitq = "none";
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2810
2811
2812
  
  	if (RPC_IS_QUEUED(task))
  		rpc_waitq = rpc_qname(task->tk_waitqueue);
b3bcedadf   Joe Perches   net/sunrpc/clnt.c...
2813
2814
  	printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s
  ",
cb3997b5a   Chuck Lever   SUNRPC: Display s...
2815
2816
  		task->tk_pid, task->tk_flags, task->tk_status,
  		clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops,
55909f21a   Trond Myklebust   SUNRPC: Deprecate...
2817
  		clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
b3bcedadf   Joe Perches   net/sunrpc/clnt.c...
2818
  		task->tk_action, rpc_waitq);
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2819
  }
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
2820
  void rpc_show_tasks(struct net *net)
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2821
2822
  {
  	struct rpc_clnt *clnt;
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2823
  	struct rpc_task *task;
68a23ee94   Chuck Lever   SUNRPC: Don't dis...
2824
  	int header = 0;
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
2825
  	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2826

70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
2827
2828
  	spin_lock(&sn->rpc_client_lock);
  	list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2829
  		spin_lock(&clnt->cl_lock);
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2830
  		list_for_each_entry(task, &clnt->cl_tasks, tk_task) {
68a23ee94   Chuck Lever   SUNRPC: Don't dis...
2831
2832
2833
2834
  			if (!header) {
  				rpc_show_header();
  				header++;
  			}
38e886e0c   Chuck Lever   SUNRPC: Refactor ...
2835
  			rpc_show_task(clnt, task);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2836
2837
2838
  		}
  		spin_unlock(&clnt->cl_lock);
  	}
70abc49b4   Stanislav Kinsbursky   SUNRPC: make SUNP...
2839
  	spin_unlock(&sn->rpc_client_lock);
188fef11d   Trond Myklebust   SUNRPC: Move rpc_...
2840
2841
  }
  #endif
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
2842
2843
  
  #if IS_ENABLED(CONFIG_SUNRPC_SWAP)
15001e5a7   Trond Myklebust   SUNRPC: Make NFS ...
2844
2845
2846
2847
2848
2849
2850
  static int
  rpc_clnt_swap_activate_callback(struct rpc_clnt *clnt,
  		struct rpc_xprt *xprt,
  		void *dummy)
  {
  	return xprt_enable_swap(xprt);
  }
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
2851
2852
2853
  int
  rpc_clnt_swap_activate(struct rpc_clnt *clnt)
  {
15001e5a7   Trond Myklebust   SUNRPC: Make NFS ...
2854
2855
2856
2857
  	if (atomic_inc_return(&clnt->cl_swapper) == 1)
  		return rpc_clnt_iterate_for_each_xprt(clnt,
  				rpc_clnt_swap_activate_callback, NULL);
  	return 0;
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
2858
2859
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate);
15001e5a7   Trond Myklebust   SUNRPC: Make NFS ...
2860
2861
2862
2863
2864
2865
2866
2867
  static int
  rpc_clnt_swap_deactivate_callback(struct rpc_clnt *clnt,
  		struct rpc_xprt *xprt,
  		void *dummy)
  {
  	xprt_disable_swap(xprt);
  	return 0;
  }
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
2868
2869
2870
  void
  rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
  {
15001e5a7   Trond Myklebust   SUNRPC: Make NFS ...
2871
2872
2873
  	if (atomic_dec_if_positive(&clnt->cl_swapper) == 0)
  		rpc_clnt_iterate_for_each_xprt(clnt,
  				rpc_clnt_swap_deactivate_callback, NULL);
3c87ef6ef   Jeff Layton   sunrpc: keep a co...
2874
2875
2876
  }
  EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
  #endif /* CONFIG_SUNRPC_SWAP */