xref: /linux/fs/afs/fsclient.c (revision eb2bce7f5e7ac1ca6da434461217fadf3c688d2c)
1 /* AFS File Server client stubs
2  *
3  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  */
11 
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/circ_buf.h>
15 #include "internal.h"
16 #include "afs_fs.h"
17 
18 /*
19  * decode an AFSFid block
20  */
21 static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
22 {
23 	const __be32 *bp = *_bp;
24 
25 	fid->vid		= ntohl(*bp++);
26 	fid->vnode		= ntohl(*bp++);
27 	fid->unique		= ntohl(*bp++);
28 	*_bp = bp;
29 }
30 
31 /*
32  * decode an AFSFetchStatus block
33  */
34 static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
35 				      struct afs_file_status *status,
36 				      struct afs_vnode *vnode)
37 {
38 	const __be32 *bp = *_bp;
39 	umode_t mode;
40 	u64 data_version, size;
41 	u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
42 
43 #define EXTRACT(DST)				\
44 	do {					\
45 		u32 x = ntohl(*bp++);		\
46 		changed |= DST - x;		\
47 		DST = x;			\
48 	} while (0)
49 
50 	status->if_version = ntohl(*bp++);
51 	EXTRACT(status->type);
52 	EXTRACT(status->nlink);
53 	size = ntohl(*bp++);
54 	data_version = ntohl(*bp++);
55 	EXTRACT(status->author);
56 	EXTRACT(status->owner);
57 	EXTRACT(status->caller_access); /* call ticket dependent */
58 	EXTRACT(status->anon_access);
59 	EXTRACT(status->mode);
60 	EXTRACT(status->parent.vnode);
61 	EXTRACT(status->parent.unique);
62 	bp++; /* seg size */
63 	status->mtime_client = ntohl(*bp++);
64 	status->mtime_server = ntohl(*bp++);
65 	EXTRACT(status->group);
66 	bp++; /* sync counter */
67 	data_version |= (u64) ntohl(*bp++) << 32;
68 	bp++; /* lock count */
69 	size |= (u64) ntohl(*bp++) << 32;
70 	bp++; /* spare 4 */
71 	*_bp = bp;
72 
73 	if (size != status->size) {
74 		status->size = size;
75 		changed |= true;
76 	}
77 	status->mode &= S_IALLUGO;
78 
79 	_debug("vnode time %lx, %lx",
80 	       status->mtime_client, status->mtime_server);
81 
82 	if (vnode) {
83 		status->parent.vid = vnode->fid.vid;
84 		if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
85 			_debug("vnode changed");
86 			i_size_write(&vnode->vfs_inode, size);
87 			vnode->vfs_inode.i_uid = status->owner;
88 			vnode->vfs_inode.i_gid = status->group;
89 			vnode->vfs_inode.i_version = vnode->fid.unique;
90 			vnode->vfs_inode.i_nlink = status->nlink;
91 
92 			mode = vnode->vfs_inode.i_mode;
93 			mode &= ~S_IALLUGO;
94 			mode |= status->mode;
95 			barrier();
96 			vnode->vfs_inode.i_mode = mode;
97 		}
98 
99 		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server;
100 		vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime;
101 		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime;
102 	}
103 
104 	if (status->data_version != data_version) {
105 		status->data_version = data_version;
106 		if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
107 			_debug("vnode modified %llx on {%x:%u}",
108 			       (unsigned long long) data_version,
109 			       vnode->fid.vid, vnode->fid.vnode);
110 			set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
111 			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
112 		}
113 	}
114 }
115 
116 /*
117  * decode an AFSCallBack block
118  */
119 static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
120 {
121 	const __be32 *bp = *_bp;
122 
123 	vnode->cb_version	= ntohl(*bp++);
124 	vnode->cb_expiry	= ntohl(*bp++);
125 	vnode->cb_type		= ntohl(*bp++);
126 	vnode->cb_expires	= vnode->cb_expiry + get_seconds();
127 	*_bp = bp;
128 }
129 
130 static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
131 				       struct afs_callback *cb)
132 {
133 	const __be32 *bp = *_bp;
134 
135 	cb->version	= ntohl(*bp++);
136 	cb->expiry	= ntohl(*bp++);
137 	cb->type	= ntohl(*bp++);
138 	*_bp = bp;
139 }
140 
141 /*
142  * decode an AFSVolSync block
143  */
144 static void xdr_decode_AFSVolSync(const __be32 **_bp,
145 				  struct afs_volsync *volsync)
146 {
147 	const __be32 *bp = *_bp;
148 
149 	volsync->creation = ntohl(*bp++);
150 	bp++; /* spare2 */
151 	bp++; /* spare3 */
152 	bp++; /* spare4 */
153 	bp++; /* spare5 */
154 	bp++; /* spare6 */
155 	*_bp = bp;
156 }
157 
158 /*
159  * deliver reply data to an FS.FetchStatus
160  */
161 static int afs_deliver_fs_fetch_status(struct afs_call *call,
162 				       struct sk_buff *skb, bool last)
163 {
164 	struct afs_vnode *vnode = call->reply;
165 	const __be32 *bp;
166 
167 	_enter(",,%u", last);
168 
169 	afs_transfer_reply(call, skb);
170 	if (!last)
171 		return 0;
172 
173 	if (call->reply_size != call->reply_max)
174 		return -EBADMSG;
175 
176 	/* unmarshall the reply once we've received all of it */
177 	bp = call->buffer;
178 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
179 	xdr_decode_AFSCallBack(&bp, vnode);
180 	if (call->reply2)
181 		xdr_decode_AFSVolSync(&bp, call->reply2);
182 
183 	_leave(" = 0 [done]");
184 	return 0;
185 }
186 
187 /*
188  * FS.FetchStatus operation type
189  */
190 static const struct afs_call_type afs_RXFSFetchStatus = {
191 	.name		= "FS.FetchStatus",
192 	.deliver	= afs_deliver_fs_fetch_status,
193 	.abort_to_error	= afs_abort_to_error,
194 	.destructor	= afs_flat_call_destructor,
195 };
196 
197 /*
198  * fetch the status information for a file
199  */
200 int afs_fs_fetch_file_status(struct afs_server *server,
201 			     struct key *key,
202 			     struct afs_vnode *vnode,
203 			     struct afs_volsync *volsync,
204 			     const struct afs_wait_mode *wait_mode)
205 {
206 	struct afs_call *call;
207 	__be32 *bp;
208 
209 	_enter(",%x,{%x:%d},,",
210 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
211 
212 	call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
213 	if (!call)
214 		return -ENOMEM;
215 
216 	call->key = key;
217 	call->reply = vnode;
218 	call->reply2 = volsync;
219 	call->service_id = FS_SERVICE;
220 	call->port = htons(AFS_FS_PORT);
221 
222 	/* marshall the parameters */
223 	bp = call->request;
224 	bp[0] = htonl(FSFETCHSTATUS);
225 	bp[1] = htonl(vnode->fid.vid);
226 	bp[2] = htonl(vnode->fid.vnode);
227 	bp[3] = htonl(vnode->fid.unique);
228 
229 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
230 }
231 
232 /*
233  * deliver reply data to an FS.FetchData
234  */
235 static int afs_deliver_fs_fetch_data(struct afs_call *call,
236 				     struct sk_buff *skb, bool last)
237 {
238 	struct afs_vnode *vnode = call->reply;
239 	const __be32 *bp;
240 	struct page *page;
241 	void *buffer;
242 	int ret;
243 
244 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
245 
246 	switch (call->unmarshall) {
247 	case 0:
248 		call->offset = 0;
249 		call->unmarshall++;
250 
251 		/* extract the returned data length */
252 	case 1:
253 		_debug("extract data length");
254 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
255 		switch (ret) {
256 		case 0:		break;
257 		case -EAGAIN:	return 0;
258 		default:	return ret;
259 		}
260 
261 		call->count = ntohl(call->tmp);
262 		_debug("DATA length: %u", call->count);
263 		if (call->count > PAGE_SIZE)
264 			return -EBADMSG;
265 		call->offset = 0;
266 		call->unmarshall++;
267 
268 		if (call->count < PAGE_SIZE) {
269 			page = call->reply3;
270 			buffer = kmap_atomic(page, KM_USER0);
271 			memset(buffer + PAGE_SIZE - call->count, 0,
272 			       call->count);
273 			kunmap_atomic(buffer, KM_USER0);
274 		}
275 
276 		/* extract the returned data */
277 	case 2:
278 		_debug("extract data");
279 		page = call->reply3;
280 		buffer = kmap_atomic(page, KM_USER0);
281 		ret = afs_extract_data(call, skb, last, buffer, call->count);
282 		kunmap_atomic(buffer, KM_USER0);
283 		switch (ret) {
284 		case 0:		break;
285 		case -EAGAIN:	return 0;
286 		default:	return ret;
287 		}
288 
289 		call->offset = 0;
290 		call->unmarshall++;
291 
292 		/* extract the metadata */
293 	case 3:
294 		ret = afs_extract_data(call, skb, last, call->buffer,
295 				       (21 + 3 + 6) * 4);
296 		switch (ret) {
297 		case 0:		break;
298 		case -EAGAIN:	return 0;
299 		default:	return ret;
300 		}
301 
302 		bp = call->buffer;
303 		xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
304 		xdr_decode_AFSCallBack(&bp, vnode);
305 		if (call->reply2)
306 			xdr_decode_AFSVolSync(&bp, call->reply2);
307 
308 		call->offset = 0;
309 		call->unmarshall++;
310 
311 	case 4:
312 		_debug("trailer");
313 		if (skb->len != 0)
314 			return -EBADMSG;
315 		break;
316 	}
317 
318 	if (!last)
319 		return 0;
320 
321 	_leave(" = 0 [done]");
322 	return 0;
323 }
324 
325 /*
326  * FS.FetchData operation type
327  */
328 static const struct afs_call_type afs_RXFSFetchData = {
329 	.name		= "FS.FetchData",
330 	.deliver	= afs_deliver_fs_fetch_data,
331 	.abort_to_error	= afs_abort_to_error,
332 	.destructor	= afs_flat_call_destructor,
333 };
334 
335 /*
336  * fetch data from a file
337  */
338 int afs_fs_fetch_data(struct afs_server *server,
339 		      struct key *key,
340 		      struct afs_vnode *vnode,
341 		      off_t offset, size_t length,
342 		      struct page *buffer,
343 		      const struct afs_wait_mode *wait_mode)
344 {
345 	struct afs_call *call;
346 	__be32 *bp;
347 
348 	_enter("");
349 
350 	call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
351 	if (!call)
352 		return -ENOMEM;
353 
354 	call->key = key;
355 	call->reply = vnode;
356 	call->reply2 = NULL; /* volsync */
357 	call->reply3 = buffer;
358 	call->service_id = FS_SERVICE;
359 	call->port = htons(AFS_FS_PORT);
360 
361 	/* marshall the parameters */
362 	bp = call->request;
363 	bp[0] = htonl(FSFETCHDATA);
364 	bp[1] = htonl(vnode->fid.vid);
365 	bp[2] = htonl(vnode->fid.vnode);
366 	bp[3] = htonl(vnode->fid.unique);
367 	bp[4] = htonl(offset);
368 	bp[5] = htonl(length);
369 
370 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
371 }
372 
373 /*
374  * deliver reply data to an FS.GiveUpCallBacks
375  */
376 static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
377 					    struct sk_buff *skb, bool last)
378 {
379 	_enter(",{%u},%d", skb->len, last);
380 
381 	if (skb->len > 0)
382 		return -EBADMSG; /* shouldn't be any reply data */
383 	return 0;
384 }
385 
386 /*
387  * FS.GiveUpCallBacks operation type
388  */
389 static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
390 	.name		= "FS.GiveUpCallBacks",
391 	.deliver	= afs_deliver_fs_give_up_callbacks,
392 	.abort_to_error	= afs_abort_to_error,
393 	.destructor	= afs_flat_call_destructor,
394 };
395 
396 /*
397  * give up a set of callbacks
398  * - the callbacks are held in the server->cb_break ring
399  */
400 int afs_fs_give_up_callbacks(struct afs_server *server,
401 			     const struct afs_wait_mode *wait_mode)
402 {
403 	struct afs_call *call;
404 	size_t ncallbacks;
405 	__be32 *bp, *tp;
406 	int loop;
407 
408 	ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
409 			      ARRAY_SIZE(server->cb_break));
410 
411 	_enter("{%zu},", ncallbacks);
412 
413 	if (ncallbacks == 0)
414 		return 0;
415 	if (ncallbacks > AFSCBMAX)
416 		ncallbacks = AFSCBMAX;
417 
418 	_debug("break %zu callbacks", ncallbacks);
419 
420 	call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
421 				   12 + ncallbacks * 6 * 4, 0);
422 	if (!call)
423 		return -ENOMEM;
424 
425 	call->service_id = FS_SERVICE;
426 	call->port = htons(AFS_FS_PORT);
427 
428 	/* marshall the parameters */
429 	bp = call->request;
430 	tp = bp + 2 + ncallbacks * 3;
431 	*bp++ = htonl(FSGIVEUPCALLBACKS);
432 	*bp++ = htonl(ncallbacks);
433 	*tp++ = htonl(ncallbacks);
434 
435 	atomic_sub(ncallbacks, &server->cb_break_n);
436 	for (loop = ncallbacks; loop > 0; loop--) {
437 		struct afs_callback *cb =
438 			&server->cb_break[server->cb_break_tail];
439 
440 		*bp++ = htonl(cb->fid.vid);
441 		*bp++ = htonl(cb->fid.vnode);
442 		*bp++ = htonl(cb->fid.unique);
443 		*tp++ = htonl(cb->version);
444 		*tp++ = htonl(cb->expiry);
445 		*tp++ = htonl(cb->type);
446 		smp_mb();
447 		server->cb_break_tail =
448 			(server->cb_break_tail + 1) &
449 			(ARRAY_SIZE(server->cb_break) - 1);
450 	}
451 
452 	ASSERT(ncallbacks > 0);
453 	wake_up_nr(&server->cb_break_waitq, ncallbacks);
454 
455 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
456 }
457 
458 /*
459  * deliver reply data to an FS.CreateFile or an FS.MakeDir
460  */
461 static int afs_deliver_fs_create_vnode(struct afs_call *call,
462 				       struct sk_buff *skb, bool last)
463 {
464 	struct afs_vnode *vnode = call->reply;
465 	const __be32 *bp;
466 
467 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
468 
469 	afs_transfer_reply(call, skb);
470 	if (!last)
471 		return 0;
472 
473 	if (call->reply_size != call->reply_max)
474 		return -EBADMSG;
475 
476 	/* unmarshall the reply once we've received all of it */
477 	bp = call->buffer;
478 	xdr_decode_AFSFid(&bp, call->reply2);
479 	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
480 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
481 	xdr_decode_AFSCallBack_raw(&bp, call->reply4);
482 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
483 
484 	_leave(" = 0 [done]");
485 	return 0;
486 }
487 
488 /*
489  * FS.CreateFile and FS.MakeDir operation type
490  */
491 static const struct afs_call_type afs_RXFSCreateXXXX = {
492 	.name		= "FS.CreateXXXX",
493 	.deliver	= afs_deliver_fs_create_vnode,
494 	.abort_to_error	= afs_abort_to_error,
495 	.destructor	= afs_flat_call_destructor,
496 };
497 
498 /*
499  * create a file or make a directory
500  */
501 int afs_fs_create(struct afs_server *server,
502 		  struct key *key,
503 		  struct afs_vnode *vnode,
504 		  const char *name,
505 		  umode_t mode,
506 		  struct afs_fid *newfid,
507 		  struct afs_file_status *newstatus,
508 		  struct afs_callback *newcb,
509 		  const struct afs_wait_mode *wait_mode)
510 {
511 	struct afs_call *call;
512 	size_t namesz, reqsz, padsz;
513 	__be32 *bp;
514 
515 	_enter("");
516 
517 	namesz = strlen(name);
518 	padsz = (4 - (namesz & 3)) & 3;
519 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
520 
521 	call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
522 				   (3 + 21 + 21 + 3 + 6) * 4);
523 	if (!call)
524 		return -ENOMEM;
525 
526 	call->key = key;
527 	call->reply = vnode;
528 	call->reply2 = newfid;
529 	call->reply3 = newstatus;
530 	call->reply4 = newcb;
531 	call->service_id = FS_SERVICE;
532 	call->port = htons(AFS_FS_PORT);
533 
534 	/* marshall the parameters */
535 	bp = call->request;
536 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
537 	*bp++ = htonl(vnode->fid.vid);
538 	*bp++ = htonl(vnode->fid.vnode);
539 	*bp++ = htonl(vnode->fid.unique);
540 	*bp++ = htonl(namesz);
541 	memcpy(bp, name, namesz);
542 	bp = (void *) bp + namesz;
543 	if (padsz > 0) {
544 		memset(bp, 0, padsz);
545 		bp = (void *) bp + padsz;
546 	}
547 	*bp++ = htonl(AFS_SET_MODE);
548 	*bp++ = 0; /* mtime */
549 	*bp++ = 0; /* owner */
550 	*bp++ = 0; /* group */
551 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
552 	*bp++ = 0; /* segment size */
553 
554 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
555 }
556 
557 /*
558  * deliver reply data to an FS.RemoveFile or FS.RemoveDir
559  */
560 static int afs_deliver_fs_remove(struct afs_call *call,
561 				 struct sk_buff *skb, bool last)
562 {
563 	struct afs_vnode *vnode = call->reply;
564 	const __be32 *bp;
565 
566 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
567 
568 	afs_transfer_reply(call, skb);
569 	if (!last)
570 		return 0;
571 
572 	if (call->reply_size != call->reply_max)
573 		return -EBADMSG;
574 
575 	/* unmarshall the reply once we've received all of it */
576 	bp = call->buffer;
577 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
578 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
579 
580 	_leave(" = 0 [done]");
581 	return 0;
582 }
583 
584 /*
585  * FS.RemoveDir/FS.RemoveFile operation type
586  */
587 static const struct afs_call_type afs_RXFSRemoveXXXX = {
588 	.name		= "FS.RemoveXXXX",
589 	.deliver	= afs_deliver_fs_remove,
590 	.abort_to_error	= afs_abort_to_error,
591 	.destructor	= afs_flat_call_destructor,
592 };
593 
594 /*
595  * remove a file or directory
596  */
597 int afs_fs_remove(struct afs_server *server,
598 		  struct key *key,
599 		  struct afs_vnode *vnode,
600 		  const char *name,
601 		  bool isdir,
602 		  const struct afs_wait_mode *wait_mode)
603 {
604 	struct afs_call *call;
605 	size_t namesz, reqsz, padsz;
606 	__be32 *bp;
607 
608 	_enter("");
609 
610 	namesz = strlen(name);
611 	padsz = (4 - (namesz & 3)) & 3;
612 	reqsz = (5 * 4) + namesz + padsz;
613 
614 	call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
615 	if (!call)
616 		return -ENOMEM;
617 
618 	call->key = key;
619 	call->reply = vnode;
620 	call->service_id = FS_SERVICE;
621 	call->port = htons(AFS_FS_PORT);
622 
623 	/* marshall the parameters */
624 	bp = call->request;
625 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
626 	*bp++ = htonl(vnode->fid.vid);
627 	*bp++ = htonl(vnode->fid.vnode);
628 	*bp++ = htonl(vnode->fid.unique);
629 	*bp++ = htonl(namesz);
630 	memcpy(bp, name, namesz);
631 	bp = (void *) bp + namesz;
632 	if (padsz > 0) {
633 		memset(bp, 0, padsz);
634 		bp = (void *) bp + padsz;
635 	}
636 
637 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
638 }
639 
640 /*
641  * deliver reply data to an FS.Link
642  */
643 static int afs_deliver_fs_link(struct afs_call *call,
644 			       struct sk_buff *skb, bool last)
645 {
646 	struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
647 	const __be32 *bp;
648 
649 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
650 
651 	afs_transfer_reply(call, skb);
652 	if (!last)
653 		return 0;
654 
655 	if (call->reply_size != call->reply_max)
656 		return -EBADMSG;
657 
658 	/* unmarshall the reply once we've received all of it */
659 	bp = call->buffer;
660 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
661 	xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
662 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
663 
664 	_leave(" = 0 [done]");
665 	return 0;
666 }
667 
668 /*
669  * FS.Link operation type
670  */
671 static const struct afs_call_type afs_RXFSLink = {
672 	.name		= "FS.Link",
673 	.deliver	= afs_deliver_fs_link,
674 	.abort_to_error	= afs_abort_to_error,
675 	.destructor	= afs_flat_call_destructor,
676 };
677 
678 /*
679  * make a hard link
680  */
681 int afs_fs_link(struct afs_server *server,
682 		struct key *key,
683 		struct afs_vnode *dvnode,
684 		struct afs_vnode *vnode,
685 		const char *name,
686 		const struct afs_wait_mode *wait_mode)
687 {
688 	struct afs_call *call;
689 	size_t namesz, reqsz, padsz;
690 	__be32 *bp;
691 
692 	_enter("");
693 
694 	namesz = strlen(name);
695 	padsz = (4 - (namesz & 3)) & 3;
696 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
697 
698 	call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
699 	if (!call)
700 		return -ENOMEM;
701 
702 	call->key = key;
703 	call->reply = dvnode;
704 	call->reply2 = vnode;
705 	call->service_id = FS_SERVICE;
706 	call->port = htons(AFS_FS_PORT);
707 
708 	/* marshall the parameters */
709 	bp = call->request;
710 	*bp++ = htonl(FSLINK);
711 	*bp++ = htonl(dvnode->fid.vid);
712 	*bp++ = htonl(dvnode->fid.vnode);
713 	*bp++ = htonl(dvnode->fid.unique);
714 	*bp++ = htonl(namesz);
715 	memcpy(bp, name, namesz);
716 	bp = (void *) bp + namesz;
717 	if (padsz > 0) {
718 		memset(bp, 0, padsz);
719 		bp = (void *) bp + padsz;
720 	}
721 	*bp++ = htonl(vnode->fid.vid);
722 	*bp++ = htonl(vnode->fid.vnode);
723 	*bp++ = htonl(vnode->fid.unique);
724 
725 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
726 }
727 
728 /*
729  * deliver reply data to an FS.Symlink
730  */
731 static int afs_deliver_fs_symlink(struct afs_call *call,
732 				  struct sk_buff *skb, bool last)
733 {
734 	struct afs_vnode *vnode = call->reply;
735 	const __be32 *bp;
736 
737 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
738 
739 	afs_transfer_reply(call, skb);
740 	if (!last)
741 		return 0;
742 
743 	if (call->reply_size != call->reply_max)
744 		return -EBADMSG;
745 
746 	/* unmarshall the reply once we've received all of it */
747 	bp = call->buffer;
748 	xdr_decode_AFSFid(&bp, call->reply2);
749 	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
750 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
751 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
752 
753 	_leave(" = 0 [done]");
754 	return 0;
755 }
756 
757 /*
758  * FS.Symlink operation type
759  */
760 static const struct afs_call_type afs_RXFSSymlink = {
761 	.name		= "FS.Symlink",
762 	.deliver	= afs_deliver_fs_symlink,
763 	.abort_to_error	= afs_abort_to_error,
764 	.destructor	= afs_flat_call_destructor,
765 };
766 
767 /*
768  * create a symbolic link
769  */
770 int afs_fs_symlink(struct afs_server *server,
771 		   struct key *key,
772 		   struct afs_vnode *vnode,
773 		   const char *name,
774 		   const char *contents,
775 		   struct afs_fid *newfid,
776 		   struct afs_file_status *newstatus,
777 		   const struct afs_wait_mode *wait_mode)
778 {
779 	struct afs_call *call;
780 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
781 	__be32 *bp;
782 
783 	_enter("");
784 
785 	namesz = strlen(name);
786 	padsz = (4 - (namesz & 3)) & 3;
787 
788 	c_namesz = strlen(contents);
789 	c_padsz = (4 - (c_namesz & 3)) & 3;
790 
791 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
792 
793 	call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
794 				   (3 + 21 + 21 + 6) * 4);
795 	if (!call)
796 		return -ENOMEM;
797 
798 	call->key = key;
799 	call->reply = vnode;
800 	call->reply2 = newfid;
801 	call->reply3 = newstatus;
802 	call->service_id = FS_SERVICE;
803 	call->port = htons(AFS_FS_PORT);
804 
805 	/* marshall the parameters */
806 	bp = call->request;
807 	*bp++ = htonl(FSSYMLINK);
808 	*bp++ = htonl(vnode->fid.vid);
809 	*bp++ = htonl(vnode->fid.vnode);
810 	*bp++ = htonl(vnode->fid.unique);
811 	*bp++ = htonl(namesz);
812 	memcpy(bp, name, namesz);
813 	bp = (void *) bp + namesz;
814 	if (padsz > 0) {
815 		memset(bp, 0, padsz);
816 		bp = (void *) bp + padsz;
817 	}
818 	*bp++ = htonl(c_namesz);
819 	memcpy(bp, contents, c_namesz);
820 	bp = (void *) bp + c_namesz;
821 	if (c_padsz > 0) {
822 		memset(bp, 0, c_padsz);
823 		bp = (void *) bp + c_padsz;
824 	}
825 	*bp++ = htonl(AFS_SET_MODE);
826 	*bp++ = 0; /* mtime */
827 	*bp++ = 0; /* owner */
828 	*bp++ = 0; /* group */
829 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
830 	*bp++ = 0; /* segment size */
831 
832 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
833 }
834 
835 /*
836  * deliver reply data to an FS.Rename
837  */
838 static int afs_deliver_fs_rename(struct afs_call *call,
839 				  struct sk_buff *skb, bool last)
840 {
841 	struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
842 	const __be32 *bp;
843 
844 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
845 
846 	afs_transfer_reply(call, skb);
847 	if (!last)
848 		return 0;
849 
850 	if (call->reply_size != call->reply_max)
851 		return -EBADMSG;
852 
853 	/* unmarshall the reply once we've received all of it */
854 	bp = call->buffer;
855 	xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
856 	if (new_dvnode != orig_dvnode)
857 		xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
858 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
859 
860 	_leave(" = 0 [done]");
861 	return 0;
862 }
863 
864 /*
865  * FS.Rename operation type
866  */
867 static const struct afs_call_type afs_RXFSRename = {
868 	.name		= "FS.Rename",
869 	.deliver	= afs_deliver_fs_rename,
870 	.abort_to_error	= afs_abort_to_error,
871 	.destructor	= afs_flat_call_destructor,
872 };
873 
874 /*
875  * create a symbolic link
876  */
877 int afs_fs_rename(struct afs_server *server,
878 		  struct key *key,
879 		  struct afs_vnode *orig_dvnode,
880 		  const char *orig_name,
881 		  struct afs_vnode *new_dvnode,
882 		  const char *new_name,
883 		  const struct afs_wait_mode *wait_mode)
884 {
885 	struct afs_call *call;
886 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
887 	__be32 *bp;
888 
889 	_enter("");
890 
891 	o_namesz = strlen(orig_name);
892 	o_padsz = (4 - (o_namesz & 3)) & 3;
893 
894 	n_namesz = strlen(new_name);
895 	n_padsz = (4 - (n_namesz & 3)) & 3;
896 
897 	reqsz = (4 * 4) +
898 		4 + o_namesz + o_padsz +
899 		(3 * 4) +
900 		4 + n_namesz + n_padsz;
901 
902 	call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
903 	if (!call)
904 		return -ENOMEM;
905 
906 	call->key = key;
907 	call->reply = orig_dvnode;
908 	call->reply2 = new_dvnode;
909 	call->service_id = FS_SERVICE;
910 	call->port = htons(AFS_FS_PORT);
911 
912 	/* marshall the parameters */
913 	bp = call->request;
914 	*bp++ = htonl(FSRENAME);
915 	*bp++ = htonl(orig_dvnode->fid.vid);
916 	*bp++ = htonl(orig_dvnode->fid.vnode);
917 	*bp++ = htonl(orig_dvnode->fid.unique);
918 	*bp++ = htonl(o_namesz);
919 	memcpy(bp, orig_name, o_namesz);
920 	bp = (void *) bp + o_namesz;
921 	if (o_padsz > 0) {
922 		memset(bp, 0, o_padsz);
923 		bp = (void *) bp + o_padsz;
924 	}
925 
926 	*bp++ = htonl(new_dvnode->fid.vid);
927 	*bp++ = htonl(new_dvnode->fid.vnode);
928 	*bp++ = htonl(new_dvnode->fid.unique);
929 	*bp++ = htonl(n_namesz);
930 	memcpy(bp, new_name, n_namesz);
931 	bp = (void *) bp + n_namesz;
932 	if (n_padsz > 0) {
933 		memset(bp, 0, n_padsz);
934 		bp = (void *) bp + n_padsz;
935 	}
936 
937 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
938 }
939