Blame view

fs/afs/cmservice.c 13.2 KB
ec26815ad   David Howells   [AFS]: Clean up t...
1
  /* AFS Cache Manager Service
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
   *
   * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version
   * 2 of the License, or (at your option) any later version.
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/sched.h>
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
16
  #include <linux/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include "internal.h"
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
18
  #include "afs_cm.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

c1206a2c6   Adrian Bunk   fs/afs/: possible...
20
  #if 0
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
21
  struct workqueue_struct *afs_cm_workqueue;
c1206a2c6   Adrian Bunk   fs/afs/: possible...
22
  #endif  /*  0  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
24
25
  static int afs_deliver_cb_init_call_back_state(struct afs_call *,
  					       struct sk_buff *, bool);
c35eccb1f   David Howells   [AFS]: Implement ...
26
27
  static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
  						struct sk_buff *, bool);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
28
29
  static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
  static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
9396d496d   David Howells   afs: support the ...
30
  static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
7c80bcce3   David Howells   afs: the AFS RPC ...
31
32
  static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
  						 struct sk_buff *, bool);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
33
  static void afs_cm_destructor(struct afs_call *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
36
   * CB.CallBack operation type
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
38
  static const struct afs_call_type afs_SRXCBCallBack = {
00d3b7a45   David Howells   [AFS]: Add securi...
39
  	.name		= "CB.CallBack",
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
40
41
42
43
  	.deliver	= afs_deliver_cb_callback,
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
46
   * CB.InitCallBackState operation type
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
48
  static const struct afs_call_type afs_SRXCBInitCallBackState = {
00d3b7a45   David Howells   [AFS]: Add securi...
49
  	.name		= "CB.InitCallBackState",
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
50
51
52
53
  	.deliver	= afs_deliver_cb_init_call_back_state,
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  /*
c35eccb1f   David Howells   [AFS]: Implement ...
56
57
58
59
60
61
62
63
64
65
   * CB.InitCallBackState3 operation type
   */
  static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
  	.name		= "CB.InitCallBackState3",
  	.deliver	= afs_deliver_cb_init_call_back_state3,
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
  
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
66
   * CB.Probe operation type
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
68
  static const struct afs_call_type afs_SRXCBProbe = {
00d3b7a45   David Howells   [AFS]: Add securi...
69
  	.name		= "CB.Probe",
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
70
71
72
73
  	.deliver	= afs_deliver_cb_probe,
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  /*
9396d496d   David Howells   afs: support the ...
76
77
78
79
80
81
82
83
84
85
   * CB.ProbeUuid operation type
   */
  static const struct afs_call_type afs_SRXCBProbeUuid = {
  	.name		= "CB.ProbeUuid",
  	.deliver	= afs_deliver_cb_probe_uuid,
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
  
  /*
7c80bcce3   David Howells   afs: the AFS RPC ...
86
   * CB.TellMeAboutYourself operation type
b908fe6b2   David Howells   [AFS]: Add suppor...
87
   */
7c80bcce3   David Howells   afs: the AFS RPC ...
88
89
90
  static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
  	.name		= "CB.TellMeAboutYourself",
  	.deliver	= afs_deliver_cb_tell_me_about_yourself,
b908fe6b2   David Howells   [AFS]: Add suppor...
91
92
93
94
95
  	.abort_to_error	= afs_abort_to_error,
  	.destructor	= afs_cm_destructor,
  };
  
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
96
97
   * route an incoming cache manager call
   * - return T if supported, F if not
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
99
  bool afs_cm_incoming_call(struct afs_call *call)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
101
102
103
104
105
106
107
108
109
110
111
  	u32 operation_id = ntohl(call->operation_ID);
  
  	_enter("{CB.OP %u}", operation_id);
  
  	switch (operation_id) {
  	case CBCallBack:
  		call->type = &afs_SRXCBCallBack;
  		return true;
  	case CBInitCallBackState:
  		call->type = &afs_SRXCBInitCallBackState;
  		return true;
c35eccb1f   David Howells   [AFS]: Implement ...
112
113
114
  	case CBInitCallBackState3:
  		call->type = &afs_SRXCBInitCallBackState3;
  		return true;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
115
116
117
  	case CBProbe:
  		call->type = &afs_SRXCBProbe;
  		return true;
7c80bcce3   David Howells   afs: the AFS RPC ...
118
119
  	case CBTellMeAboutYourself:
  		call->type = &afs_SRXCBTellMeAboutYourself;
b908fe6b2   David Howells   [AFS]: Add suppor...
120
  		return true;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
121
122
  	default:
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  	}
ec26815ad   David Howells   [AFS]: Clean up t...
124
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
127
   * clean up a cache manager call
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
129
  static void afs_cm_destructor(struct afs_call *call)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
131
132
133
134
135
136
  	_enter("");
  
  	afs_put_server(call->server);
  	call->server = NULL;
  	kfree(call->buffer);
  	call->buffer = NULL;
ec26815ad   David Howells   [AFS]: Clean up t...
137
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
140
   * allow the fileserver to see if the cache manager is still alive
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
142
  static void SRXAFSCB_CallBack(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
144
  	struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
146
  	_enter("");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
148
149
150
151
152
153
  	/* be sure to send the reply *before* attempting to spam the AFS server
  	 * with FSFetchStatus requests on the vnodes with broken callbacks lest
  	 * the AFS server get into a vicious cycle of trying to break further
  	 * callbacks because it hadn't received completion of the CBCallBack op
  	 * yet */
  	afs_send_empty_reply(call);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
155
156
  	afs_break_callbacks(call->server, call->count, call->request);
  	_leave("");
ec26815ad   David Howells   [AFS]: Clean up t...
157
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
160
   * deliver request data to a CB.CallBack call
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
162
163
  static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
  				   bool last)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  	struct afs_callback *cb;
  	struct afs_server *server;
  	struct in_addr addr;
  	__be32 *bp;
  	u32 tmp;
  	int ret, loop;
  
  	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
  
  	switch (call->unmarshall) {
  	case 0:
  		call->offset = 0;
  		call->unmarshall++;
  
  		/* extract the FID array and its count in two steps */
  	case 1:
  		_debug("extract FID count");
  		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
  		switch (ret) {
  		case 0:		break;
  		case -EAGAIN:	return 0;
  		default:	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  		call->count = ntohl(call->tmp);
  		_debug("FID count: %u", call->count);
  		if (call->count > AFSCBMAX)
  			return -EBADMSG;
  
  		call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
  		if (!call->buffer)
  			return -ENOMEM;
  		call->offset = 0;
  		call->unmarshall++;
  
  	case 2:
  		_debug("extract FID array");
  		ret = afs_extract_data(call, skb, last, call->buffer,
  				       call->count * 3 * 4);
  		switch (ret) {
  		case 0:		break;
  		case -EAGAIN:	return 0;
  		default:	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  		_debug("unmarshall FID array");
  		call->request = kcalloc(call->count,
  					sizeof(struct afs_callback),
  					GFP_KERNEL);
  		if (!call->request)
  			return -ENOMEM;
  
  		cb = call->request;
  		bp = call->buffer;
  		for (loop = call->count; loop > 0; loop--, cb++) {
  			cb->fid.vid	= ntohl(*bp++);
  			cb->fid.vnode	= ntohl(*bp++);
  			cb->fid.unique	= ntohl(*bp++);
  			cb->type	= AFSCM_CB_UNTYPED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  		}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
225
226
227
228
229
230
231
232
233
234
235
236
  		call->offset = 0;
  		call->unmarshall++;
  
  		/* extract the callback array and its count in two steps */
  	case 3:
  		_debug("extract CB count");
  		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
  		switch (ret) {
  		case 0:		break;
  		case -EAGAIN:	return 0;
  		default:	return ret;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  		tmp = ntohl(call->tmp);
  		_debug("CB count: %u", tmp);
  		if (tmp != call->count && tmp != 0)
  			return -EBADMSG;
  		call->offset = 0;
  		call->unmarshall++;
  		if (tmp == 0)
  			goto empty_cb_array;
  
  	case 4:
  		_debug("extract CB array");
  		ret = afs_extract_data(call, skb, last, call->request,
  				       call->count * 3 * 4);
  		switch (ret) {
  		case 0:		break;
  		case -EAGAIN:	return 0;
  		default:	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
257
258
259
260
261
262
263
264
  		_debug("unmarshall CB array");
  		cb = call->request;
  		bp = call->buffer;
  		for (loop = call->count; loop > 0; loop--, cb++) {
  			cb->version	= ntohl(*bp++);
  			cb->expiry	= ntohl(*bp++);
  			cb->type	= ntohl(*bp++);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
266
267
268
  	empty_cb_array:
  		call->offset = 0;
  		call->unmarshall++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
270
271
272
273
  	case 5:
  		_debug("trailer");
  		if (skb->len != 0)
  			return -EBADMSG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
  		break;
  	}
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
276
277
  	if (!last)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
279
  	call->state = AFS_CALL_REPLYING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
281
282
283
284
285
286
287
288
289
  	/* we'll need the file server record as that tells us which set of
  	 * vnodes to operate upon */
  	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
  	server = afs_find_server(&addr);
  	if (!server)
  		return -ENOTCONN;
  	call->server = server;
  
  	INIT_WORK(&call->work, SRXAFSCB_CallBack);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
290
  	queue_work(afs_wq, &call->work);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
291
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
292
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
295
   * allow the fileserver to request callback state (re-)initialisation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
297
  static void SRXAFSCB_InitCallBackState(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  {
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
299
  	struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
301
  	_enter("{%p}", call->server);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
303
304
305
  	afs_init_callback_state(call->server);
  	afs_send_empty_reply(call);
  	_leave("");
ec26815ad   David Howells   [AFS]: Clean up t...
306
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
309
   * deliver request data to a CB.InitCallBackState call
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
   */
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
311
312
313
  static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
  					       struct sk_buff *skb,
  					       bool last)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
  {
  	struct afs_server *server;
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
316
  	struct in_addr addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
318
  	_enter(",{%u},%d", skb->len, last);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
320
321
322
323
  	if (skb->len > 0)
  		return -EBADMSG;
  	if (!last)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
325
326
  	/* no unmarshalling required */
  	call->state = AFS_CALL_REPLYING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
328
329
330
331
332
333
334
  	/* we'll need the file server record as that tells us which set of
  	 * vnodes to operate upon */
  	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
  	server = afs_find_server(&addr);
  	if (!server)
  		return -ENOTCONN;
  	call->server = server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
336
  	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
337
  	queue_work(afs_wq, &call->work);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
338
339
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
341
  /*
c35eccb1f   David Howells   [AFS]: Implement ...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
   * deliver request data to a CB.InitCallBackState3 call
   */
  static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,
  						struct sk_buff *skb,
  						bool last)
  {
  	struct afs_server *server;
  	struct in_addr addr;
  
  	_enter(",{%u},%d", skb->len, last);
  
  	if (!last)
  		return 0;
  
  	/* no unmarshalling required */
  	call->state = AFS_CALL_REPLYING;
  
  	/* we'll need the file server record as that tells us which set of
  	 * vnodes to operate upon */
  	memcpy(&addr, &ip_hdr(skb)->saddr, 4);
  	server = afs_find_server(&addr);
  	if (!server)
  		return -ENOTCONN;
  	call->server = server;
  
  	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
368
  	queue_work(afs_wq, &call->work);
c35eccb1f   David Howells   [AFS]: Implement ...
369
370
371
372
  	return 0;
  }
  
  /*
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
373
374
375
376
377
   * allow the fileserver to see if the cache manager is still alive
   */
  static void SRXAFSCB_Probe(struct work_struct *work)
  {
  	struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
379
380
381
382
  	_enter("");
  	afs_send_empty_reply(call);
  	_leave("");
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
384
385
386
387
388
389
390
  /*
   * deliver request data to a CB.Probe call
   */
  static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
  				bool last)
  {
  	_enter(",{%u},%d", skb->len, last);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
392
393
394
395
  	if (skb->len > 0)
  		return -EBADMSG;
  	if (!last)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
397
398
  	/* no unmarshalling required */
  	call->state = AFS_CALL_REPLYING;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399

08e0e7c82   David Howells   [AF_RXRPC]: Make ...
400
  	INIT_WORK(&call->work, SRXAFSCB_Probe);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
401
  	queue_work(afs_wq, &call->work);
08e0e7c82   David Howells   [AF_RXRPC]: Make ...
402
  	return 0;
ec26815ad   David Howells   [AFS]: Clean up t...
403
  }
b908fe6b2   David Howells   [AFS]: Add suppor...
404
405
  
  /*
9396d496d   David Howells   afs: support the ...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
   * allow the fileserver to quickly find out if the fileserver has been rebooted
   */
  static void SRXAFSCB_ProbeUuid(struct work_struct *work)
  {
  	struct afs_call *call = container_of(work, struct afs_call, work);
  	struct afs_uuid *r = call->request;
  
  	struct {
  		__be32	match;
  	} reply;
  
  	_enter("");
  
  
  	if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
  		reply.match = htonl(0);
  	else
  		reply.match = htonl(1);
  
  	afs_send_simple_reply(call, &reply, sizeof(reply));
  	_leave("");
  }
  
  /*
   * deliver request data to a CB.ProbeUuid call
   */
  static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
  				     bool last)
  {
  	struct afs_uuid *r;
  	unsigned loop;
  	__be32 *b;
  	int ret;
  
  	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
  
  	if (skb->len > 0)
  		return -EBADMSG;
  	if (!last)
  		return 0;
  
  	switch (call->unmarshall) {
  	case 0:
  		call->offset = 0;
  		call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
  		if (!call->buffer)
  			return -ENOMEM;
  		call->unmarshall++;
  
  	case 1:
  		_debug("extract UUID");
  		ret = afs_extract_data(call, skb, last, call->buffer,
  				       11 * sizeof(__be32));
  		switch (ret) {
  		case 0:		break;
  		case -EAGAIN:	return 0;
  		default:	return ret;
  		}
  
  		_debug("unmarshall UUID");
  		call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
  		if (!call->request)
  			return -ENOMEM;
  
  		b = call->buffer;
  		r = call->request;
  		r->time_low			= ntohl(b[0]);
  		r->time_mid			= ntohl(b[1]);
  		r->time_hi_and_version		= ntohl(b[2]);
  		r->clock_seq_hi_and_reserved 	= ntohl(b[3]);
  		r->clock_seq_low		= ntohl(b[4]);
  
  		for (loop = 0; loop < 6; loop++)
  			r->node[loop] = ntohl(b[loop + 5]);
  
  		call->offset = 0;
  		call->unmarshall++;
  
  	case 2:
  		_debug("trailer");
  		if (skb->len != 0)
  			return -EBADMSG;
  		break;
  	}
  
  	if (!last)
  		return 0;
  
  	call->state = AFS_CALL_REPLYING;
  
  	INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
497
  	queue_work(afs_wq, &call->work);
9396d496d   David Howells   afs: support the ...
498
499
500
501
  	return 0;
  }
  
  /*
b908fe6b2   David Howells   [AFS]: Add suppor...
502
503
   * allow the fileserver to ask about the cache manager's capabilities
   */
7c80bcce3   David Howells   afs: the AFS RPC ...
504
  static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
b908fe6b2   David Howells   [AFS]: Add suppor...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  {
  	struct afs_interface *ifs;
  	struct afs_call *call = container_of(work, struct afs_call, work);
  	int loop, nifs;
  
  	struct {
  		struct /* InterfaceAddr */ {
  			__be32 nifs;
  			__be32 uuid[11];
  			__be32 ifaddr[32];
  			__be32 netmask[32];
  			__be32 mtu[32];
  		} ia;
  		struct /* Capabilities */ {
  			__be32 capcount;
  			__be32 caps[1];
  		} cap;
  	} reply;
  
  	_enter("");
  
  	nifs = 0;
  	ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL);
  	if (ifs) {
  		nifs = afs_get_ipv4_interfaces(ifs, 32, false);
  		if (nifs < 0) {
  			kfree(ifs);
  			ifs = NULL;
  			nifs = 0;
  		}
  	}
  
  	memset(&reply, 0, sizeof(reply));
  	reply.ia.nifs = htonl(nifs);
  
  	reply.ia.uuid[0] = htonl(afs_uuid.time_low);
  	reply.ia.uuid[1] = htonl(afs_uuid.time_mid);
  	reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version);
  	reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved);
  	reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low);
  	for (loop = 0; loop < 6; loop++)
  		reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]);
  
  	if (ifs) {
  		for (loop = 0; loop < nifs; loop++) {
  			reply.ia.ifaddr[loop] = ifs[loop].address.s_addr;
  			reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
  			reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
  		}
5b35fad9d   Patrick McHardy   [AFS]: Fix memory...
554
  		kfree(ifs);
b908fe6b2   David Howells   [AFS]: Add suppor...
555
556
557
558
559
560
561
562
563
564
  	}
  
  	reply.cap.capcount = htonl(1);
  	reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
  	afs_send_simple_reply(call, &reply, sizeof(reply));
  
  	_leave("");
  }
  
  /*
7c80bcce3   David Howells   afs: the AFS RPC ...
565
   * deliver request data to a CB.TellMeAboutYourself call
b908fe6b2   David Howells   [AFS]: Add suppor...
566
   */
7c80bcce3   David Howells   afs: the AFS RPC ...
567
568
  static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
  						 struct sk_buff *skb, bool last)
b908fe6b2   David Howells   [AFS]: Add suppor...
569
570
571
572
573
574
575
576
577
578
  {
  	_enter(",{%u},%d", skb->len, last);
  
  	if (skb->len > 0)
  		return -EBADMSG;
  	if (!last)
  		return 0;
  
  	/* no unmarshalling required */
  	call->state = AFS_CALL_REPLYING;
7c80bcce3   David Howells   afs: the AFS RPC ...
579
  	INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
0ad53eeef   Tejun Heo   afs: add afs_wq a...
580
  	queue_work(afs_wq, &call->work);
b908fe6b2   David Howells   [AFS]: Add suppor...
581
582
  	return 0;
  }