xref: /linux/fs/afs/yfsclient.c (revision 9bd87ec631ba07285138eed9c85645a12294f6c6)
1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
230062bd1SDavid Howells /* YFS File Server client stubs
330062bd1SDavid Howells  *
430062bd1SDavid Howells  * Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
530062bd1SDavid Howells  * Written by David Howells (dhowells@redhat.com)
630062bd1SDavid Howells  */
730062bd1SDavid Howells 
830062bd1SDavid Howells #include <linux/init.h>
930062bd1SDavid Howells #include <linux/slab.h>
1030062bd1SDavid Howells #include <linux/sched.h>
1130062bd1SDavid Howells #include <linux/circ_buf.h>
1230062bd1SDavid Howells #include <linux/iversion.h>
1330062bd1SDavid Howells #include "internal.h"
1430062bd1SDavid Howells #include "afs_fs.h"
1530062bd1SDavid Howells #include "xdr_fs.h"
1630062bd1SDavid Howells #include "protocol_yfs.h"
1730062bd1SDavid Howells 
1830062bd1SDavid Howells #define xdr_size(x) (sizeof(*x) / sizeof(__be32))
1930062bd1SDavid Howells 
2030062bd1SDavid Howells static void xdr_decode_YFSFid(const __be32 **_bp, struct afs_fid *fid)
2130062bd1SDavid Howells {
2230062bd1SDavid Howells 	const struct yfs_xdr_YFSFid *x = (const void *)*_bp;
2330062bd1SDavid Howells 
2430062bd1SDavid Howells 	fid->vid	= xdr_to_u64(x->volume);
2530062bd1SDavid Howells 	fid->vnode	= xdr_to_u64(x->vnode.lo);
2630062bd1SDavid Howells 	fid->vnode_hi	= ntohl(x->vnode.hi);
2730062bd1SDavid Howells 	fid->unique	= ntohl(x->vnode.unique);
2830062bd1SDavid Howells 	*_bp += xdr_size(x);
2930062bd1SDavid Howells }
3030062bd1SDavid Howells 
3130062bd1SDavid Howells static __be32 *xdr_encode_u32(__be32 *bp, u32 n)
3230062bd1SDavid Howells {
3330062bd1SDavid Howells 	*bp++ = htonl(n);
3430062bd1SDavid Howells 	return bp;
3530062bd1SDavid Howells }
3630062bd1SDavid Howells 
3730062bd1SDavid Howells static __be32 *xdr_encode_u64(__be32 *bp, u64 n)
3830062bd1SDavid Howells {
3930062bd1SDavid Howells 	struct yfs_xdr_u64 *x = (void *)bp;
4030062bd1SDavid Howells 
4130062bd1SDavid Howells 	*x = u64_to_xdr(n);
4230062bd1SDavid Howells 	return bp + xdr_size(x);
4330062bd1SDavid Howells }
4430062bd1SDavid Howells 
4530062bd1SDavid Howells static __be32 *xdr_encode_YFSFid(__be32 *bp, struct afs_fid *fid)
4630062bd1SDavid Howells {
4730062bd1SDavid Howells 	struct yfs_xdr_YFSFid *x = (void *)bp;
4830062bd1SDavid Howells 
4930062bd1SDavid Howells 	x->volume	= u64_to_xdr(fid->vid);
5030062bd1SDavid Howells 	x->vnode.lo	= u64_to_xdr(fid->vnode);
5130062bd1SDavid Howells 	x->vnode.hi	= htonl(fid->vnode_hi);
5230062bd1SDavid Howells 	x->vnode.unique	= htonl(fid->unique);
5330062bd1SDavid Howells 	return bp + xdr_size(x);
5430062bd1SDavid Howells }
5530062bd1SDavid Howells 
5630062bd1SDavid Howells static size_t xdr_strlen(unsigned int len)
5730062bd1SDavid Howells {
5830062bd1SDavid Howells 	return sizeof(__be32) + round_up(len, sizeof(__be32));
5930062bd1SDavid Howells }
6030062bd1SDavid Howells 
6130062bd1SDavid Howells static __be32 *xdr_encode_string(__be32 *bp, const char *p, unsigned int len)
6230062bd1SDavid Howells {
6330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, len);
6430062bd1SDavid Howells 	bp = memcpy(bp, p, len);
6530062bd1SDavid Howells 	if (len & 3) {
6630062bd1SDavid Howells 		unsigned int pad = 4 - (len & 3);
6730062bd1SDavid Howells 
6830062bd1SDavid Howells 		memset((u8 *)bp + len, 0, pad);
6930062bd1SDavid Howells 		len += pad;
7030062bd1SDavid Howells 	}
7130062bd1SDavid Howells 
7230062bd1SDavid Howells 	return bp + len / sizeof(__be32);
7330062bd1SDavid Howells }
7430062bd1SDavid Howells 
75e49c7b2fSDavid Howells static __be32 *xdr_encode_name(__be32 *bp, const struct qstr *p)
76e49c7b2fSDavid Howells {
77e49c7b2fSDavid Howells 	return xdr_encode_string(bp, p->name, p->len);
78e49c7b2fSDavid Howells }
79e49c7b2fSDavid Howells 
8030062bd1SDavid Howells static s64 linux_to_yfs_time(const struct timespec64 *t)
8130062bd1SDavid Howells {
8230062bd1SDavid Howells 	/* Convert to 100ns intervals. */
8330062bd1SDavid Howells 	return (u64)t->tv_sec * 10000000 + t->tv_nsec/100;
8430062bd1SDavid Howells }
8530062bd1SDavid Howells 
8630062bd1SDavid Howells static __be32 *xdr_encode_YFSStoreStatus_mode(__be32 *bp, mode_t mode)
8730062bd1SDavid Howells {
8830062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
8930062bd1SDavid Howells 
9030062bd1SDavid Howells 	x->mask		= htonl(AFS_SET_MODE);
9130062bd1SDavid Howells 	x->mode		= htonl(mode & S_IALLUGO);
9230062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(0);
9330062bd1SDavid Howells 	x->owner	= u64_to_xdr(0);
9430062bd1SDavid Howells 	x->group	= u64_to_xdr(0);
9530062bd1SDavid Howells 	return bp + xdr_size(x);
9630062bd1SDavid Howells }
9730062bd1SDavid Howells 
9830062bd1SDavid Howells static __be32 *xdr_encode_YFSStoreStatus_mtime(__be32 *bp, const struct timespec64 *t)
9930062bd1SDavid Howells {
10030062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
10130062bd1SDavid Howells 	s64 mtime = linux_to_yfs_time(t);
10230062bd1SDavid Howells 
10330062bd1SDavid Howells 	x->mask		= htonl(AFS_SET_MTIME);
10430062bd1SDavid Howells 	x->mode		= htonl(0);
10530062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(mtime);
10630062bd1SDavid Howells 	x->owner	= u64_to_xdr(0);
10730062bd1SDavid Howells 	x->group	= u64_to_xdr(0);
10830062bd1SDavid Howells 	return bp + xdr_size(x);
10930062bd1SDavid Howells }
11030062bd1SDavid Howells 
11130062bd1SDavid Howells /*
11230062bd1SDavid Howells  * Convert a signed 100ns-resolution 64-bit time into a timespec.
11330062bd1SDavid Howells  */
11430062bd1SDavid Howells static struct timespec64 yfs_time_to_linux(s64 t)
11530062bd1SDavid Howells {
11630062bd1SDavid Howells 	struct timespec64 ts;
11730062bd1SDavid Howells 	u64 abs_t;
11830062bd1SDavid Howells 
11930062bd1SDavid Howells 	/*
12030062bd1SDavid Howells 	 * Unfortunately can not use normal 64 bit division on 32 bit arch, but
12130062bd1SDavid Howells 	 * the alternative, do_div, does not work with negative numbers so have
12230062bd1SDavid Howells 	 * to special case them
12330062bd1SDavid Howells 	 */
12430062bd1SDavid Howells 	if (t < 0) {
12530062bd1SDavid Howells 		abs_t = -t;
12630062bd1SDavid Howells 		ts.tv_nsec = (time64_t)(do_div(abs_t, 10000000) * 100);
12730062bd1SDavid Howells 		ts.tv_nsec = -ts.tv_nsec;
12830062bd1SDavid Howells 		ts.tv_sec = -abs_t;
12930062bd1SDavid Howells 	} else {
13030062bd1SDavid Howells 		abs_t = t;
13130062bd1SDavid Howells 		ts.tv_nsec = (time64_t)do_div(abs_t, 10000000) * 100;
13230062bd1SDavid Howells 		ts.tv_sec = abs_t;
13330062bd1SDavid Howells 	}
13430062bd1SDavid Howells 
13530062bd1SDavid Howells 	return ts;
13630062bd1SDavid Howells }
13730062bd1SDavid Howells 
13830062bd1SDavid Howells static struct timespec64 xdr_to_time(const struct yfs_xdr_u64 xdr)
13930062bd1SDavid Howells {
14030062bd1SDavid Howells 	s64 t = xdr_to_u64(xdr);
14130062bd1SDavid Howells 
14230062bd1SDavid Howells 	return yfs_time_to_linux(t);
14330062bd1SDavid Howells }
14430062bd1SDavid Howells 
14530062bd1SDavid Howells static void yfs_check_req(struct afs_call *call, __be32 *bp)
14630062bd1SDavid Howells {
14730062bd1SDavid Howells 	size_t len = (void *)bp - call->request;
14830062bd1SDavid Howells 
14930062bd1SDavid Howells 	if (len > call->request_size)
15030062bd1SDavid Howells 		pr_err("kAFS: %s: Request buffer overflow (%zu>%u)\n",
15130062bd1SDavid Howells 		       call->type->name, len, call->request_size);
15230062bd1SDavid Howells 	else if (len < call->request_size)
153a4e530aeSKefeng Wang 		pr_warn("kAFS: %s: Request buffer underflow (%zu<%u)\n",
15430062bd1SDavid Howells 			call->type->name, len, call->request_size);
15530062bd1SDavid Howells }
15630062bd1SDavid Howells 
15730062bd1SDavid Howells /*
15830062bd1SDavid Howells  * Dump a bad file status record.
15930062bd1SDavid Howells  */
16030062bd1SDavid Howells static void xdr_dump_bad(const __be32 *bp)
16130062bd1SDavid Howells {
16230062bd1SDavid Howells 	__be32 x[4];
16330062bd1SDavid Howells 	int i;
16430062bd1SDavid Howells 
16530062bd1SDavid Howells 	pr_notice("YFS XDR: Bad status record\n");
1663efe55b0SDavid Howells 	for (i = 0; i < 6 * 4 * 4; i += 16) {
16730062bd1SDavid Howells 		memcpy(x, bp, 16);
16830062bd1SDavid Howells 		bp += 4;
16930062bd1SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
17030062bd1SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
17130062bd1SDavid Howells 	}
17230062bd1SDavid Howells 
1733efe55b0SDavid Howells 	memcpy(x, bp, 8);
1743efe55b0SDavid Howells 	pr_notice("0x60: %08x %08x\n", ntohl(x[0]), ntohl(x[1]));
17530062bd1SDavid Howells }
17630062bd1SDavid Howells 
17730062bd1SDavid Howells /*
17830062bd1SDavid Howells  * Decode a YFSFetchStatus block
17930062bd1SDavid Howells  */
18038355eecSDavid Howells static void xdr_decode_YFSFetchStatus(const __be32 **_bp,
181a58823acSDavid Howells 				      struct afs_call *call,
182a58823acSDavid Howells 				      struct afs_status_cb *scb)
18330062bd1SDavid Howells {
18430062bd1SDavid Howells 	const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp;
185a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
18630062bd1SDavid Howells 	u32 type;
18730062bd1SDavid Howells 
18830062bd1SDavid Howells 	status->abort_code = ntohl(xdr->abort_code);
18930062bd1SDavid Howells 	if (status->abort_code != 0) {
190a58823acSDavid Howells 		if (status->abort_code == VNOVNODE)
19130062bd1SDavid Howells 			status->nlink = 0;
192a38a7558SDavid Howells 		scb->have_error = true;
19338355eecSDavid Howells 		goto advance;
19430062bd1SDavid Howells 	}
19530062bd1SDavid Howells 
19630062bd1SDavid Howells 	type = ntohl(xdr->type);
19730062bd1SDavid Howells 	switch (type) {
19830062bd1SDavid Howells 	case AFS_FTYPE_FILE:
19930062bd1SDavid Howells 	case AFS_FTYPE_DIR:
20030062bd1SDavid Howells 	case AFS_FTYPE_SYMLINK:
20130062bd1SDavid Howells 		status->type = type;
20230062bd1SDavid Howells 		break;
20330062bd1SDavid Howells 	default:
20430062bd1SDavid Howells 		goto bad;
20530062bd1SDavid Howells 	}
20630062bd1SDavid Howells 
207a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
208a58823acSDavid Howells 	status->author		= xdr_to_u64(xdr->author);
209a58823acSDavid Howells 	status->owner		= xdr_to_u64(xdr->owner);
210a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
211a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
212a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
213a58823acSDavid Howells 	status->group		= xdr_to_u64(xdr->group);
214a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
21530062bd1SDavid Howells 
21630062bd1SDavid Howells 	status->mtime_client	= xdr_to_time(xdr->mtime_client);
21730062bd1SDavid Howells 	status->mtime_server	= xdr_to_time(xdr->mtime_server);
218a58823acSDavid Howells 	status->size		= xdr_to_u64(xdr->size);
219a58823acSDavid Howells 	status->data_version	= xdr_to_u64(xdr->data_version);
220a38a7558SDavid Howells 	scb->have_status	= true;
221c72057b5SDavid Howells advance:
22230062bd1SDavid Howells 	*_bp += xdr_size(xdr);
22338355eecSDavid Howells 	return;
22430062bd1SDavid Howells 
22530062bd1SDavid Howells bad:
22630062bd1SDavid Howells 	xdr_dump_bad(*_bp);
2277126ead9SDavid Howells 	afs_protocol_error(call, afs_eproto_bad_status);
228c72057b5SDavid Howells 	goto advance;
22930062bd1SDavid Howells }
23030062bd1SDavid Howells 
23130062bd1SDavid Howells /*
232a58823acSDavid Howells  * Decode a YFSCallBack block
23330062bd1SDavid Howells  */
234a58823acSDavid Howells static void xdr_decode_YFSCallBack(const __be32 **_bp,
235a58823acSDavid Howells 				   struct afs_call *call,
236a58823acSDavid Howells 				   struct afs_status_cb *scb)
23778107055SDavid Howells {
23878107055SDavid Howells 	struct yfs_xdr_YFSCallBack *x = (void *)*_bp;
239a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
24078107055SDavid Howells 	ktime_t cb_expiry;
24178107055SDavid Howells 
24278107055SDavid Howells 	cb_expiry = call->reply_time;
24378107055SDavid Howells 	cb_expiry = ktime_add(cb_expiry, xdr_to_u64(x->expiration_time) * 100);
24478107055SDavid Howells 	cb->expires_at	= ktime_divns(cb_expiry, NSEC_PER_SEC);
245a58823acSDavid Howells 	scb->have_cb	= true;
24678107055SDavid Howells 	*_bp += xdr_size(x);
24778107055SDavid Howells }
24878107055SDavid Howells 
24930062bd1SDavid Howells /*
25030062bd1SDavid Howells  * Decode a YFSVolSync block
25130062bd1SDavid Howells  */
25230062bd1SDavid Howells static void xdr_decode_YFSVolSync(const __be32 **_bp,
25330062bd1SDavid Howells 				  struct afs_volsync *volsync)
25430062bd1SDavid Howells {
25530062bd1SDavid Howells 	struct yfs_xdr_YFSVolSync *x = (void *)*_bp;
25630062bd1SDavid Howells 	u64 creation;
25730062bd1SDavid Howells 
25830062bd1SDavid Howells 	if (volsync) {
25930062bd1SDavid Howells 		creation = xdr_to_u64(x->vol_creation_date);
26030062bd1SDavid Howells 		do_div(creation, 10 * 1000 * 1000);
26130062bd1SDavid Howells 		volsync->creation = creation;
26230062bd1SDavid Howells 	}
26330062bd1SDavid Howells 
26430062bd1SDavid Howells 	*_bp += xdr_size(x);
26530062bd1SDavid Howells }
26630062bd1SDavid Howells 
26730062bd1SDavid Howells /*
26830062bd1SDavid Howells  * Encode the requested attributes into a YFSStoreStatus block
26930062bd1SDavid Howells  */
27030062bd1SDavid Howells static __be32 *xdr_encode_YFS_StoreStatus(__be32 *bp, struct iattr *attr)
27130062bd1SDavid Howells {
27230062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
27330062bd1SDavid Howells 	s64 mtime = 0, owner = 0, group = 0;
27430062bd1SDavid Howells 	u32 mask = 0, mode = 0;
27530062bd1SDavid Howells 
27630062bd1SDavid Howells 	mask = 0;
27730062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
27830062bd1SDavid Howells 		mask |= AFS_SET_MTIME;
27930062bd1SDavid Howells 		mtime = linux_to_yfs_time(&attr->ia_mtime);
28030062bd1SDavid Howells 	}
28130062bd1SDavid Howells 
28230062bd1SDavid Howells 	if (attr->ia_valid & ATTR_UID) {
28330062bd1SDavid Howells 		mask |= AFS_SET_OWNER;
28430062bd1SDavid Howells 		owner = from_kuid(&init_user_ns, attr->ia_uid);
28530062bd1SDavid Howells 	}
28630062bd1SDavid Howells 
28730062bd1SDavid Howells 	if (attr->ia_valid & ATTR_GID) {
28830062bd1SDavid Howells 		mask |= AFS_SET_GROUP;
28930062bd1SDavid Howells 		group = from_kgid(&init_user_ns, attr->ia_gid);
29030062bd1SDavid Howells 	}
29130062bd1SDavid Howells 
29230062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
29330062bd1SDavid Howells 		mask |= AFS_SET_MODE;
29430062bd1SDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
29530062bd1SDavid Howells 	}
29630062bd1SDavid Howells 
29730062bd1SDavid Howells 	x->mask		= htonl(mask);
29830062bd1SDavid Howells 	x->mode		= htonl(mode);
29930062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(mtime);
30030062bd1SDavid Howells 	x->owner	= u64_to_xdr(owner);
30130062bd1SDavid Howells 	x->group	= u64_to_xdr(group);
30230062bd1SDavid Howells 	return bp + xdr_size(x);
30330062bd1SDavid Howells }
30430062bd1SDavid Howells 
30530062bd1SDavid Howells /*
30630062bd1SDavid Howells  * Decode a YFSFetchVolumeStatus block.
30730062bd1SDavid Howells  */
30830062bd1SDavid Howells static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp,
30930062bd1SDavid Howells 					    struct afs_volume_status *vs)
31030062bd1SDavid Howells {
31130062bd1SDavid Howells 	const struct yfs_xdr_YFSFetchVolumeStatus *x = (const void *)*_bp;
31230062bd1SDavid Howells 	u32 flags;
31330062bd1SDavid Howells 
31430062bd1SDavid Howells 	vs->vid			= xdr_to_u64(x->vid);
31530062bd1SDavid Howells 	vs->parent_id		= xdr_to_u64(x->parent_id);
31630062bd1SDavid Howells 	flags			= ntohl(x->flags);
31730062bd1SDavid Howells 	vs->online		= flags & yfs_FVSOnline;
31830062bd1SDavid Howells 	vs->in_service		= flags & yfs_FVSInservice;
31930062bd1SDavid Howells 	vs->blessed		= flags & yfs_FVSBlessed;
32030062bd1SDavid Howells 	vs->needs_salvage	= flags & yfs_FVSNeedsSalvage;
32130062bd1SDavid Howells 	vs->type		= ntohl(x->type);
32230062bd1SDavid Howells 	vs->min_quota		= 0;
32330062bd1SDavid Howells 	vs->max_quota		= xdr_to_u64(x->max_quota);
32430062bd1SDavid Howells 	vs->blocks_in_use	= xdr_to_u64(x->blocks_in_use);
32530062bd1SDavid Howells 	vs->part_blocks_avail	= xdr_to_u64(x->part_blocks_avail);
32630062bd1SDavid Howells 	vs->part_max_blocks	= xdr_to_u64(x->part_max_blocks);
32730062bd1SDavid Howells 	vs->vol_copy_date	= xdr_to_u64(x->vol_copy_date);
32830062bd1SDavid Howells 	vs->vol_backup_date	= xdr_to_u64(x->vol_backup_date);
32930062bd1SDavid Howells 	*_bp += sizeof(*x) / sizeof(__be32);
33030062bd1SDavid Howells }
33130062bd1SDavid Howells 
33230062bd1SDavid Howells /*
333a58823acSDavid Howells  * Deliver reply data to operations that just return a file status and a volume
334a58823acSDavid Howells  * sync record.
335a58823acSDavid Howells  */
336a58823acSDavid Howells static int yfs_deliver_status_and_volsync(struct afs_call *call)
337a58823acSDavid Howells {
338e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
339a58823acSDavid Howells 	const __be32 *bp;
340a58823acSDavid Howells 	int ret;
341a58823acSDavid Howells 
342a58823acSDavid Howells 	ret = afs_transfer_reply(call);
343a58823acSDavid Howells 	if (ret < 0)
344a58823acSDavid Howells 		return ret;
345a58823acSDavid Howells 
346a58823acSDavid Howells 	bp = call->buffer;
347e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &op->file[0].scb);
348e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
34930062bd1SDavid Howells 
35030062bd1SDavid Howells 	_leave(" = 0 [done]");
35130062bd1SDavid Howells 	return 0;
35230062bd1SDavid Howells }
35330062bd1SDavid Howells 
35430062bd1SDavid Howells /*
35530062bd1SDavid Howells  * Deliver reply data to an YFS.FetchData64.
35630062bd1SDavid Howells  */
35730062bd1SDavid Howells static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
35830062bd1SDavid Howells {
359e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
360e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
361e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
36230062bd1SDavid Howells 	const __be32 *bp;
36330062bd1SDavid Howells 	unsigned int size;
36430062bd1SDavid Howells 	int ret;
36530062bd1SDavid Howells 
36630062bd1SDavid Howells 	_enter("{%u,%zu/%llu}",
367fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
36830062bd1SDavid Howells 
36930062bd1SDavid Howells 	switch (call->unmarshall) {
37030062bd1SDavid Howells 	case 0:
37130062bd1SDavid Howells 		req->actual_len = 0;
37230062bd1SDavid Howells 		req->index = 0;
37330062bd1SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
37430062bd1SDavid Howells 		afs_extract_to_tmp64(call);
37530062bd1SDavid Howells 		call->unmarshall++;
37635a3a90cSGustavo A. R. Silva 		/* Fall through */
37730062bd1SDavid Howells 
37835a3a90cSGustavo A. R. Silva 		/* extract the returned data length */
37930062bd1SDavid Howells 	case 1:
38030062bd1SDavid Howells 		_debug("extract data length");
38130062bd1SDavid Howells 		ret = afs_extract_data(call, true);
38230062bd1SDavid Howells 		if (ret < 0)
38330062bd1SDavid Howells 			return ret;
38430062bd1SDavid Howells 
38530062bd1SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
38630062bd1SDavid Howells 		_debug("DATA length: %llu", req->actual_len);
38730062bd1SDavid Howells 		req->remain = min(req->len, req->actual_len);
38830062bd1SDavid Howells 		if (req->remain == 0)
38930062bd1SDavid Howells 			goto no_more_data;
39030062bd1SDavid Howells 
39130062bd1SDavid Howells 		call->unmarshall++;
39230062bd1SDavid Howells 
39330062bd1SDavid Howells 	begin_page:
39430062bd1SDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
39530062bd1SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
39630062bd1SDavid Howells 			size = PAGE_SIZE - req->offset;
39730062bd1SDavid Howells 		else
39830062bd1SDavid Howells 			size = req->remain;
39930062bd1SDavid Howells 		call->bvec[0].bv_len = size;
40030062bd1SDavid Howells 		call->bvec[0].bv_offset = req->offset;
40130062bd1SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
402fc276122SDavid Howells 		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
40330062bd1SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
40435a3a90cSGustavo A. R. Silva 		/* Fall through */
40530062bd1SDavid Howells 
40635a3a90cSGustavo A. R. Silva 		/* extract the returned data */
40730062bd1SDavid Howells 	case 2:
40830062bd1SDavid Howells 		_debug("extract data %zu/%llu",
409fc276122SDavid Howells 		       iov_iter_count(call->iter), req->remain);
41030062bd1SDavid Howells 
41130062bd1SDavid Howells 		ret = afs_extract_data(call, true);
41230062bd1SDavid Howells 		if (ret < 0)
41330062bd1SDavid Howells 			return ret;
41430062bd1SDavid Howells 		req->remain -= call->bvec[0].bv_len;
41530062bd1SDavid Howells 		req->offset += call->bvec[0].bv_len;
41630062bd1SDavid Howells 		ASSERTCMP(req->offset, <=, PAGE_SIZE);
41730062bd1SDavid Howells 		if (req->offset == PAGE_SIZE) {
41830062bd1SDavid Howells 			req->offset = 0;
41930062bd1SDavid Howells 			req->index++;
42030062bd1SDavid Howells 			if (req->remain > 0)
42130062bd1SDavid Howells 				goto begin_page;
42230062bd1SDavid Howells 		}
42330062bd1SDavid Howells 
42430062bd1SDavid Howells 		ASSERTCMP(req->remain, ==, 0);
42530062bd1SDavid Howells 		if (req->actual_len <= req->len)
42630062bd1SDavid Howells 			goto no_more_data;
42730062bd1SDavid Howells 
42830062bd1SDavid Howells 		/* Discard any excess data the server gave us */
42923a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
43030062bd1SDavid Howells 		call->unmarshall = 3;
431e690c9e3SGustavo A. R. Silva 		/* Fall through */
43235a3a90cSGustavo A. R. Silva 
43330062bd1SDavid Howells 	case 3:
43430062bd1SDavid Howells 		_debug("extract discard %zu/%llu",
435fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
43630062bd1SDavid Howells 
43730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
43830062bd1SDavid Howells 		if (ret < 0)
43930062bd1SDavid Howells 			return ret;
44030062bd1SDavid Howells 
44130062bd1SDavid Howells 	no_more_data:
44230062bd1SDavid Howells 		call->unmarshall = 4;
44330062bd1SDavid Howells 		afs_extract_to_buf(call,
44430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
44530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
44630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
44735a3a90cSGustavo A. R. Silva 		/* Fall through */
44830062bd1SDavid Howells 
44935a3a90cSGustavo A. R. Silva 		/* extract the metadata */
45030062bd1SDavid Howells 	case 4:
45130062bd1SDavid Howells 		ret = afs_extract_data(call, false);
45230062bd1SDavid Howells 		if (ret < 0)
45330062bd1SDavid Howells 			return ret;
45430062bd1SDavid Howells 
45530062bd1SDavid Howells 		bp = call->buffer;
456e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
457e49c7b2fSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, &vp->scb);
458e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
45930062bd1SDavid Howells 
460e49c7b2fSDavid Howells 		req->data_version = vp->scb.status.data_version;
461e49c7b2fSDavid Howells 		req->file_size = vp->scb.status.size;
462a58823acSDavid Howells 
46330062bd1SDavid Howells 		call->unmarshall++;
464e690c9e3SGustavo A. R. Silva 		/* Fall through */
46535a3a90cSGustavo A. R. Silva 
46630062bd1SDavid Howells 	case 5:
46730062bd1SDavid Howells 		break;
46830062bd1SDavid Howells 	}
46930062bd1SDavid Howells 
47030062bd1SDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
47130062bd1SDavid Howells 		if (req->offset < PAGE_SIZE)
47230062bd1SDavid Howells 			zero_user_segment(req->pages[req->index],
47330062bd1SDavid Howells 					  req->offset, PAGE_SIZE);
47430062bd1SDavid Howells 		req->offset = 0;
47530062bd1SDavid Howells 	}
47630062bd1SDavid Howells 
4779d1be4f4SDavid Howells 	if (req->page_done)
4789d1be4f4SDavid Howells 		for (req->index = 0; req->index < req->nr_pages; req->index++)
4799d1be4f4SDavid Howells 			req->page_done(req);
4809d1be4f4SDavid Howells 
48130062bd1SDavid Howells 	_leave(" = 0 [done]");
48230062bd1SDavid Howells 	return 0;
48330062bd1SDavid Howells }
48430062bd1SDavid Howells 
48530062bd1SDavid Howells /*
48630062bd1SDavid Howells  * YFS.FetchData64 operation type
48730062bd1SDavid Howells  */
48830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchData64 = {
48930062bd1SDavid Howells 	.name		= "YFS.FetchData64",
49030062bd1SDavid Howells 	.op		= yfs_FS_FetchData64,
49130062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_data64,
492e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
49330062bd1SDavid Howells };
49430062bd1SDavid Howells 
49530062bd1SDavid Howells /*
49630062bd1SDavid Howells  * Fetch data from a file.
49730062bd1SDavid Howells  */
498e49c7b2fSDavid Howells void yfs_fs_fetch_data(struct afs_operation *op)
49930062bd1SDavid Howells {
500e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
501e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
50230062bd1SDavid Howells 	struct afs_call *call;
50330062bd1SDavid Howells 	__be32 *bp;
50430062bd1SDavid Howells 
50530062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%llx,%llx",
506e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode,
50730062bd1SDavid Howells 	       req->pos, req->len);
50830062bd1SDavid Howells 
509e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64,
51030062bd1SDavid Howells 				   sizeof(__be32) * 2 +
51130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
51230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 2,
51330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
51430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
51530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
51630062bd1SDavid Howells 	if (!call)
517e49c7b2fSDavid Howells 		return afs_op_nomem(op);
51830062bd1SDavid Howells 
51930062bd1SDavid Howells 	/* marshall the parameters */
52030062bd1SDavid Howells 	bp = call->request;
52130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHDATA64);
52230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
523e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
52430062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->pos);
52530062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->len);
52630062bd1SDavid Howells 	yfs_check_req(call, bp);
52730062bd1SDavid Howells 
528e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
529e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
53030062bd1SDavid Howells }
53130062bd1SDavid Howells 
53230062bd1SDavid Howells /*
53330062bd1SDavid Howells  * Deliver reply data for YFS.CreateFile or YFS.MakeDir.
53430062bd1SDavid Howells  */
53530062bd1SDavid Howells static int yfs_deliver_fs_create_vnode(struct afs_call *call)
53630062bd1SDavid Howells {
537e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
538e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
539e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
54030062bd1SDavid Howells 	const __be32 *bp;
54130062bd1SDavid Howells 	int ret;
54230062bd1SDavid Howells 
54330062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
54430062bd1SDavid Howells 
54530062bd1SDavid Howells 	ret = afs_transfer_reply(call);
54630062bd1SDavid Howells 	if (ret < 0)
54730062bd1SDavid Howells 		return ret;
54830062bd1SDavid Howells 
54930062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
55030062bd1SDavid Howells 	bp = call->buffer;
551e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &op->file[1].fid);
552e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
553e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
554e49c7b2fSDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
555e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
55630062bd1SDavid Howells 
55730062bd1SDavid Howells 	_leave(" = 0 [done]");
55830062bd1SDavid Howells 	return 0;
55930062bd1SDavid Howells }
56030062bd1SDavid Howells 
56130062bd1SDavid Howells /*
56230062bd1SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
56330062bd1SDavid Howells  */
56430062bd1SDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
56530062bd1SDavid Howells 	.name		= "YFS.CreateFile",
56630062bd1SDavid Howells 	.op		= yfs_FS_CreateFile,
56730062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
56830062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
56930062bd1SDavid Howells };
57030062bd1SDavid Howells 
57130062bd1SDavid Howells /*
57230062bd1SDavid Howells  * Create a file.
57330062bd1SDavid Howells  */
574e49c7b2fSDavid Howells void yfs_fs_create_file(struct afs_operation *op)
57530062bd1SDavid Howells {
576e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
577e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
57830062bd1SDavid Howells 	struct afs_call *call;
579e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
58030062bd1SDavid Howells 	__be32 *bp;
58130062bd1SDavid Howells 
58230062bd1SDavid Howells 	_enter("");
58330062bd1SDavid Howells 
58430062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
58530062bd1SDavid Howells 		 sizeof(__be32) +
58630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
587e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
58830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus) +
58930062bd1SDavid Howells 		 sizeof(__be32));
59030062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
59130062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
59230062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
59330062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
59430062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
59530062bd1SDavid Howells 
596e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, reqsz, rplsz);
59730062bd1SDavid Howells 	if (!call)
598e49c7b2fSDavid Howells 		return afs_op_nomem(op);
59930062bd1SDavid Howells 
60030062bd1SDavid Howells 	/* marshall the parameters */
60130062bd1SDavid Howells 	bp = call->request;
60230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSCREATEFILE);
60330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
604e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
605e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
606e49c7b2fSDavid Howells 	bp = xdr_encode_YFSStoreStatus_mode(bp, op->create.mode);
6075edc22ccSMarc Dionne 	bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
60830062bd1SDavid Howells 	yfs_check_req(call, bp);
60930062bd1SDavid Howells 
610e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
611e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
61230062bd1SDavid Howells }
61330062bd1SDavid Howells 
61430062bd1SDavid Howells static const struct afs_call_type yfs_RXFSMakeDir = {
61530062bd1SDavid Howells 	.name		= "YFS.MakeDir",
61630062bd1SDavid Howells 	.op		= yfs_FS_MakeDir,
61730062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
61830062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
61930062bd1SDavid Howells };
62030062bd1SDavid Howells 
62130062bd1SDavid Howells /*
62230062bd1SDavid Howells  * Make a directory.
62330062bd1SDavid Howells  */
624e49c7b2fSDavid Howells void yfs_fs_make_dir(struct afs_operation *op)
62530062bd1SDavid Howells {
626e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
627e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
62830062bd1SDavid Howells 	struct afs_call *call;
629e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
63030062bd1SDavid Howells 	__be32 *bp;
63130062bd1SDavid Howells 
63230062bd1SDavid Howells 	_enter("");
63330062bd1SDavid Howells 
63430062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
63530062bd1SDavid Howells 		 sizeof(struct yfs_xdr_RPCFlags) +
63630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
637e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
63830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus));
63930062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
64030062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
64130062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
64230062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
64330062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
64430062bd1SDavid Howells 
645e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXFSMakeDir, reqsz, rplsz);
64630062bd1SDavid Howells 	if (!call)
647e49c7b2fSDavid Howells 		return afs_op_nomem(op);
64830062bd1SDavid Howells 
64930062bd1SDavid Howells 	/* marshall the parameters */
65030062bd1SDavid Howells 	bp = call->request;
65130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSMAKEDIR);
65230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
653e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
654e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
655e49c7b2fSDavid Howells 	bp = xdr_encode_YFSStoreStatus_mode(bp, op->create.mode);
65630062bd1SDavid Howells 	yfs_check_req(call, bp);
65730062bd1SDavid Howells 
658e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
659e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
66030062bd1SDavid Howells }
66130062bd1SDavid Howells 
66230062bd1SDavid Howells /*
66330062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile2 operation.
66430062bd1SDavid Howells  */
66530062bd1SDavid Howells static int yfs_deliver_fs_remove_file2(struct afs_call *call)
66630062bd1SDavid Howells {
667e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
668e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
669e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
67030062bd1SDavid Howells 	struct afs_fid fid;
67130062bd1SDavid Howells 	const __be32 *bp;
67230062bd1SDavid Howells 	int ret;
67330062bd1SDavid Howells 
67430062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
67530062bd1SDavid Howells 
67630062bd1SDavid Howells 	ret = afs_transfer_reply(call);
67730062bd1SDavid Howells 	if (ret < 0)
67830062bd1SDavid Howells 		return ret;
67930062bd1SDavid Howells 
68030062bd1SDavid Howells 	bp = call->buffer;
681e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
68230062bd1SDavid Howells 	xdr_decode_YFSFid(&bp, &fid);
683e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
68430062bd1SDavid Howells 	/* Was deleted if vnode->status.abort_code == VNOVNODE. */
68530062bd1SDavid Howells 
686e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
68730062bd1SDavid Howells 	return 0;
68830062bd1SDavid Howells }
68930062bd1SDavid Howells 
690e49c7b2fSDavid Howells static void yfs_done_fs_remove_file2(struct afs_call *call)
691e49c7b2fSDavid Howells {
692e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
693e49c7b2fSDavid Howells 	    call->abort_code == RX_INVALID_OPERATION) {
694e49c7b2fSDavid Howells 		set_bit(AFS_SERVER_FL_NO_RM2, &call->server->flags);
695e49c7b2fSDavid Howells 		call->op->flags |= AFS_OPERATION_DOWNGRADE;
696e49c7b2fSDavid Howells 	}
697e49c7b2fSDavid Howells }
698e49c7b2fSDavid Howells 
69930062bd1SDavid Howells /*
70030062bd1SDavid Howells  * YFS.RemoveFile2 operation type.
70130062bd1SDavid Howells  */
70230062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile2 = {
70330062bd1SDavid Howells 	.name		= "YFS.RemoveFile2",
70430062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile2,
70530062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove_file2,
706e49c7b2fSDavid Howells 	.done		= yfs_done_fs_remove_file2,
70730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
70830062bd1SDavid Howells };
70930062bd1SDavid Howells 
71030062bd1SDavid Howells /*
71130062bd1SDavid Howells  * Remove a file and retrieve new file status.
71230062bd1SDavid Howells  */
713e49c7b2fSDavid Howells void yfs_fs_remove_file2(struct afs_operation *op)
71430062bd1SDavid Howells {
715e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
716e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
71730062bd1SDavid Howells 	struct afs_call *call;
71830062bd1SDavid Howells 	__be32 *bp;
71930062bd1SDavid Howells 
72030062bd1SDavid Howells 	_enter("");
72130062bd1SDavid Howells 
722e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile2,
72330062bd1SDavid Howells 				   sizeof(__be32) +
72430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
72530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
726e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
72730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
72830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
72930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
73030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
73130062bd1SDavid Howells 	if (!call)
732e49c7b2fSDavid Howells 		return afs_op_nomem(op);
73330062bd1SDavid Howells 
73430062bd1SDavid Howells 	/* marshall the parameters */
73530062bd1SDavid Howells 	bp = call->request;
73630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE2);
73730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
738e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
739e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
74030062bd1SDavid Howells 	yfs_check_req(call, bp);
74130062bd1SDavid Howells 
742e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
743e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
74430062bd1SDavid Howells }
74530062bd1SDavid Howells 
74630062bd1SDavid Howells /*
74730062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile or YFS.RemoveDir operation.
74830062bd1SDavid Howells  */
74930062bd1SDavid Howells static int yfs_deliver_fs_remove(struct afs_call *call)
75030062bd1SDavid Howells {
751e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
752e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
75330062bd1SDavid Howells 	const __be32 *bp;
75430062bd1SDavid Howells 	int ret;
75530062bd1SDavid Howells 
75630062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
75730062bd1SDavid Howells 
75830062bd1SDavid Howells 	ret = afs_transfer_reply(call);
75930062bd1SDavid Howells 	if (ret < 0)
76030062bd1SDavid Howells 		return ret;
76130062bd1SDavid Howells 
76230062bd1SDavid Howells 	bp = call->buffer;
763e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
764e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
76530062bd1SDavid Howells 	return 0;
76630062bd1SDavid Howells }
76730062bd1SDavid Howells 
76830062bd1SDavid Howells /*
76930062bd1SDavid Howells  * FS.RemoveDir and FS.RemoveFile operation types.
77030062bd1SDavid Howells  */
77130062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile = {
77230062bd1SDavid Howells 	.name		= "YFS.RemoveFile",
77330062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile,
77430062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
77530062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
77630062bd1SDavid Howells };
77730062bd1SDavid Howells 
778e49c7b2fSDavid Howells /*
779e49c7b2fSDavid Howells  * Remove a file.
780e49c7b2fSDavid Howells  */
781e49c7b2fSDavid Howells void yfs_fs_remove_file(struct afs_operation *op)
782e49c7b2fSDavid Howells {
783e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
784e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
785e49c7b2fSDavid Howells 	struct afs_call *call;
786e49c7b2fSDavid Howells 	__be32 *bp;
787e49c7b2fSDavid Howells 
788e49c7b2fSDavid Howells 	_enter("");
789e49c7b2fSDavid Howells 
79020325960SDavid Howells 	if (!test_bit(AFS_SERVER_FL_NO_RM2, &op->server->flags))
791e49c7b2fSDavid Howells 		return yfs_fs_remove_file2(op);
792e49c7b2fSDavid Howells 
793e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile,
794e49c7b2fSDavid Howells 				   sizeof(__be32) +
795e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
796e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
797e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
798e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
799e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
800e49c7b2fSDavid Howells 	if (!call)
801e49c7b2fSDavid Howells 		return afs_op_nomem(op);
802e49c7b2fSDavid Howells 
803e49c7b2fSDavid Howells 	/* marshall the parameters */
804e49c7b2fSDavid Howells 	bp = call->request;
805e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE);
806e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
807e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
808e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
809e49c7b2fSDavid Howells 	yfs_check_req(call, bp);
810e49c7b2fSDavid Howells 
811e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
812e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
813e49c7b2fSDavid Howells }
814e49c7b2fSDavid Howells 
81530062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveDir = {
81630062bd1SDavid Howells 	.name		= "YFS.RemoveDir",
81730062bd1SDavid Howells 	.op		= yfs_FS_RemoveDir,
81830062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
81930062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
82030062bd1SDavid Howells };
82130062bd1SDavid Howells 
82230062bd1SDavid Howells /*
823e49c7b2fSDavid Howells  * Remove a directory.
82430062bd1SDavid Howells  */
825e49c7b2fSDavid Howells void yfs_fs_remove_dir(struct afs_operation *op)
82630062bd1SDavid Howells {
827e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
828e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
82930062bd1SDavid Howells 	struct afs_call *call;
83030062bd1SDavid Howells 	__be32 *bp;
83130062bd1SDavid Howells 
83230062bd1SDavid Howells 	_enter("");
83330062bd1SDavid Howells 
834e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveDir,
83530062bd1SDavid Howells 				   sizeof(__be32) +
83630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
83730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
838e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
83930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
84030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
84130062bd1SDavid Howells 	if (!call)
842e49c7b2fSDavid Howells 		return afs_op_nomem(op);
84330062bd1SDavid Howells 
84430062bd1SDavid Howells 	/* marshall the parameters */
84530062bd1SDavid Howells 	bp = call->request;
846e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEDIR);
84730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
848e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
849e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
85030062bd1SDavid Howells 	yfs_check_req(call, bp);
85130062bd1SDavid Howells 
852e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
853e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
85430062bd1SDavid Howells }
85530062bd1SDavid Howells 
85630062bd1SDavid Howells /*
85730062bd1SDavid Howells  * Deliver reply data to a YFS.Link operation.
85830062bd1SDavid Howells  */
85930062bd1SDavid Howells static int yfs_deliver_fs_link(struct afs_call *call)
86030062bd1SDavid Howells {
861e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
862e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
863e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
86430062bd1SDavid Howells 	const __be32 *bp;
86530062bd1SDavid Howells 	int ret;
86630062bd1SDavid Howells 
86730062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
86830062bd1SDavid Howells 
86930062bd1SDavid Howells 	ret = afs_transfer_reply(call);
87030062bd1SDavid Howells 	if (ret < 0)
87130062bd1SDavid Howells 		return ret;
87230062bd1SDavid Howells 
87330062bd1SDavid Howells 	bp = call->buffer;
874e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
875e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
876e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
87730062bd1SDavid Howells 	_leave(" = 0 [done]");
87830062bd1SDavid Howells 	return 0;
87930062bd1SDavid Howells }
88030062bd1SDavid Howells 
88130062bd1SDavid Howells /*
88230062bd1SDavid Howells  * YFS.Link operation type.
88330062bd1SDavid Howells  */
88430062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSLink = {
88530062bd1SDavid Howells 	.name		= "YFS.Link",
88630062bd1SDavid Howells 	.op		= yfs_FS_Link,
88730062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_link,
88830062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
88930062bd1SDavid Howells };
89030062bd1SDavid Howells 
89130062bd1SDavid Howells /*
89230062bd1SDavid Howells  * Make a hard link.
89330062bd1SDavid Howells  */
894e49c7b2fSDavid Howells void yfs_fs_link(struct afs_operation *op)
89530062bd1SDavid Howells {
896e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
897e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
898e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
89930062bd1SDavid Howells 	struct afs_call *call;
90030062bd1SDavid Howells 	__be32 *bp;
90130062bd1SDavid Howells 
90230062bd1SDavid Howells 	_enter("");
90330062bd1SDavid Howells 
904e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSLink,
90530062bd1SDavid Howells 				   sizeof(__be32) +
90630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
90730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
908e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
90930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
91030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
91130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
91230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
91330062bd1SDavid Howells 	if (!call)
914e49c7b2fSDavid Howells 		return afs_op_nomem(op);
91530062bd1SDavid Howells 
91630062bd1SDavid Howells 	/* marshall the parameters */
91730062bd1SDavid Howells 	bp = call->request;
91830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSLINK);
91930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
920e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
921e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
922e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
92330062bd1SDavid Howells 	yfs_check_req(call, bp);
92430062bd1SDavid Howells 
925e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
926e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
92730062bd1SDavid Howells }
92830062bd1SDavid Howells 
92930062bd1SDavid Howells /*
93030062bd1SDavid Howells  * Deliver reply data to a YFS.Symlink operation.
93130062bd1SDavid Howells  */
93230062bd1SDavid Howells static int yfs_deliver_fs_symlink(struct afs_call *call)
93330062bd1SDavid Howells {
934e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
935e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
936e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
93730062bd1SDavid Howells 	const __be32 *bp;
93830062bd1SDavid Howells 	int ret;
93930062bd1SDavid Howells 
94030062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
94130062bd1SDavid Howells 
94230062bd1SDavid Howells 	ret = afs_transfer_reply(call);
94330062bd1SDavid Howells 	if (ret < 0)
94430062bd1SDavid Howells 		return ret;
94530062bd1SDavid Howells 
94630062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
94730062bd1SDavid Howells 	bp = call->buffer;
948e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &vp->fid);
949e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
950e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
951e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
95230062bd1SDavid Howells 
95330062bd1SDavid Howells 	_leave(" = 0 [done]");
95430062bd1SDavid Howells 	return 0;
95530062bd1SDavid Howells }
95630062bd1SDavid Howells 
95730062bd1SDavid Howells /*
95830062bd1SDavid Howells  * YFS.Symlink operation type
95930062bd1SDavid Howells  */
96030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSymlink = {
96130062bd1SDavid Howells 	.name		= "YFS.Symlink",
96230062bd1SDavid Howells 	.op		= yfs_FS_Symlink,
96330062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_symlink,
96430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
96530062bd1SDavid Howells };
96630062bd1SDavid Howells 
96730062bd1SDavid Howells /*
96830062bd1SDavid Howells  * Create a symbolic link.
96930062bd1SDavid Howells  */
970e49c7b2fSDavid Howells void yfs_fs_symlink(struct afs_operation *op)
97130062bd1SDavid Howells {
972e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
973e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
97430062bd1SDavid Howells 	struct afs_call *call;
975e49c7b2fSDavid Howells 	size_t contents_sz;
97630062bd1SDavid Howells 	__be32 *bp;
97730062bd1SDavid Howells 
97830062bd1SDavid Howells 	_enter("");
97930062bd1SDavid Howells 
980e49c7b2fSDavid Howells 	contents_sz = strlen(op->create.symlink);
981e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSymlink,
98230062bd1SDavid Howells 				   sizeof(__be32) +
98330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
98430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
985e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
98630062bd1SDavid Howells 				   xdr_strlen(contents_sz) +
98730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
98830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
98930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
99030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
99130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
99230062bd1SDavid Howells 	if (!call)
993e49c7b2fSDavid Howells 		return afs_op_nomem(op);
99430062bd1SDavid Howells 
99530062bd1SDavid Howells 	/* marshall the parameters */
99630062bd1SDavid Howells 	bp = call->request;
99730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSYMLINK);
99830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
999e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
1000e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
1001e49c7b2fSDavid Howells 	bp = xdr_encode_string(bp, op->create.symlink, contents_sz);
100230062bd1SDavid Howells 	bp = xdr_encode_YFSStoreStatus_mode(bp, S_IRWXUGO);
100330062bd1SDavid Howells 	yfs_check_req(call, bp);
100430062bd1SDavid Howells 
1005e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
1006e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
100730062bd1SDavid Howells }
100830062bd1SDavid Howells 
100930062bd1SDavid Howells /*
101030062bd1SDavid Howells  * Deliver reply data to a YFS.Rename operation.
101130062bd1SDavid Howells  */
101230062bd1SDavid Howells static int yfs_deliver_fs_rename(struct afs_call *call)
101330062bd1SDavid Howells {
1014e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1015e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
1016e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
101730062bd1SDavid Howells 	const __be32 *bp;
101830062bd1SDavid Howells 	int ret;
101930062bd1SDavid Howells 
102030062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
102130062bd1SDavid Howells 
102230062bd1SDavid Howells 	ret = afs_transfer_reply(call);
102330062bd1SDavid Howells 	if (ret < 0)
102430062bd1SDavid Howells 		return ret;
102530062bd1SDavid Howells 
102630062bd1SDavid Howells 	bp = call->buffer;
102738355eecSDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
102838355eecSDavid Howells 	 * report, so we just decode it twice.
102938355eecSDavid Howells 	 */
1030e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &orig_dvp->scb);
1031e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &new_dvp->scb);
1032e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
103330062bd1SDavid Howells 	_leave(" = 0 [done]");
103430062bd1SDavid Howells 	return 0;
103530062bd1SDavid Howells }
103630062bd1SDavid Howells 
103730062bd1SDavid Howells /*
103830062bd1SDavid Howells  * YFS.Rename operation type
103930062bd1SDavid Howells  */
104030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRename = {
104130062bd1SDavid Howells 	.name		= "FS.Rename",
104230062bd1SDavid Howells 	.op		= yfs_FS_Rename,
104330062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_rename,
104430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
104530062bd1SDavid Howells };
104630062bd1SDavid Howells 
104730062bd1SDavid Howells /*
104830062bd1SDavid Howells  * Rename a file or directory.
104930062bd1SDavid Howells  */
1050e49c7b2fSDavid Howells void yfs_fs_rename(struct afs_operation *op)
105130062bd1SDavid Howells {
1052e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
1053e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
1054e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
1055e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
105630062bd1SDavid Howells 	struct afs_call *call;
105730062bd1SDavid Howells 	__be32 *bp;
105830062bd1SDavid Howells 
105930062bd1SDavid Howells 	_enter("");
106030062bd1SDavid Howells 
1061e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRename,
106230062bd1SDavid Howells 				   sizeof(__be32) +
106330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
106430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1065e49c7b2fSDavid Howells 				   xdr_strlen(orig_name->len) +
106630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1067e49c7b2fSDavid Howells 				   xdr_strlen(new_name->len),
106830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
106930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
107030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
107130062bd1SDavid Howells 	if (!call)
1072e49c7b2fSDavid Howells 		return afs_op_nomem(op);
107330062bd1SDavid Howells 
107430062bd1SDavid Howells 	/* marshall the parameters */
107530062bd1SDavid Howells 	bp = call->request;
107630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRENAME);
107730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1078e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &orig_dvp->fid);
1079e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, orig_name);
1080e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &new_dvp->fid);
1081e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, new_name);
108230062bd1SDavid Howells 	yfs_check_req(call, bp);
108330062bd1SDavid Howells 
1084e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1085e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
108630062bd1SDavid Howells }
108730062bd1SDavid Howells 
108830062bd1SDavid Howells /*
108930062bd1SDavid Howells  * YFS.StoreData64 operation type.
109030062bd1SDavid Howells  */
109130062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64 = {
109230062bd1SDavid Howells 	.name		= "YFS.StoreData64",
109330062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1094a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
109530062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
109630062bd1SDavid Howells };
109730062bd1SDavid Howells 
109830062bd1SDavid Howells /*
109930062bd1SDavid Howells  * Store a set of pages to a large file.
110030062bd1SDavid Howells  */
1101e49c7b2fSDavid Howells void yfs_fs_store_data(struct afs_operation *op)
110230062bd1SDavid Howells {
1103e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
110430062bd1SDavid Howells 	struct afs_call *call;
110530062bd1SDavid Howells 	loff_t size, pos, i_size;
110630062bd1SDavid Howells 	__be32 *bp;
110730062bd1SDavid Howells 
110830062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1109e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
111030062bd1SDavid Howells 
1111e49c7b2fSDavid Howells 	size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset;
1112e49c7b2fSDavid Howells 	if (op->store.first != op->store.last)
1113e49c7b2fSDavid Howells 		size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT;
1114e49c7b2fSDavid Howells 	pos = (loff_t)op->store.first << PAGE_SHIFT;
1115e49c7b2fSDavid Howells 	pos += op->store.first_offset;
111630062bd1SDavid Howells 
1117e49c7b2fSDavid Howells 	i_size = i_size_read(&vp->vnode->vfs_inode);
111830062bd1SDavid Howells 	if (pos + size > i_size)
111930062bd1SDavid Howells 		i_size = size + pos;
112030062bd1SDavid Howells 
112130062bd1SDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
112230062bd1SDavid Howells 	       (unsigned long long)size, (unsigned long long)pos,
112330062bd1SDavid Howells 	       (unsigned long long)i_size);
112430062bd1SDavid Howells 
1125e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64,
112630062bd1SDavid Howells 				   sizeof(__be32) +
112730062bd1SDavid Howells 				   sizeof(__be32) +
112830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
112930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
113030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
113130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
113230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
113330062bd1SDavid Howells 	if (!call)
1134e49c7b2fSDavid Howells 		return afs_op_nomem(op);
113530062bd1SDavid Howells 
1136e49c7b2fSDavid Howells 	call->key = op->key;
113730062bd1SDavid Howells 	call->send_pages = true;
113830062bd1SDavid Howells 
113930062bd1SDavid Howells 	/* marshall the parameters */
114030062bd1SDavid Howells 	bp = call->request;
114130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
114230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1143e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1144e49c7b2fSDavid Howells 	bp = xdr_encode_YFSStoreStatus_mtime(bp, &op->mtime);
114530062bd1SDavid Howells 	bp = xdr_encode_u64(bp, pos);
114630062bd1SDavid Howells 	bp = xdr_encode_u64(bp, size);
114730062bd1SDavid Howells 	bp = xdr_encode_u64(bp, i_size);
114830062bd1SDavid Howells 	yfs_check_req(call, bp);
114930062bd1SDavid Howells 
1150e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1151e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
115230062bd1SDavid Howells }
115330062bd1SDavid Howells 
115430062bd1SDavid Howells /*
115530062bd1SDavid Howells  * YFS.StoreStatus operation type
115630062bd1SDavid Howells  */
115730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreStatus = {
115830062bd1SDavid Howells 	.name		= "YFS.StoreStatus",
115930062bd1SDavid Howells 	.op		= yfs_FS_StoreStatus,
1160a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
116130062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
116230062bd1SDavid Howells };
116330062bd1SDavid Howells 
116430062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = {
116530062bd1SDavid Howells 	.name		= "YFS.StoreData64",
116630062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1167a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
116830062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
116930062bd1SDavid Howells };
117030062bd1SDavid Howells 
117130062bd1SDavid Howells /*
117230062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 rather than
117330062bd1SDavid Howells  * YFS.StoreStatus so as to alter the file size also.
117430062bd1SDavid Howells  */
1175e49c7b2fSDavid Howells static void yfs_fs_setattr_size(struct afs_operation *op)
117630062bd1SDavid Howells {
1177e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
117830062bd1SDavid Howells 	struct afs_call *call;
1179e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
118030062bd1SDavid Howells 	__be32 *bp;
118130062bd1SDavid Howells 
118230062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1183e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
118430062bd1SDavid Howells 
1185e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64_as_Status,
118630062bd1SDavid Howells 				   sizeof(__be32) * 2 +
118730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
118830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
118930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
119030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
119130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
119230062bd1SDavid Howells 	if (!call)
1193e49c7b2fSDavid Howells 		return afs_op_nomem(op);
119430062bd1SDavid Howells 
119530062bd1SDavid Howells 	/* marshall the parameters */
119630062bd1SDavid Howells 	bp = call->request;
119730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
119830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1199e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
120030062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
12018c7ae38dSDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* position of start of write */
120230062bd1SDavid Howells 	bp = xdr_encode_u64(bp, 0);		/* size of write */
120330062bd1SDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* new file length */
120430062bd1SDavid Howells 	yfs_check_req(call, bp);
120530062bd1SDavid Howells 
1206e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1207e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
120830062bd1SDavid Howells }
120930062bd1SDavid Howells 
121030062bd1SDavid Howells /*
121130062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 if there's a change in
121230062bd1SDavid Howells  * file size, and YFS.StoreStatus otherwise.
121330062bd1SDavid Howells  */
1214e49c7b2fSDavid Howells void yfs_fs_setattr(struct afs_operation *op)
121530062bd1SDavid Howells {
1216e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
121730062bd1SDavid Howells 	struct afs_call *call;
1218e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
121930062bd1SDavid Howells 	__be32 *bp;
122030062bd1SDavid Howells 
122130062bd1SDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1222e49c7b2fSDavid Howells 		return yfs_fs_setattr_size(op);
122330062bd1SDavid Howells 
122430062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1225e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
122630062bd1SDavid Howells 
1227e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreStatus,
122830062bd1SDavid Howells 				   sizeof(__be32) * 2 +
122930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
123030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
123130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
123230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
123330062bd1SDavid Howells 	if (!call)
1234e49c7b2fSDavid Howells 		return afs_op_nomem(op);
123530062bd1SDavid Howells 
123630062bd1SDavid Howells 	/* marshall the parameters */
123730062bd1SDavid Howells 	bp = call->request;
123830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTORESTATUS);
123930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1240e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
124130062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
124230062bd1SDavid Howells 	yfs_check_req(call, bp);
124330062bd1SDavid Howells 
1244e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1245e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
124630062bd1SDavid Howells }
124730062bd1SDavid Howells 
124830062bd1SDavid Howells /*
124930062bd1SDavid Howells  * Deliver reply data to a YFS.GetVolumeStatus operation.
125030062bd1SDavid Howells  */
125130062bd1SDavid Howells static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
125230062bd1SDavid Howells {
1253e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
125430062bd1SDavid Howells 	const __be32 *bp;
125530062bd1SDavid Howells 	char *p;
125630062bd1SDavid Howells 	u32 size;
125730062bd1SDavid Howells 	int ret;
125830062bd1SDavid Howells 
125930062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
126030062bd1SDavid Howells 
126130062bd1SDavid Howells 	switch (call->unmarshall) {
126230062bd1SDavid Howells 	case 0:
126330062bd1SDavid Howells 		call->unmarshall++;
126430062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchVolumeStatus));
126535a3a90cSGustavo A. R. Silva 		/* Fall through */
126630062bd1SDavid Howells 
126735a3a90cSGustavo A. R. Silva 		/* extract the returned status record */
126830062bd1SDavid Howells 	case 1:
126930062bd1SDavid Howells 		_debug("extract status");
127030062bd1SDavid Howells 		ret = afs_extract_data(call, true);
127130062bd1SDavid Howells 		if (ret < 0)
127230062bd1SDavid Howells 			return ret;
127330062bd1SDavid Howells 
127430062bd1SDavid Howells 		bp = call->buffer;
1275e49c7b2fSDavid Howells 		xdr_decode_YFSFetchVolumeStatus(&bp, &op->volstatus.vs);
127630062bd1SDavid Howells 		call->unmarshall++;
127730062bd1SDavid Howells 		afs_extract_to_tmp(call);
127835a3a90cSGustavo A. R. Silva 		/* Fall through */
127930062bd1SDavid Howells 
128035a3a90cSGustavo A. R. Silva 		/* extract the volume name length */
128130062bd1SDavid Howells 	case 2:
128230062bd1SDavid Howells 		ret = afs_extract_data(call, true);
128330062bd1SDavid Howells 		if (ret < 0)
128430062bd1SDavid Howells 			return ret;
128530062bd1SDavid Howells 
128630062bd1SDavid Howells 		call->count = ntohl(call->tmp);
128730062bd1SDavid Howells 		_debug("volname length: %u", call->count);
128830062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
12897126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
129030062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1291ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
129230062bd1SDavid Howells 		call->unmarshall++;
129335a3a90cSGustavo A. R. Silva 		/* Fall through */
129430062bd1SDavid Howells 
129535a3a90cSGustavo A. R. Silva 		/* extract the volume name */
129630062bd1SDavid Howells 	case 3:
129730062bd1SDavid Howells 		_debug("extract volname");
129830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
129930062bd1SDavid Howells 		if (ret < 0)
130030062bd1SDavid Howells 			return ret;
130130062bd1SDavid Howells 
1302ffba718eSDavid Howells 		p = call->buffer;
130330062bd1SDavid Howells 		p[call->count] = 0;
130430062bd1SDavid Howells 		_debug("volname '%s'", p);
130530062bd1SDavid Howells 		afs_extract_to_tmp(call);
130630062bd1SDavid Howells 		call->unmarshall++;
130735a3a90cSGustavo A. R. Silva 		/* Fall through */
130830062bd1SDavid Howells 
130935a3a90cSGustavo A. R. Silva 		/* extract the offline message length */
131030062bd1SDavid Howells 	case 4:
131130062bd1SDavid Howells 		ret = afs_extract_data(call, true);
131230062bd1SDavid Howells 		if (ret < 0)
131330062bd1SDavid Howells 			return ret;
131430062bd1SDavid Howells 
131530062bd1SDavid Howells 		call->count = ntohl(call->tmp);
131630062bd1SDavid Howells 		_debug("offline msg length: %u", call->count);
131730062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
13187126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
131930062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1320ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
132130062bd1SDavid Howells 		call->unmarshall++;
132235a3a90cSGustavo A. R. Silva 		/* Fall through */
132330062bd1SDavid Howells 
132435a3a90cSGustavo A. R. Silva 		/* extract the offline message */
132530062bd1SDavid Howells 	case 5:
132630062bd1SDavid Howells 		_debug("extract offline");
132730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
132830062bd1SDavid Howells 		if (ret < 0)
132930062bd1SDavid Howells 			return ret;
133030062bd1SDavid Howells 
1331ffba718eSDavid Howells 		p = call->buffer;
133230062bd1SDavid Howells 		p[call->count] = 0;
133330062bd1SDavid Howells 		_debug("offline '%s'", p);
133430062bd1SDavid Howells 
133530062bd1SDavid Howells 		afs_extract_to_tmp(call);
133630062bd1SDavid Howells 		call->unmarshall++;
133735a3a90cSGustavo A. R. Silva 		/* Fall through */
133830062bd1SDavid Howells 
133935a3a90cSGustavo A. R. Silva 		/* extract the message of the day length */
134030062bd1SDavid Howells 	case 6:
134130062bd1SDavid Howells 		ret = afs_extract_data(call, true);
134230062bd1SDavid Howells 		if (ret < 0)
134330062bd1SDavid Howells 			return ret;
134430062bd1SDavid Howells 
134530062bd1SDavid Howells 		call->count = ntohl(call->tmp);
134630062bd1SDavid Howells 		_debug("motd length: %u", call->count);
134730062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
13487126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
134930062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1350ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
135130062bd1SDavid Howells 		call->unmarshall++;
135235a3a90cSGustavo A. R. Silva 		/* Fall through */
135330062bd1SDavid Howells 
135435a3a90cSGustavo A. R. Silva 		/* extract the message of the day */
135530062bd1SDavid Howells 	case 7:
135630062bd1SDavid Howells 		_debug("extract motd");
135730062bd1SDavid Howells 		ret = afs_extract_data(call, false);
135830062bd1SDavid Howells 		if (ret < 0)
135930062bd1SDavid Howells 			return ret;
136030062bd1SDavid Howells 
1361ffba718eSDavid Howells 		p = call->buffer;
136230062bd1SDavid Howells 		p[call->count] = 0;
136330062bd1SDavid Howells 		_debug("motd '%s'", p);
136430062bd1SDavid Howells 
136530062bd1SDavid Howells 		call->unmarshall++;
1366e690c9e3SGustavo A. R. Silva 		/* Fall through */
136735a3a90cSGustavo A. R. Silva 
136830062bd1SDavid Howells 	case 8:
136930062bd1SDavid Howells 		break;
137030062bd1SDavid Howells 	}
137130062bd1SDavid Howells 
137230062bd1SDavid Howells 	_leave(" = 0 [done]");
137330062bd1SDavid Howells 	return 0;
137430062bd1SDavid Howells }
137530062bd1SDavid Howells 
137630062bd1SDavid Howells /*
137730062bd1SDavid Howells  * YFS.GetVolumeStatus operation type
137830062bd1SDavid Howells  */
137930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSGetVolumeStatus = {
138030062bd1SDavid Howells 	.name		= "YFS.GetVolumeStatus",
138130062bd1SDavid Howells 	.op		= yfs_FS_GetVolumeStatus,
138230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_get_volume_status,
1383ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
138430062bd1SDavid Howells };
138530062bd1SDavid Howells 
138630062bd1SDavid Howells /*
138730062bd1SDavid Howells  * fetch the status of a volume
138830062bd1SDavid Howells  */
1389e49c7b2fSDavid Howells void yfs_fs_get_volume_status(struct afs_operation *op)
139030062bd1SDavid Howells {
1391e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
139230062bd1SDavid Howells 	struct afs_call *call;
139330062bd1SDavid Howells 	__be32 *bp;
139430062bd1SDavid Howells 
139530062bd1SDavid Howells 	_enter("");
139630062bd1SDavid Howells 
1397e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSGetVolumeStatus,
139830062bd1SDavid Howells 				   sizeof(__be32) * 2 +
139930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64),
1400ffba718eSDavid Howells 				   max_t(size_t,
140130062bd1SDavid Howells 					 sizeof(struct yfs_xdr_YFSFetchVolumeStatus) +
1402ffba718eSDavid Howells 					 sizeof(__be32),
1403ffba718eSDavid Howells 					 AFSOPAQUEMAX + 1));
1404ffba718eSDavid Howells 	if (!call)
1405e49c7b2fSDavid Howells 		return afs_op_nomem(op);
140630062bd1SDavid Howells 
140730062bd1SDavid Howells 	/* marshall the parameters */
140830062bd1SDavid Howells 	bp = call->request;
140930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSGETVOLUMESTATUS);
141030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1411e49c7b2fSDavid Howells 	bp = xdr_encode_u64(bp, vp->fid.vid);
141230062bd1SDavid Howells 	yfs_check_req(call, bp);
141330062bd1SDavid Howells 
1414e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1415e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
141630062bd1SDavid Howells }
141730062bd1SDavid Howells 
141830062bd1SDavid Howells /*
141930062bd1SDavid Howells  * YFS.SetLock operation type
142030062bd1SDavid Howells  */
142130062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSetLock = {
142230062bd1SDavid Howells 	.name		= "YFS.SetLock",
142330062bd1SDavid Howells 	.op		= yfs_FS_SetLock,
1424f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1425a690f60aSDavid Howells 	.done		= afs_lock_op_done,
142630062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
142730062bd1SDavid Howells };
142830062bd1SDavid Howells 
142930062bd1SDavid Howells /*
143030062bd1SDavid Howells  * YFS.ExtendLock operation type
143130062bd1SDavid Howells  */
143230062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSExtendLock = {
143330062bd1SDavid Howells 	.name		= "YFS.ExtendLock",
143430062bd1SDavid Howells 	.op		= yfs_FS_ExtendLock,
1435f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1436a690f60aSDavid Howells 	.done		= afs_lock_op_done,
143730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
143830062bd1SDavid Howells };
143930062bd1SDavid Howells 
144030062bd1SDavid Howells /*
144130062bd1SDavid Howells  * YFS.ReleaseLock operation type
144230062bd1SDavid Howells  */
144330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSReleaseLock = {
144430062bd1SDavid Howells 	.name		= "YFS.ReleaseLock",
144530062bd1SDavid Howells 	.op		= yfs_FS_ReleaseLock,
1446f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
144730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
144830062bd1SDavid Howells };
144930062bd1SDavid Howells 
145030062bd1SDavid Howells /*
145130062bd1SDavid Howells  * Set a lock on a file
145230062bd1SDavid Howells  */
1453e49c7b2fSDavid Howells void yfs_fs_set_lock(struct afs_operation *op)
145430062bd1SDavid Howells {
1455e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
145630062bd1SDavid Howells 	struct afs_call *call;
145730062bd1SDavid Howells 	__be32 *bp;
145830062bd1SDavid Howells 
145930062bd1SDavid Howells 	_enter("");
146030062bd1SDavid Howells 
1461e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSetLock,
146230062bd1SDavid Howells 				   sizeof(__be32) * 2 +
146330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
146430062bd1SDavid Howells 				   sizeof(__be32),
146530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
146630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
146730062bd1SDavid Howells 	if (!call)
1468e49c7b2fSDavid Howells 		return afs_op_nomem(op);
146930062bd1SDavid Howells 
147030062bd1SDavid Howells 	/* marshall the parameters */
147130062bd1SDavid Howells 	bp = call->request;
147230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSETLOCK);
147330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1474e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1475e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->lock.type);
147630062bd1SDavid Howells 	yfs_check_req(call, bp);
147730062bd1SDavid Howells 
1478e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1479e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
148030062bd1SDavid Howells }
148130062bd1SDavid Howells 
148230062bd1SDavid Howells /*
148330062bd1SDavid Howells  * extend a lock on a file
148430062bd1SDavid Howells  */
1485e49c7b2fSDavid Howells void yfs_fs_extend_lock(struct afs_operation *op)
148630062bd1SDavid Howells {
1487e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
148830062bd1SDavid Howells 	struct afs_call *call;
148930062bd1SDavid Howells 	__be32 *bp;
149030062bd1SDavid Howells 
149130062bd1SDavid Howells 	_enter("");
149230062bd1SDavid Howells 
1493e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSExtendLock,
149430062bd1SDavid Howells 				   sizeof(__be32) * 2 +
149530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
149630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
149730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
149830062bd1SDavid Howells 	if (!call)
1499e49c7b2fSDavid Howells 		return afs_op_nomem(op);
150030062bd1SDavid Howells 
150130062bd1SDavid Howells 	/* marshall the parameters */
150230062bd1SDavid Howells 	bp = call->request;
150330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSEXTENDLOCK);
150430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1505e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
150630062bd1SDavid Howells 	yfs_check_req(call, bp);
150730062bd1SDavid Howells 
1508e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1509e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
151030062bd1SDavid Howells }
151130062bd1SDavid Howells 
151230062bd1SDavid Howells /*
151330062bd1SDavid Howells  * release a lock on a file
151430062bd1SDavid Howells  */
1515e49c7b2fSDavid Howells void yfs_fs_release_lock(struct afs_operation *op)
151630062bd1SDavid Howells {
1517e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
151830062bd1SDavid Howells 	struct afs_call *call;
151930062bd1SDavid Howells 	__be32 *bp;
152030062bd1SDavid Howells 
152130062bd1SDavid Howells 	_enter("");
152230062bd1SDavid Howells 
1523e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSReleaseLock,
152430062bd1SDavid Howells 				   sizeof(__be32) * 2 +
152530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
152630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
152730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
152830062bd1SDavid Howells 	if (!call)
1529e49c7b2fSDavid Howells 		return afs_op_nomem(op);
153030062bd1SDavid Howells 
153130062bd1SDavid Howells 	/* marshall the parameters */
153230062bd1SDavid Howells 	bp = call->request;
153330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRELEASELOCK);
153430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1535e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
153630062bd1SDavid Howells 	yfs_check_req(call, bp);
153730062bd1SDavid Howells 
1538e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1539e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
154030062bd1SDavid Howells }
154130062bd1SDavid Howells 
154230062bd1SDavid Howells /*
1543*9bd87ec6SDavid Howells  * Deliver a reply to YFS.FetchStatus
1544*9bd87ec6SDavid Howells  */
1545*9bd87ec6SDavid Howells static int yfs_deliver_fs_fetch_status(struct afs_call *call)
1546*9bd87ec6SDavid Howells {
1547*9bd87ec6SDavid Howells 	struct afs_operation *op = call->op;
1548*9bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
1549*9bd87ec6SDavid Howells 	const __be32 *bp;
1550*9bd87ec6SDavid Howells 	int ret;
1551*9bd87ec6SDavid Howells 
1552*9bd87ec6SDavid Howells 	ret = afs_transfer_reply(call);
1553*9bd87ec6SDavid Howells 	if (ret < 0)
1554*9bd87ec6SDavid Howells 		return ret;
1555*9bd87ec6SDavid Howells 
1556*9bd87ec6SDavid Howells 	/* unmarshall the reply once we've received all of it */
1557*9bd87ec6SDavid Howells 	bp = call->buffer;
1558*9bd87ec6SDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
1559*9bd87ec6SDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
1560*9bd87ec6SDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
1561*9bd87ec6SDavid Howells 
1562*9bd87ec6SDavid Howells 	_leave(" = 0 [done]");
1563*9bd87ec6SDavid Howells 	return 0;
1564*9bd87ec6SDavid Howells }
1565*9bd87ec6SDavid Howells 
1566*9bd87ec6SDavid Howells /*
156730062bd1SDavid Howells  * YFS.FetchStatus operation type
156830062bd1SDavid Howells  */
156930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchStatus = {
157030062bd1SDavid Howells 	.name		= "YFS.FetchStatus",
157130062bd1SDavid Howells 	.op		= yfs_FS_FetchStatus,
1572*9bd87ec6SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_status,
157330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
157430062bd1SDavid Howells };
157530062bd1SDavid Howells 
157630062bd1SDavid Howells /*
157730062bd1SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
157830062bd1SDavid Howells  */
1579e49c7b2fSDavid Howells void yfs_fs_fetch_status(struct afs_operation *op)
158030062bd1SDavid Howells {
1581*9bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
158230062bd1SDavid Howells 	struct afs_call *call;
158330062bd1SDavid Howells 	__be32 *bp;
158430062bd1SDavid Howells 
158530062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1586e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
158730062bd1SDavid Howells 
1588e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchStatus,
158930062bd1SDavid Howells 				   sizeof(__be32) * 2 +
159030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
159130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
159230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
159330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1594e49c7b2fSDavid Howells 	if (!call)
1595e49c7b2fSDavid Howells 		return afs_op_nomem(op);
159630062bd1SDavid Howells 
159730062bd1SDavid Howells 	/* marshall the parameters */
159830062bd1SDavid Howells 	bp = call->request;
159930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHSTATUS);
160030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1601e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
160230062bd1SDavid Howells 	yfs_check_req(call, bp);
160330062bd1SDavid Howells 
1604e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1605e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
160630062bd1SDavid Howells }
160730062bd1SDavid Howells 
160830062bd1SDavid Howells /*
160930062bd1SDavid Howells  * Deliver reply data to an YFS.InlineBulkStatus call
161030062bd1SDavid Howells  */
161130062bd1SDavid Howells static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
161230062bd1SDavid Howells {
1613e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
161487182759SDavid Howells 	struct afs_status_cb *scb;
161530062bd1SDavid Howells 	const __be32 *bp;
161630062bd1SDavid Howells 	u32 tmp;
161730062bd1SDavid Howells 	int ret;
161830062bd1SDavid Howells 
161930062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
162030062bd1SDavid Howells 
162130062bd1SDavid Howells 	switch (call->unmarshall) {
162230062bd1SDavid Howells 	case 0:
162330062bd1SDavid Howells 		afs_extract_to_tmp(call);
162430062bd1SDavid Howells 		call->unmarshall++;
162535a3a90cSGustavo A. R. Silva 		/* Fall through */
162630062bd1SDavid Howells 
162730062bd1SDavid Howells 		/* Extract the file status count and array in two steps */
162830062bd1SDavid Howells 	case 1:
162930062bd1SDavid Howells 		_debug("extract status count");
163030062bd1SDavid Howells 		ret = afs_extract_data(call, true);
163130062bd1SDavid Howells 		if (ret < 0)
163230062bd1SDavid Howells 			return ret;
163330062bd1SDavid Howells 
163430062bd1SDavid Howells 		tmp = ntohl(call->tmp);
1635e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1636e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
16377126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
163830062bd1SDavid Howells 
163930062bd1SDavid Howells 		call->count = 0;
164030062bd1SDavid Howells 		call->unmarshall++;
164130062bd1SDavid Howells 	more_counts:
164230062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchStatus));
1643e690c9e3SGustavo A. R. Silva 		/* Fall through */
164435a3a90cSGustavo A. R. Silva 
164530062bd1SDavid Howells 	case 2:
164630062bd1SDavid Howells 		_debug("extract status array %u", call->count);
164730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
164830062bd1SDavid Howells 		if (ret < 0)
164930062bd1SDavid Howells 			return ret;
165030062bd1SDavid Howells 
1651e49c7b2fSDavid Howells 		switch (call->count) {
1652e49c7b2fSDavid Howells 		case 0:
1653e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1654e49c7b2fSDavid Howells 			break;
1655e49c7b2fSDavid Howells 		case 1:
1656e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1657e49c7b2fSDavid Howells 			break;
1658e49c7b2fSDavid Howells 		default:
1659e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1660e49c7b2fSDavid Howells 			break;
1661e49c7b2fSDavid Howells 		}
1662e49c7b2fSDavid Howells 
166330062bd1SDavid Howells 		bp = call->buffer;
166438355eecSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, scb);
166530062bd1SDavid Howells 
166630062bd1SDavid Howells 		call->count++;
1667e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
166830062bd1SDavid Howells 			goto more_counts;
166930062bd1SDavid Howells 
167030062bd1SDavid Howells 		call->count = 0;
167130062bd1SDavid Howells 		call->unmarshall++;
167230062bd1SDavid Howells 		afs_extract_to_tmp(call);
167335a3a90cSGustavo A. R. Silva 		/* Fall through */
167430062bd1SDavid Howells 
167530062bd1SDavid Howells 		/* Extract the callback count and array in two steps */
167630062bd1SDavid Howells 	case 3:
167730062bd1SDavid Howells 		_debug("extract CB count");
167830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
167930062bd1SDavid Howells 		if (ret < 0)
168030062bd1SDavid Howells 			return ret;
168130062bd1SDavid Howells 
168230062bd1SDavid Howells 		tmp = ntohl(call->tmp);
168330062bd1SDavid Howells 		_debug("CB count: %u", tmp);
1684e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
16857126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
168630062bd1SDavid Howells 		call->count = 0;
168730062bd1SDavid Howells 		call->unmarshall++;
168830062bd1SDavid Howells 	more_cbs:
168930062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSCallBack));
1690e690c9e3SGustavo A. R. Silva 		/* Fall through */
169135a3a90cSGustavo A. R. Silva 
169230062bd1SDavid Howells 	case 4:
169330062bd1SDavid Howells 		_debug("extract CB array");
169430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
169530062bd1SDavid Howells 		if (ret < 0)
169630062bd1SDavid Howells 			return ret;
169730062bd1SDavid Howells 
169830062bd1SDavid Howells 		_debug("unmarshall CB array");
1699e49c7b2fSDavid Howells 		switch (call->count) {
1700e49c7b2fSDavid Howells 		case 0:
1701e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1702e49c7b2fSDavid Howells 			break;
1703e49c7b2fSDavid Howells 		case 1:
1704e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1705e49c7b2fSDavid Howells 			break;
1706e49c7b2fSDavid Howells 		default:
1707e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1708e49c7b2fSDavid Howells 			break;
1709e49c7b2fSDavid Howells 		}
1710e49c7b2fSDavid Howells 
171130062bd1SDavid Howells 		bp = call->buffer;
1712a58823acSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, scb);
171330062bd1SDavid Howells 		call->count++;
1714e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
171530062bd1SDavid Howells 			goto more_cbs;
171630062bd1SDavid Howells 
171730062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSVolSync));
171830062bd1SDavid Howells 		call->unmarshall++;
1719e690c9e3SGustavo A. R. Silva 		/* Fall through */
172035a3a90cSGustavo A. R. Silva 
172130062bd1SDavid Howells 	case 5:
172230062bd1SDavid Howells 		ret = afs_extract_data(call, false);
172330062bd1SDavid Howells 		if (ret < 0)
172430062bd1SDavid Howells 			return ret;
172530062bd1SDavid Howells 
172630062bd1SDavid Howells 		bp = call->buffer;
1727e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
172830062bd1SDavid Howells 
172930062bd1SDavid Howells 		call->unmarshall++;
1730e690c9e3SGustavo A. R. Silva 		/* Fall through */
173135a3a90cSGustavo A. R. Silva 
173230062bd1SDavid Howells 	case 6:
173330062bd1SDavid Howells 		break;
173430062bd1SDavid Howells 	}
173530062bd1SDavid Howells 
173630062bd1SDavid Howells 	_leave(" = 0 [done]");
173730062bd1SDavid Howells 	return 0;
173830062bd1SDavid Howells }
173930062bd1SDavid Howells 
174030062bd1SDavid Howells /*
174130062bd1SDavid Howells  * FS.InlineBulkStatus operation type
174230062bd1SDavid Howells  */
174330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
174430062bd1SDavid Howells 	.name		= "YFS.InlineBulkStatus",
174530062bd1SDavid Howells 	.op		= yfs_FS_InlineBulkStatus,
174630062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_inline_bulk_status,
174730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
174830062bd1SDavid Howells };
174930062bd1SDavid Howells 
175030062bd1SDavid Howells /*
175130062bd1SDavid Howells  * Fetch the status information for up to 1024 files
175230062bd1SDavid Howells  */
1753e49c7b2fSDavid Howells void yfs_fs_inline_bulk_status(struct afs_operation *op)
175430062bd1SDavid Howells {
1755e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1756e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
175730062bd1SDavid Howells 	struct afs_call *call;
175830062bd1SDavid Howells 	__be32 *bp;
175930062bd1SDavid Howells 	int i;
176030062bd1SDavid Howells 
176130062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1762e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
176330062bd1SDavid Howells 
1764e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSInlineBulkStatus,
176530062bd1SDavid Howells 				   sizeof(__be32) +
176630062bd1SDavid Howells 				   sizeof(__be32) +
176730062bd1SDavid Howells 				   sizeof(__be32) +
1768e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) * op->nr_files,
176930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus));
1770e49c7b2fSDavid Howells 	if (!call)
1771e49c7b2fSDavid Howells 		return afs_op_nomem(op);
177230062bd1SDavid Howells 
177330062bd1SDavid Howells 	/* marshall the parameters */
177430062bd1SDavid Howells 	bp = call->request;
177530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSINLINEBULKSTATUS);
177630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPCFlags */
1777e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->nr_files);
1778e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
1779e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1780e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++)
1781e49c7b2fSDavid Howells 		bp = xdr_encode_YFSFid(bp, &op->more_files[i].fid);
178230062bd1SDavid Howells 	yfs_check_req(call, bp);
178330062bd1SDavid Howells 
1784e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1785e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
178630062bd1SDavid Howells }
1787ae46578bSDavid Howells 
1788ae46578bSDavid Howells /*
1789ae46578bSDavid Howells  * Deliver reply data to an YFS.FetchOpaqueACL.
1790ae46578bSDavid Howells  */
1791ae46578bSDavid Howells static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
1792ae46578bSDavid Howells {
1793e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1794e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1795e49c7b2fSDavid Howells 	struct yfs_acl *yacl = op->yacl;
1796ae46578bSDavid Howells 	struct afs_acl *acl;
1797ae46578bSDavid Howells 	const __be32 *bp;
1798ae46578bSDavid Howells 	unsigned int size;
1799ae46578bSDavid Howells 	int ret;
1800ae46578bSDavid Howells 
1801ae46578bSDavid Howells 	_enter("{%u}", call->unmarshall);
1802ae46578bSDavid Howells 
1803ae46578bSDavid Howells 	switch (call->unmarshall) {
1804ae46578bSDavid Howells 	case 0:
1805ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1806ae46578bSDavid Howells 		call->unmarshall++;
180735a3a90cSGustavo A. R. Silva 		/* Fall through */
1808ae46578bSDavid Howells 
1809ae46578bSDavid Howells 		/* Extract the file ACL length */
1810ae46578bSDavid Howells 	case 1:
1811ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1812ae46578bSDavid Howells 		if (ret < 0)
1813ae46578bSDavid Howells 			return ret;
1814ae46578bSDavid Howells 
1815ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1816ae46578bSDavid Howells 		size = round_up(size, 4);
1817ae46578bSDavid Howells 
1818ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_ACL) {
1819ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1820ae46578bSDavid Howells 			if (!acl)
1821ae46578bSDavid Howells 				return -ENOMEM;
1822ae46578bSDavid Howells 			yacl->acl = acl;
1823ae46578bSDavid Howells 			acl->size = call->count2;
1824ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1825ae46578bSDavid Howells 		} else {
182623a28913SDavid Howells 			afs_extract_discard(call, size);
1827ae46578bSDavid Howells 		}
1828ae46578bSDavid Howells 		call->unmarshall++;
182935a3a90cSGustavo A. R. Silva 		/* Fall through */
1830ae46578bSDavid Howells 
1831ae46578bSDavid Howells 		/* Extract the file ACL */
1832ae46578bSDavid Howells 	case 2:
1833ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1834ae46578bSDavid Howells 		if (ret < 0)
1835ae46578bSDavid Howells 			return ret;
1836ae46578bSDavid Howells 
1837ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1838ae46578bSDavid Howells 		call->unmarshall++;
183935a3a90cSGustavo A. R. Silva 		/* Fall through */
1840ae46578bSDavid Howells 
1841ae46578bSDavid Howells 		/* Extract the volume ACL length */
1842ae46578bSDavid Howells 	case 3:
1843ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1844ae46578bSDavid Howells 		if (ret < 0)
1845ae46578bSDavid Howells 			return ret;
1846ae46578bSDavid Howells 
1847ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1848ae46578bSDavid Howells 		size = round_up(size, 4);
1849ae46578bSDavid Howells 
1850ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_VOL_ACL) {
1851ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1852ae46578bSDavid Howells 			if (!acl)
1853ae46578bSDavid Howells 				return -ENOMEM;
1854ae46578bSDavid Howells 			yacl->vol_acl = acl;
1855ae46578bSDavid Howells 			acl->size = call->count2;
1856ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1857ae46578bSDavid Howells 		} else {
185823a28913SDavid Howells 			afs_extract_discard(call, size);
1859ae46578bSDavid Howells 		}
1860ae46578bSDavid Howells 		call->unmarshall++;
186135a3a90cSGustavo A. R. Silva 		/* Fall through */
1862ae46578bSDavid Howells 
1863ae46578bSDavid Howells 		/* Extract the volume ACL */
1864ae46578bSDavid Howells 	case 4:
1865ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1866ae46578bSDavid Howells 		if (ret < 0)
1867ae46578bSDavid Howells 			return ret;
1868ae46578bSDavid Howells 
1869ae46578bSDavid Howells 		afs_extract_to_buf(call,
1870ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1871ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1872ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1873ae46578bSDavid Howells 		call->unmarshall++;
187435a3a90cSGustavo A. R. Silva 		/* Fall through */
1875ae46578bSDavid Howells 
1876ae46578bSDavid Howells 		/* extract the metadata */
1877ae46578bSDavid Howells 	case 5:
1878ae46578bSDavid Howells 		ret = afs_extract_data(call, false);
1879ae46578bSDavid Howells 		if (ret < 0)
1880ae46578bSDavid Howells 			return ret;
1881ae46578bSDavid Howells 
1882ae46578bSDavid Howells 		bp = call->buffer;
1883ae46578bSDavid Howells 		yacl->inherit_flag = ntohl(*bp++);
1884ae46578bSDavid Howells 		yacl->num_cleaned = ntohl(*bp++);
1885e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
1886e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
1887ae46578bSDavid Howells 
1888ae46578bSDavid Howells 		call->unmarshall++;
188935a3a90cSGustavo A. R. Silva 		/* Fall through */
1890ae46578bSDavid Howells 
1891ae46578bSDavid Howells 	case 6:
1892ae46578bSDavid Howells 		break;
1893ae46578bSDavid Howells 	}
1894ae46578bSDavid Howells 
1895ae46578bSDavid Howells 	_leave(" = 0 [done]");
1896ae46578bSDavid Howells 	return 0;
1897ae46578bSDavid Howells }
1898ae46578bSDavid Howells 
1899ae46578bSDavid Howells void yfs_free_opaque_acl(struct yfs_acl *yacl)
1900ae46578bSDavid Howells {
1901ae46578bSDavid Howells 	if (yacl) {
1902ae46578bSDavid Howells 		kfree(yacl->acl);
1903ae46578bSDavid Howells 		kfree(yacl->vol_acl);
1904ae46578bSDavid Howells 		kfree(yacl);
1905ae46578bSDavid Howells 	}
1906ae46578bSDavid Howells }
1907ae46578bSDavid Howells 
1908ae46578bSDavid Howells /*
1909ae46578bSDavid Howells  * YFS.FetchOpaqueACL operation type
1910ae46578bSDavid Howells  */
1911ae46578bSDavid Howells static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
1912ae46578bSDavid Howells 	.name		= "YFS.FetchOpaqueACL",
1913ae46578bSDavid Howells 	.op		= yfs_FS_FetchOpaqueACL,
1914ae46578bSDavid Howells 	.deliver	= yfs_deliver_fs_fetch_opaque_acl,
1915773e0c40SDavid Howells 	.destructor	= afs_flat_call_destructor,
1916ae46578bSDavid Howells };
1917ae46578bSDavid Howells 
1918ae46578bSDavid Howells /*
1919ae46578bSDavid Howells  * Fetch the YFS advanced ACLs for a file.
1920ae46578bSDavid Howells  */
1921e49c7b2fSDavid Howells void yfs_fs_fetch_opaque_acl(struct afs_operation *op)
1922ae46578bSDavid Howells {
1923e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1924ae46578bSDavid Howells 	struct afs_call *call;
1925ae46578bSDavid Howells 	__be32 *bp;
1926ae46578bSDavid Howells 
1927ae46578bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1928e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1929ae46578bSDavid Howells 
1930e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchOpaqueACL,
1931ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1932ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
1933ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1934ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1935ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1936e49c7b2fSDavid Howells 	if (!call)
1937e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1938ae46578bSDavid Howells 
1939ae46578bSDavid Howells 	/* marshall the parameters */
1940ae46578bSDavid Howells 	bp = call->request;
1941ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHOPAQUEACL);
1942ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1943e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1944ae46578bSDavid Howells 	yfs_check_req(call, bp);
1945ae46578bSDavid Howells 
1946e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1947e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
1948ae46578bSDavid Howells }
1949f5e45463SDavid Howells 
1950f5e45463SDavid Howells /*
1951f5e45463SDavid Howells  * YFS.StoreOpaqueACL2 operation type
1952f5e45463SDavid Howells  */
1953f5e45463SDavid Howells static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
1954f5e45463SDavid Howells 	.name		= "YFS.StoreOpaqueACL2",
1955f5e45463SDavid Howells 	.op		= yfs_FS_StoreOpaqueACL2,
1956f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1957f5e45463SDavid Howells 	.destructor	= afs_flat_call_destructor,
1958f5e45463SDavid Howells };
1959f5e45463SDavid Howells 
1960f5e45463SDavid Howells /*
1961f5e45463SDavid Howells  * Fetch the YFS ACL for a file.
1962f5e45463SDavid Howells  */
1963e49c7b2fSDavid Howells void yfs_fs_store_opaque_acl2(struct afs_operation *op)
1964f5e45463SDavid Howells {
1965e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1966f5e45463SDavid Howells 	struct afs_call *call;
1967e49c7b2fSDavid Howells 	struct afs_acl *acl = op->acl;
1968f5e45463SDavid Howells 	size_t size;
1969f5e45463SDavid Howells 	__be32 *bp;
1970f5e45463SDavid Howells 
1971f5e45463SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1972e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1973f5e45463SDavid Howells 
1974f5e45463SDavid Howells 	size = round_up(acl->size, 4);
1975e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreOpaqueACL2,
1976f5e45463SDavid Howells 				   sizeof(__be32) * 2 +
1977f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1978f5e45463SDavid Howells 				   sizeof(__be32) + size,
1979f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1980f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1981e49c7b2fSDavid Howells 	if (!call)
1982e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1983f5e45463SDavid Howells 
1984f5e45463SDavid Howells 	/* marshall the parameters */
1985f5e45463SDavid Howells 	bp = call->request;
1986f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
1987f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1988e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1989f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, acl->size);
1990f5e45463SDavid Howells 	memcpy(bp, acl->data, acl->size);
1991f5e45463SDavid Howells 	if (acl->size != size)
1992f5e45463SDavid Howells 		memset((void *)bp + acl->size, 0, size - acl->size);
1993f5e45463SDavid Howells 	yfs_check_req(call, bp);
1994f5e45463SDavid Howells 
1995e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1996e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
199730062bd1SDavid Howells }
1998