xref: /openbmc/linux/fs/afs/yfsclient.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
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 
xdr_decode_YFSFid(const __be32 ** _bp,struct afs_fid * fid)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 
xdr_encode_u32(__be32 * bp,u32 n)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 
xdr_encode_u64(__be32 * bp,u64 n)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 
xdr_encode_YFSFid(__be32 * bp,struct afs_fid * fid)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 
xdr_strlen(unsigned int len)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 
xdr_encode_string(__be32 * bp,const char * p,unsigned int len)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 
xdr_encode_name(__be32 * bp,const struct qstr * p)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 
linux_to_yfs_time(const struct timespec64 * t)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 
xdr_encode_YFSStoreStatus(__be32 * bp,mode_t * mode,const struct timespec64 * t)8652af7105SMarc Dionne static __be32 *xdr_encode_YFSStoreStatus(__be32 *bp, mode_t *mode,
8752af7105SMarc Dionne 					 const struct timespec64 *t)
8830062bd1SDavid Howells {
8930062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
9052af7105SMarc Dionne 	mode_t masked_mode = mode ? *mode & S_IALLUGO : 0;
9130062bd1SDavid Howells 	s64 mtime = linux_to_yfs_time(t);
9252af7105SMarc Dionne 	u32 mask = AFS_SET_MTIME;
9330062bd1SDavid Howells 
9452af7105SMarc Dionne 	mask |= mode ? AFS_SET_MODE : 0;
9552af7105SMarc Dionne 
9652af7105SMarc Dionne 	x->mask		= htonl(mask);
9752af7105SMarc Dionne 	x->mode		= htonl(masked_mode);
9830062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(mtime);
9930062bd1SDavid Howells 	x->owner	= u64_to_xdr(0);
10030062bd1SDavid Howells 	x->group	= u64_to_xdr(0);
10130062bd1SDavid Howells 	return bp + xdr_size(x);
10230062bd1SDavid Howells }
10330062bd1SDavid Howells 
10430062bd1SDavid Howells /*
10530062bd1SDavid Howells  * Convert a signed 100ns-resolution 64-bit time into a timespec.
10630062bd1SDavid Howells  */
yfs_time_to_linux(s64 t)10730062bd1SDavid Howells static struct timespec64 yfs_time_to_linux(s64 t)
10830062bd1SDavid Howells {
10930062bd1SDavid Howells 	struct timespec64 ts;
11030062bd1SDavid Howells 	u64 abs_t;
11130062bd1SDavid Howells 
11230062bd1SDavid Howells 	/*
11330062bd1SDavid Howells 	 * Unfortunately can not use normal 64 bit division on 32 bit arch, but
11430062bd1SDavid Howells 	 * the alternative, do_div, does not work with negative numbers so have
11530062bd1SDavid Howells 	 * to special case them
11630062bd1SDavid Howells 	 */
11730062bd1SDavid Howells 	if (t < 0) {
11830062bd1SDavid Howells 		abs_t = -t;
11930062bd1SDavid Howells 		ts.tv_nsec = (time64_t)(do_div(abs_t, 10000000) * 100);
12030062bd1SDavid Howells 		ts.tv_nsec = -ts.tv_nsec;
12130062bd1SDavid Howells 		ts.tv_sec = -abs_t;
12230062bd1SDavid Howells 	} else {
12330062bd1SDavid Howells 		abs_t = t;
12430062bd1SDavid Howells 		ts.tv_nsec = (time64_t)do_div(abs_t, 10000000) * 100;
12530062bd1SDavid Howells 		ts.tv_sec = abs_t;
12630062bd1SDavid Howells 	}
12730062bd1SDavid Howells 
12830062bd1SDavid Howells 	return ts;
12930062bd1SDavid Howells }
13030062bd1SDavid Howells 
xdr_to_time(const struct yfs_xdr_u64 xdr)13130062bd1SDavid Howells static struct timespec64 xdr_to_time(const struct yfs_xdr_u64 xdr)
13230062bd1SDavid Howells {
13330062bd1SDavid Howells 	s64 t = xdr_to_u64(xdr);
13430062bd1SDavid Howells 
13530062bd1SDavid Howells 	return yfs_time_to_linux(t);
13630062bd1SDavid Howells }
13730062bd1SDavid Howells 
yfs_check_req(struct afs_call * call,__be32 * bp)13830062bd1SDavid Howells static void yfs_check_req(struct afs_call *call, __be32 *bp)
13930062bd1SDavid Howells {
14030062bd1SDavid Howells 	size_t len = (void *)bp - call->request;
14130062bd1SDavid Howells 
14230062bd1SDavid Howells 	if (len > call->request_size)
14330062bd1SDavid Howells 		pr_err("kAFS: %s: Request buffer overflow (%zu>%u)\n",
14430062bd1SDavid Howells 		       call->type->name, len, call->request_size);
14530062bd1SDavid Howells 	else if (len < call->request_size)
146a4e530aeSKefeng Wang 		pr_warn("kAFS: %s: Request buffer underflow (%zu<%u)\n",
14730062bd1SDavid Howells 			call->type->name, len, call->request_size);
14830062bd1SDavid Howells }
14930062bd1SDavid Howells 
15030062bd1SDavid Howells /*
15130062bd1SDavid Howells  * Dump a bad file status record.
15230062bd1SDavid Howells  */
xdr_dump_bad(const __be32 * bp)15330062bd1SDavid Howells static void xdr_dump_bad(const __be32 *bp)
15430062bd1SDavid Howells {
15530062bd1SDavid Howells 	__be32 x[4];
15630062bd1SDavid Howells 	int i;
15730062bd1SDavid Howells 
15830062bd1SDavid Howells 	pr_notice("YFS XDR: Bad status record\n");
1593efe55b0SDavid Howells 	for (i = 0; i < 6 * 4 * 4; i += 16) {
16030062bd1SDavid Howells 		memcpy(x, bp, 16);
16130062bd1SDavid Howells 		bp += 4;
16230062bd1SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
16330062bd1SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
16430062bd1SDavid Howells 	}
16530062bd1SDavid Howells 
1663efe55b0SDavid Howells 	memcpy(x, bp, 8);
1673efe55b0SDavid Howells 	pr_notice("0x60: %08x %08x\n", ntohl(x[0]), ntohl(x[1]));
16830062bd1SDavid Howells }
16930062bd1SDavid Howells 
17030062bd1SDavid Howells /*
17130062bd1SDavid Howells  * Decode a YFSFetchStatus block
17230062bd1SDavid Howells  */
xdr_decode_YFSFetchStatus(const __be32 ** _bp,struct afs_call * call,struct afs_status_cb * scb)17338355eecSDavid Howells static void xdr_decode_YFSFetchStatus(const __be32 **_bp,
174a58823acSDavid Howells 				      struct afs_call *call,
175a58823acSDavid Howells 				      struct afs_status_cb *scb)
17630062bd1SDavid Howells {
17730062bd1SDavid Howells 	const struct yfs_xdr_YFSFetchStatus *xdr = (const void *)*_bp;
178a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
17930062bd1SDavid Howells 	u32 type;
18030062bd1SDavid Howells 
18130062bd1SDavid Howells 	status->abort_code = ntohl(xdr->abort_code);
18230062bd1SDavid Howells 	if (status->abort_code != 0) {
183a58823acSDavid Howells 		if (status->abort_code == VNOVNODE)
18430062bd1SDavid Howells 			status->nlink = 0;
185a38a7558SDavid Howells 		scb->have_error = true;
18638355eecSDavid Howells 		goto advance;
18730062bd1SDavid Howells 	}
18830062bd1SDavid Howells 
18930062bd1SDavid Howells 	type = ntohl(xdr->type);
19030062bd1SDavid Howells 	switch (type) {
19130062bd1SDavid Howells 	case AFS_FTYPE_FILE:
19230062bd1SDavid Howells 	case AFS_FTYPE_DIR:
19330062bd1SDavid Howells 	case AFS_FTYPE_SYMLINK:
19430062bd1SDavid Howells 		status->type = type;
19530062bd1SDavid Howells 		break;
19630062bd1SDavid Howells 	default:
19730062bd1SDavid Howells 		goto bad;
19830062bd1SDavid Howells 	}
19930062bd1SDavid Howells 
200a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
201a58823acSDavid Howells 	status->author		= xdr_to_u64(xdr->author);
202a58823acSDavid Howells 	status->owner		= xdr_to_u64(xdr->owner);
203a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
204a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
205a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
206a58823acSDavid Howells 	status->group		= xdr_to_u64(xdr->group);
207a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
20830062bd1SDavid Howells 
20930062bd1SDavid Howells 	status->mtime_client	= xdr_to_time(xdr->mtime_client);
21030062bd1SDavid Howells 	status->mtime_server	= xdr_to_time(xdr->mtime_server);
211a58823acSDavid Howells 	status->size		= xdr_to_u64(xdr->size);
212a58823acSDavid Howells 	status->data_version	= xdr_to_u64(xdr->data_version);
213a38a7558SDavid Howells 	scb->have_status	= true;
214c72057b5SDavid Howells advance:
21530062bd1SDavid Howells 	*_bp += xdr_size(xdr);
21638355eecSDavid Howells 	return;
21730062bd1SDavid Howells 
21830062bd1SDavid Howells bad:
21930062bd1SDavid Howells 	xdr_dump_bad(*_bp);
2207126ead9SDavid Howells 	afs_protocol_error(call, afs_eproto_bad_status);
221c72057b5SDavid Howells 	goto advance;
22230062bd1SDavid Howells }
22330062bd1SDavid Howells 
22430062bd1SDavid Howells /*
225a58823acSDavid Howells  * Decode a YFSCallBack block
22630062bd1SDavid Howells  */
xdr_decode_YFSCallBack(const __be32 ** _bp,struct afs_call * call,struct afs_status_cb * scb)227a58823acSDavid Howells static void xdr_decode_YFSCallBack(const __be32 **_bp,
228a58823acSDavid Howells 				   struct afs_call *call,
229a58823acSDavid Howells 				   struct afs_status_cb *scb)
23078107055SDavid Howells {
23178107055SDavid Howells 	struct yfs_xdr_YFSCallBack *x = (void *)*_bp;
232a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
23378107055SDavid Howells 	ktime_t cb_expiry;
23478107055SDavid Howells 
2357903192cSDavid Howells 	cb_expiry = ktime_add(call->issue_time, xdr_to_u64(x->expiration_time) * 100);
23678107055SDavid Howells 	cb->expires_at	= ktime_divns(cb_expiry, NSEC_PER_SEC);
237a58823acSDavid Howells 	scb->have_cb	= true;
23878107055SDavid Howells 	*_bp += xdr_size(x);
23978107055SDavid Howells }
24078107055SDavid Howells 
24130062bd1SDavid Howells /*
24230062bd1SDavid Howells  * Decode a YFSVolSync block
24330062bd1SDavid Howells  */
xdr_decode_YFSVolSync(const __be32 ** _bp,struct afs_volsync * volsync)24430062bd1SDavid Howells static void xdr_decode_YFSVolSync(const __be32 **_bp,
24530062bd1SDavid Howells 				  struct afs_volsync *volsync)
24630062bd1SDavid Howells {
24730062bd1SDavid Howells 	struct yfs_xdr_YFSVolSync *x = (void *)*_bp;
24830062bd1SDavid Howells 	u64 creation;
24930062bd1SDavid Howells 
25030062bd1SDavid Howells 	if (volsync) {
25130062bd1SDavid Howells 		creation = xdr_to_u64(x->vol_creation_date);
25230062bd1SDavid Howells 		do_div(creation, 10 * 1000 * 1000);
25330062bd1SDavid Howells 		volsync->creation = creation;
25430062bd1SDavid Howells 	}
25530062bd1SDavid Howells 
25630062bd1SDavid Howells 	*_bp += xdr_size(x);
25730062bd1SDavid Howells }
25830062bd1SDavid Howells 
25930062bd1SDavid Howells /*
26030062bd1SDavid Howells  * Encode the requested attributes into a YFSStoreStatus block
26130062bd1SDavid Howells  */
xdr_encode_YFS_StoreStatus(__be32 * bp,struct iattr * attr)26230062bd1SDavid Howells static __be32 *xdr_encode_YFS_StoreStatus(__be32 *bp, struct iattr *attr)
26330062bd1SDavid Howells {
26430062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
26530062bd1SDavid Howells 	s64 mtime = 0, owner = 0, group = 0;
26630062bd1SDavid Howells 	u32 mask = 0, mode = 0;
26730062bd1SDavid Howells 
26830062bd1SDavid Howells 	mask = 0;
26930062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
27030062bd1SDavid Howells 		mask |= AFS_SET_MTIME;
27130062bd1SDavid Howells 		mtime = linux_to_yfs_time(&attr->ia_mtime);
27230062bd1SDavid Howells 	}
27330062bd1SDavid Howells 
27430062bd1SDavid Howells 	if (attr->ia_valid & ATTR_UID) {
27530062bd1SDavid Howells 		mask |= AFS_SET_OWNER;
27630062bd1SDavid Howells 		owner = from_kuid(&init_user_ns, attr->ia_uid);
27730062bd1SDavid Howells 	}
27830062bd1SDavid Howells 
27930062bd1SDavid Howells 	if (attr->ia_valid & ATTR_GID) {
28030062bd1SDavid Howells 		mask |= AFS_SET_GROUP;
28130062bd1SDavid Howells 		group = from_kgid(&init_user_ns, attr->ia_gid);
28230062bd1SDavid Howells 	}
28330062bd1SDavid Howells 
28430062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
28530062bd1SDavid Howells 		mask |= AFS_SET_MODE;
28630062bd1SDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
28730062bd1SDavid Howells 	}
28830062bd1SDavid Howells 
28930062bd1SDavid Howells 	x->mask		= htonl(mask);
29030062bd1SDavid Howells 	x->mode		= htonl(mode);
29130062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(mtime);
29230062bd1SDavid Howells 	x->owner	= u64_to_xdr(owner);
29330062bd1SDavid Howells 	x->group	= u64_to_xdr(group);
29430062bd1SDavid Howells 	return bp + xdr_size(x);
29530062bd1SDavid Howells }
29630062bd1SDavid Howells 
29730062bd1SDavid Howells /*
29830062bd1SDavid Howells  * Decode a YFSFetchVolumeStatus block.
29930062bd1SDavid Howells  */
xdr_decode_YFSFetchVolumeStatus(const __be32 ** _bp,struct afs_volume_status * vs)30030062bd1SDavid Howells static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp,
30130062bd1SDavid Howells 					    struct afs_volume_status *vs)
30230062bd1SDavid Howells {
30330062bd1SDavid Howells 	const struct yfs_xdr_YFSFetchVolumeStatus *x = (const void *)*_bp;
30430062bd1SDavid Howells 	u32 flags;
30530062bd1SDavid Howells 
30630062bd1SDavid Howells 	vs->vid			= xdr_to_u64(x->vid);
30730062bd1SDavid Howells 	vs->parent_id		= xdr_to_u64(x->parent_id);
30830062bd1SDavid Howells 	flags			= ntohl(x->flags);
30930062bd1SDavid Howells 	vs->online		= flags & yfs_FVSOnline;
31030062bd1SDavid Howells 	vs->in_service		= flags & yfs_FVSInservice;
31130062bd1SDavid Howells 	vs->blessed		= flags & yfs_FVSBlessed;
31230062bd1SDavid Howells 	vs->needs_salvage	= flags & yfs_FVSNeedsSalvage;
31330062bd1SDavid Howells 	vs->type		= ntohl(x->type);
31430062bd1SDavid Howells 	vs->min_quota		= 0;
31530062bd1SDavid Howells 	vs->max_quota		= xdr_to_u64(x->max_quota);
31630062bd1SDavid Howells 	vs->blocks_in_use	= xdr_to_u64(x->blocks_in_use);
31730062bd1SDavid Howells 	vs->part_blocks_avail	= xdr_to_u64(x->part_blocks_avail);
31830062bd1SDavid Howells 	vs->part_max_blocks	= xdr_to_u64(x->part_max_blocks);
31930062bd1SDavid Howells 	vs->vol_copy_date	= xdr_to_u64(x->vol_copy_date);
32030062bd1SDavid Howells 	vs->vol_backup_date	= xdr_to_u64(x->vol_backup_date);
32130062bd1SDavid Howells 	*_bp += sizeof(*x) / sizeof(__be32);
32230062bd1SDavid Howells }
32330062bd1SDavid Howells 
32430062bd1SDavid Howells /*
325a58823acSDavid Howells  * Deliver reply data to operations that just return a file status and a volume
326a58823acSDavid Howells  * sync record.
327a58823acSDavid Howells  */
yfs_deliver_status_and_volsync(struct afs_call * call)328a58823acSDavid Howells static int yfs_deliver_status_and_volsync(struct afs_call *call)
329a58823acSDavid Howells {
330e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
331a58823acSDavid Howells 	const __be32 *bp;
332a58823acSDavid Howells 	int ret;
333a58823acSDavid Howells 
334a58823acSDavid Howells 	ret = afs_transfer_reply(call);
335a58823acSDavid Howells 	if (ret < 0)
336a58823acSDavid Howells 		return ret;
337a58823acSDavid Howells 
338a58823acSDavid Howells 	bp = call->buffer;
339e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &op->file[0].scb);
340e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
34130062bd1SDavid Howells 
34230062bd1SDavid Howells 	_leave(" = 0 [done]");
34330062bd1SDavid Howells 	return 0;
34430062bd1SDavid Howells }
34530062bd1SDavid Howells 
34630062bd1SDavid Howells /*
34730062bd1SDavid Howells  * Deliver reply data to an YFS.FetchData64.
34830062bd1SDavid Howells  */
yfs_deliver_fs_fetch_data64(struct afs_call * call)34930062bd1SDavid Howells static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
35030062bd1SDavid Howells {
351e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
352e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
353e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
35430062bd1SDavid Howells 	const __be32 *bp;
35530062bd1SDavid Howells 	int ret;
35630062bd1SDavid Howells 
357f105da1aSDavid Howells 	_enter("{%u,%zu, %zu/%llu}",
358f105da1aSDavid Howells 	       call->unmarshall, call->iov_len, iov_iter_count(call->iter),
359f105da1aSDavid Howells 	       req->actual_len);
36030062bd1SDavid Howells 
36130062bd1SDavid Howells 	switch (call->unmarshall) {
36230062bd1SDavid Howells 	case 0:
36330062bd1SDavid Howells 		req->actual_len = 0;
36430062bd1SDavid Howells 		afs_extract_to_tmp64(call);
36530062bd1SDavid Howells 		call->unmarshall++;
366df561f66SGustavo A. R. Silva 		fallthrough;
36730062bd1SDavid Howells 
368c4508464SDavid Howells 		/* Extract the returned data length into ->actual_len.  This
369c4508464SDavid Howells 		 * may indicate more or less data than was requested will be
370c4508464SDavid Howells 		 * returned.
371c4508464SDavid Howells 		 */
37230062bd1SDavid Howells 	case 1:
37330062bd1SDavid Howells 		_debug("extract data length");
37430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
37530062bd1SDavid Howells 		if (ret < 0)
37630062bd1SDavid Howells 			return ret;
37730062bd1SDavid Howells 
37830062bd1SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
37930062bd1SDavid Howells 		_debug("DATA length: %llu", req->actual_len);
380c4508464SDavid Howells 
381c4508464SDavid Howells 		if (req->actual_len == 0)
38230062bd1SDavid Howells 			goto no_more_data;
38330062bd1SDavid Howells 
384c4508464SDavid Howells 		call->iter = req->iter;
385c4508464SDavid Howells 		call->iov_len = min(req->actual_len, req->len);
38630062bd1SDavid Howells 		call->unmarshall++;
387df561f66SGustavo A. R. Silva 		fallthrough;
38830062bd1SDavid Howells 
38935a3a90cSGustavo A. R. Silva 		/* extract the returned data */
39030062bd1SDavid Howells 	case 2:
39130062bd1SDavid Howells 		_debug("extract data %zu/%llu",
392c4508464SDavid Howells 		       iov_iter_count(call->iter), req->actual_len);
39330062bd1SDavid Howells 
39430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
39530062bd1SDavid Howells 		if (ret < 0)
39630062bd1SDavid Howells 			return ret;
39730062bd1SDavid Howells 
398c4508464SDavid Howells 		call->iter = &call->def_iter;
39930062bd1SDavid Howells 		if (req->actual_len <= req->len)
40030062bd1SDavid Howells 			goto no_more_data;
40130062bd1SDavid Howells 
40230062bd1SDavid Howells 		/* Discard any excess data the server gave us */
40323a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
40430062bd1SDavid Howells 		call->unmarshall = 3;
405df561f66SGustavo A. R. Silva 		fallthrough;
40635a3a90cSGustavo A. R. Silva 
40730062bd1SDavid Howells 	case 3:
40830062bd1SDavid Howells 		_debug("extract discard %zu/%llu",
409fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
41030062bd1SDavid Howells 
41130062bd1SDavid Howells 		ret = afs_extract_data(call, true);
41230062bd1SDavid Howells 		if (ret < 0)
41330062bd1SDavid Howells 			return ret;
41430062bd1SDavid Howells 
41530062bd1SDavid Howells 	no_more_data:
41630062bd1SDavid Howells 		call->unmarshall = 4;
41730062bd1SDavid Howells 		afs_extract_to_buf(call,
41830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
41930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
42030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
421df561f66SGustavo A. R. Silva 		fallthrough;
42230062bd1SDavid Howells 
42335a3a90cSGustavo A. R. Silva 		/* extract the metadata */
42430062bd1SDavid Howells 	case 4:
42530062bd1SDavid Howells 		ret = afs_extract_data(call, false);
42630062bd1SDavid Howells 		if (ret < 0)
42730062bd1SDavid Howells 			return ret;
42830062bd1SDavid Howells 
42930062bd1SDavid Howells 		bp = call->buffer;
430e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
431e49c7b2fSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, &vp->scb);
432e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
43330062bd1SDavid Howells 
434e49c7b2fSDavid Howells 		req->data_version = vp->scb.status.data_version;
435e49c7b2fSDavid Howells 		req->file_size = vp->scb.status.size;
436a58823acSDavid Howells 
43730062bd1SDavid Howells 		call->unmarshall++;
438df561f66SGustavo A. R. Silva 		fallthrough;
43935a3a90cSGustavo A. R. Silva 
44030062bd1SDavid Howells 	case 5:
44130062bd1SDavid Howells 		break;
44230062bd1SDavid Howells 	}
44330062bd1SDavid Howells 
44430062bd1SDavid Howells 	_leave(" = 0 [done]");
44530062bd1SDavid Howells 	return 0;
44630062bd1SDavid Howells }
44730062bd1SDavid Howells 
44830062bd1SDavid Howells /*
44930062bd1SDavid Howells  * YFS.FetchData64 operation type
45030062bd1SDavid Howells  */
45130062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchData64 = {
45230062bd1SDavid Howells 	.name		= "YFS.FetchData64",
45330062bd1SDavid Howells 	.op		= yfs_FS_FetchData64,
45430062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_data64,
455e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
45630062bd1SDavid Howells };
45730062bd1SDavid Howells 
45830062bd1SDavid Howells /*
45930062bd1SDavid Howells  * Fetch data from a file.
46030062bd1SDavid Howells  */
yfs_fs_fetch_data(struct afs_operation * op)461e49c7b2fSDavid Howells void yfs_fs_fetch_data(struct afs_operation *op)
46230062bd1SDavid Howells {
463e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
464e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
46530062bd1SDavid Howells 	struct afs_call *call;
46630062bd1SDavid Howells 	__be32 *bp;
46730062bd1SDavid Howells 
46830062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%llx,%llx",
469e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode,
47030062bd1SDavid Howells 	       req->pos, req->len);
47130062bd1SDavid Howells 
472e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64,
47330062bd1SDavid Howells 				   sizeof(__be32) * 2 +
47430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
47530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 2,
47630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
47730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
47830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
47930062bd1SDavid Howells 	if (!call)
480e49c7b2fSDavid Howells 		return afs_op_nomem(op);
48130062bd1SDavid Howells 
482c4508464SDavid Howells 	req->call_debug_id = call->debug_id;
483c4508464SDavid Howells 
48430062bd1SDavid Howells 	/* marshall the parameters */
48530062bd1SDavid Howells 	bp = call->request;
48630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHDATA64);
48730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
488e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
48930062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->pos);
49030062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->len);
49130062bd1SDavid Howells 	yfs_check_req(call, bp);
49230062bd1SDavid Howells 
493e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
494e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
49530062bd1SDavid Howells }
49630062bd1SDavid Howells 
49730062bd1SDavid Howells /*
49830062bd1SDavid Howells  * Deliver reply data for YFS.CreateFile or YFS.MakeDir.
49930062bd1SDavid Howells  */
yfs_deliver_fs_create_vnode(struct afs_call * call)50030062bd1SDavid Howells static int yfs_deliver_fs_create_vnode(struct afs_call *call)
50130062bd1SDavid Howells {
502e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
503e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
504e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
50530062bd1SDavid Howells 	const __be32 *bp;
50630062bd1SDavid Howells 	int ret;
50730062bd1SDavid Howells 
50830062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
50930062bd1SDavid Howells 
51030062bd1SDavid Howells 	ret = afs_transfer_reply(call);
51130062bd1SDavid Howells 	if (ret < 0)
51230062bd1SDavid Howells 		return ret;
51330062bd1SDavid Howells 
51430062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
51530062bd1SDavid Howells 	bp = call->buffer;
516e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &op->file[1].fid);
517e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
518e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
519e49c7b2fSDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
520e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
52130062bd1SDavid Howells 
52230062bd1SDavid Howells 	_leave(" = 0 [done]");
52330062bd1SDavid Howells 	return 0;
52430062bd1SDavid Howells }
52530062bd1SDavid Howells 
52630062bd1SDavid Howells /*
52730062bd1SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
52830062bd1SDavid Howells  */
52930062bd1SDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
53030062bd1SDavid Howells 	.name		= "YFS.CreateFile",
53130062bd1SDavid Howells 	.op		= yfs_FS_CreateFile,
53230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
53330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
53430062bd1SDavid Howells };
53530062bd1SDavid Howells 
53630062bd1SDavid Howells /*
53730062bd1SDavid Howells  * Create a file.
53830062bd1SDavid Howells  */
yfs_fs_create_file(struct afs_operation * op)539e49c7b2fSDavid Howells void yfs_fs_create_file(struct afs_operation *op)
54030062bd1SDavid Howells {
541e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
542e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
54330062bd1SDavid Howells 	struct afs_call *call;
544e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
54530062bd1SDavid Howells 	__be32 *bp;
54630062bd1SDavid Howells 
54730062bd1SDavid Howells 	_enter("");
54830062bd1SDavid Howells 
54930062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
55030062bd1SDavid Howells 		 sizeof(__be32) +
55130062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
552e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
55330062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus) +
55430062bd1SDavid Howells 		 sizeof(__be32));
55530062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
55630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
55730062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
55830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
55930062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
56030062bd1SDavid Howells 
561e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, reqsz, rplsz);
56230062bd1SDavid Howells 	if (!call)
563e49c7b2fSDavid Howells 		return afs_op_nomem(op);
56430062bd1SDavid Howells 
56530062bd1SDavid Howells 	/* marshall the parameters */
56630062bd1SDavid Howells 	bp = call->request;
56730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSCREATEFILE);
56830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
569e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
570e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
57152af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &op->create.mode, &op->mtime);
5725edc22ccSMarc Dionne 	bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
57330062bd1SDavid Howells 	yfs_check_req(call, bp);
57430062bd1SDavid Howells 
575e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
576e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
57730062bd1SDavid Howells }
57830062bd1SDavid Howells 
57930062bd1SDavid Howells static const struct afs_call_type yfs_RXFSMakeDir = {
58030062bd1SDavid Howells 	.name		= "YFS.MakeDir",
58130062bd1SDavid Howells 	.op		= yfs_FS_MakeDir,
58230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
58330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
58430062bd1SDavid Howells };
58530062bd1SDavid Howells 
58630062bd1SDavid Howells /*
58730062bd1SDavid Howells  * Make a directory.
58830062bd1SDavid Howells  */
yfs_fs_make_dir(struct afs_operation * op)589e49c7b2fSDavid Howells void yfs_fs_make_dir(struct afs_operation *op)
59030062bd1SDavid Howells {
591e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
592e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
59330062bd1SDavid Howells 	struct afs_call *call;
594e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
59530062bd1SDavid Howells 	__be32 *bp;
59630062bd1SDavid Howells 
59730062bd1SDavid Howells 	_enter("");
59830062bd1SDavid Howells 
59930062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
60030062bd1SDavid Howells 		 sizeof(struct yfs_xdr_RPCFlags) +
60130062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
602e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
60330062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus));
60430062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
60530062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
60630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
60730062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
60830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
60930062bd1SDavid Howells 
610e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXFSMakeDir, reqsz, rplsz);
61130062bd1SDavid Howells 	if (!call)
612e49c7b2fSDavid Howells 		return afs_op_nomem(op);
61330062bd1SDavid Howells 
61430062bd1SDavid Howells 	/* marshall the parameters */
61530062bd1SDavid Howells 	bp = call->request;
61630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSMAKEDIR);
61730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
618e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
619e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
62052af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &op->create.mode, &op->mtime);
62130062bd1SDavid Howells 	yfs_check_req(call, bp);
62230062bd1SDavid Howells 
623e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
624e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
62530062bd1SDavid Howells }
62630062bd1SDavid Howells 
62730062bd1SDavid Howells /*
62830062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile2 operation.
62930062bd1SDavid Howells  */
yfs_deliver_fs_remove_file2(struct afs_call * call)63030062bd1SDavid Howells static int yfs_deliver_fs_remove_file2(struct afs_call *call)
63130062bd1SDavid Howells {
632e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
633e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
634e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
63530062bd1SDavid Howells 	struct afs_fid fid;
63630062bd1SDavid Howells 	const __be32 *bp;
63730062bd1SDavid Howells 	int ret;
63830062bd1SDavid Howells 
63930062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
64030062bd1SDavid Howells 
64130062bd1SDavid Howells 	ret = afs_transfer_reply(call);
64230062bd1SDavid Howells 	if (ret < 0)
64330062bd1SDavid Howells 		return ret;
64430062bd1SDavid Howells 
64530062bd1SDavid Howells 	bp = call->buffer;
646e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
64730062bd1SDavid Howells 	xdr_decode_YFSFid(&bp, &fid);
648e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
64930062bd1SDavid Howells 	/* Was deleted if vnode->status.abort_code == VNOVNODE. */
65030062bd1SDavid Howells 
651e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
65230062bd1SDavid Howells 	return 0;
65330062bd1SDavid Howells }
65430062bd1SDavid Howells 
yfs_done_fs_remove_file2(struct afs_call * call)655e49c7b2fSDavid Howells static void yfs_done_fs_remove_file2(struct afs_call *call)
656e49c7b2fSDavid Howells {
657e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
658*c89b19e9SDavid Howells 	    (call->abort_code == RX_INVALID_OPERATION ||
659*c89b19e9SDavid Howells 	     call->abort_code == RXGEN_OPCODE)) {
660*c89b19e9SDavid Howells 		set_bit(AFS_SERVER_FL_NO_RM2, &call->op->server->flags);
661e49c7b2fSDavid Howells 		call->op->flags |= AFS_OPERATION_DOWNGRADE;
662e49c7b2fSDavid Howells 	}
663e49c7b2fSDavid Howells }
664e49c7b2fSDavid Howells 
66530062bd1SDavid Howells /*
66630062bd1SDavid Howells  * YFS.RemoveFile2 operation type.
66730062bd1SDavid Howells  */
66830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile2 = {
66930062bd1SDavid Howells 	.name		= "YFS.RemoveFile2",
67030062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile2,
67130062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove_file2,
672e49c7b2fSDavid Howells 	.done		= yfs_done_fs_remove_file2,
67330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
67430062bd1SDavid Howells };
67530062bd1SDavid Howells 
67630062bd1SDavid Howells /*
67730062bd1SDavid Howells  * Remove a file and retrieve new file status.
67830062bd1SDavid Howells  */
yfs_fs_remove_file2(struct afs_operation * op)679e49c7b2fSDavid Howells void yfs_fs_remove_file2(struct afs_operation *op)
68030062bd1SDavid Howells {
681e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
682e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
68330062bd1SDavid Howells 	struct afs_call *call;
68430062bd1SDavid Howells 	__be32 *bp;
68530062bd1SDavid Howells 
68630062bd1SDavid Howells 	_enter("");
68730062bd1SDavid Howells 
688e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile2,
68930062bd1SDavid Howells 				   sizeof(__be32) +
69030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
69130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
692e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
69330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
69430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
69530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
69630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
69730062bd1SDavid Howells 	if (!call)
698e49c7b2fSDavid Howells 		return afs_op_nomem(op);
69930062bd1SDavid Howells 
70030062bd1SDavid Howells 	/* marshall the parameters */
70130062bd1SDavid Howells 	bp = call->request;
70230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE2);
70330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
704e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
705e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
70630062bd1SDavid Howells 	yfs_check_req(call, bp);
70730062bd1SDavid Howells 
708e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
709e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
71030062bd1SDavid Howells }
71130062bd1SDavid Howells 
71230062bd1SDavid Howells /*
71330062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile or YFS.RemoveDir operation.
71430062bd1SDavid Howells  */
yfs_deliver_fs_remove(struct afs_call * call)71530062bd1SDavid Howells static int yfs_deliver_fs_remove(struct afs_call *call)
71630062bd1SDavid Howells {
717e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
718e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
71930062bd1SDavid Howells 	const __be32 *bp;
72030062bd1SDavid Howells 	int ret;
72130062bd1SDavid Howells 
72230062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
72330062bd1SDavid Howells 
72430062bd1SDavid Howells 	ret = afs_transfer_reply(call);
72530062bd1SDavid Howells 	if (ret < 0)
72630062bd1SDavid Howells 		return ret;
72730062bd1SDavid Howells 
72830062bd1SDavid Howells 	bp = call->buffer;
729e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
730e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
73130062bd1SDavid Howells 	return 0;
73230062bd1SDavid Howells }
73330062bd1SDavid Howells 
73430062bd1SDavid Howells /*
73530062bd1SDavid Howells  * FS.RemoveDir and FS.RemoveFile operation types.
73630062bd1SDavid Howells  */
73730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile = {
73830062bd1SDavid Howells 	.name		= "YFS.RemoveFile",
73930062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile,
74030062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
74130062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
74230062bd1SDavid Howells };
74330062bd1SDavid Howells 
744e49c7b2fSDavid Howells /*
745e49c7b2fSDavid Howells  * Remove a file.
746e49c7b2fSDavid Howells  */
yfs_fs_remove_file(struct afs_operation * op)747e49c7b2fSDavid Howells void yfs_fs_remove_file(struct afs_operation *op)
748e49c7b2fSDavid Howells {
749e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
750e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
751e49c7b2fSDavid Howells 	struct afs_call *call;
752e49c7b2fSDavid Howells 	__be32 *bp;
753e49c7b2fSDavid Howells 
754e49c7b2fSDavid Howells 	_enter("");
755e49c7b2fSDavid Howells 
75620325960SDavid Howells 	if (!test_bit(AFS_SERVER_FL_NO_RM2, &op->server->flags))
757e49c7b2fSDavid Howells 		return yfs_fs_remove_file2(op);
758e49c7b2fSDavid Howells 
759e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile,
760e49c7b2fSDavid Howells 				   sizeof(__be32) +
761e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
762e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
763e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
764e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
765e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
766e49c7b2fSDavid Howells 	if (!call)
767e49c7b2fSDavid Howells 		return afs_op_nomem(op);
768e49c7b2fSDavid Howells 
769e49c7b2fSDavid Howells 	/* marshall the parameters */
770e49c7b2fSDavid Howells 	bp = call->request;
771e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE);
772e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
773e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
774e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
775e49c7b2fSDavid Howells 	yfs_check_req(call, bp);
776e49c7b2fSDavid Howells 
777e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
778e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
779e49c7b2fSDavid Howells }
780e49c7b2fSDavid Howells 
78130062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveDir = {
78230062bd1SDavid Howells 	.name		= "YFS.RemoveDir",
78330062bd1SDavid Howells 	.op		= yfs_FS_RemoveDir,
78430062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
78530062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
78630062bd1SDavid Howells };
78730062bd1SDavid Howells 
78830062bd1SDavid Howells /*
789e49c7b2fSDavid Howells  * Remove a directory.
79030062bd1SDavid Howells  */
yfs_fs_remove_dir(struct afs_operation * op)791e49c7b2fSDavid Howells void yfs_fs_remove_dir(struct afs_operation *op)
79230062bd1SDavid Howells {
793e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
794e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
79530062bd1SDavid Howells 	struct afs_call *call;
79630062bd1SDavid Howells 	__be32 *bp;
79730062bd1SDavid Howells 
79830062bd1SDavid Howells 	_enter("");
79930062bd1SDavid Howells 
800e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveDir,
80130062bd1SDavid Howells 				   sizeof(__be32) +
80230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
80330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
804e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
80530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
80630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
80730062bd1SDavid Howells 	if (!call)
808e49c7b2fSDavid Howells 		return afs_op_nomem(op);
80930062bd1SDavid Howells 
81030062bd1SDavid Howells 	/* marshall the parameters */
81130062bd1SDavid Howells 	bp = call->request;
812e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEDIR);
81330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
814e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
815e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
81630062bd1SDavid Howells 	yfs_check_req(call, bp);
81730062bd1SDavid Howells 
818e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
819e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
82030062bd1SDavid Howells }
82130062bd1SDavid Howells 
82230062bd1SDavid Howells /*
82330062bd1SDavid Howells  * Deliver reply data to a YFS.Link operation.
82430062bd1SDavid Howells  */
yfs_deliver_fs_link(struct afs_call * call)82530062bd1SDavid Howells static int yfs_deliver_fs_link(struct afs_call *call)
82630062bd1SDavid Howells {
827e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
828e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
829e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
83030062bd1SDavid Howells 	const __be32 *bp;
83130062bd1SDavid Howells 	int ret;
83230062bd1SDavid Howells 
83330062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
83430062bd1SDavid Howells 
83530062bd1SDavid Howells 	ret = afs_transfer_reply(call);
83630062bd1SDavid Howells 	if (ret < 0)
83730062bd1SDavid Howells 		return ret;
83830062bd1SDavid Howells 
83930062bd1SDavid Howells 	bp = call->buffer;
840e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
841e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
842e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
84330062bd1SDavid Howells 	_leave(" = 0 [done]");
84430062bd1SDavid Howells 	return 0;
84530062bd1SDavid Howells }
84630062bd1SDavid Howells 
84730062bd1SDavid Howells /*
84830062bd1SDavid Howells  * YFS.Link operation type.
84930062bd1SDavid Howells  */
85030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSLink = {
85130062bd1SDavid Howells 	.name		= "YFS.Link",
85230062bd1SDavid Howells 	.op		= yfs_FS_Link,
85330062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_link,
85430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
85530062bd1SDavid Howells };
85630062bd1SDavid Howells 
85730062bd1SDavid Howells /*
85830062bd1SDavid Howells  * Make a hard link.
85930062bd1SDavid Howells  */
yfs_fs_link(struct afs_operation * op)860e49c7b2fSDavid Howells void yfs_fs_link(struct afs_operation *op)
86130062bd1SDavid Howells {
862e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
863e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
864e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
86530062bd1SDavid Howells 	struct afs_call *call;
86630062bd1SDavid Howells 	__be32 *bp;
86730062bd1SDavid Howells 
86830062bd1SDavid Howells 	_enter("");
86930062bd1SDavid Howells 
870e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSLink,
87130062bd1SDavid Howells 				   sizeof(__be32) +
87230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
87330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
874e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
87530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
87630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
87730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
87830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
87930062bd1SDavid Howells 	if (!call)
880e49c7b2fSDavid Howells 		return afs_op_nomem(op);
88130062bd1SDavid Howells 
88230062bd1SDavid Howells 	/* marshall the parameters */
88330062bd1SDavid Howells 	bp = call->request;
88430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSLINK);
88530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
886e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
887e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
888e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
88930062bd1SDavid Howells 	yfs_check_req(call, bp);
89030062bd1SDavid Howells 
891e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
892e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
89330062bd1SDavid Howells }
89430062bd1SDavid Howells 
89530062bd1SDavid Howells /*
89630062bd1SDavid Howells  * Deliver reply data to a YFS.Symlink operation.
89730062bd1SDavid Howells  */
yfs_deliver_fs_symlink(struct afs_call * call)89830062bd1SDavid Howells static int yfs_deliver_fs_symlink(struct afs_call *call)
89930062bd1SDavid Howells {
900e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
901e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
902e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
90330062bd1SDavid Howells 	const __be32 *bp;
90430062bd1SDavid Howells 	int ret;
90530062bd1SDavid Howells 
90630062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
90730062bd1SDavid Howells 
90830062bd1SDavid Howells 	ret = afs_transfer_reply(call);
90930062bd1SDavid Howells 	if (ret < 0)
91030062bd1SDavid Howells 		return ret;
91130062bd1SDavid Howells 
91230062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
91330062bd1SDavid Howells 	bp = call->buffer;
914e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &vp->fid);
915e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
916e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
917e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
91830062bd1SDavid Howells 
91930062bd1SDavid Howells 	_leave(" = 0 [done]");
92030062bd1SDavid Howells 	return 0;
92130062bd1SDavid Howells }
92230062bd1SDavid Howells 
92330062bd1SDavid Howells /*
92430062bd1SDavid Howells  * YFS.Symlink operation type
92530062bd1SDavid Howells  */
92630062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSymlink = {
92730062bd1SDavid Howells 	.name		= "YFS.Symlink",
92830062bd1SDavid Howells 	.op		= yfs_FS_Symlink,
92930062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_symlink,
93030062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
93130062bd1SDavid Howells };
93230062bd1SDavid Howells 
93330062bd1SDavid Howells /*
93430062bd1SDavid Howells  * Create a symbolic link.
93530062bd1SDavid Howells  */
yfs_fs_symlink(struct afs_operation * op)936e49c7b2fSDavid Howells void yfs_fs_symlink(struct afs_operation *op)
93730062bd1SDavid Howells {
938e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
939e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
94030062bd1SDavid Howells 	struct afs_call *call;
941e49c7b2fSDavid Howells 	size_t contents_sz;
94252af7105SMarc Dionne 	mode_t mode = 0777;
94330062bd1SDavid Howells 	__be32 *bp;
94430062bd1SDavid Howells 
94530062bd1SDavid Howells 	_enter("");
94630062bd1SDavid Howells 
947e49c7b2fSDavid Howells 	contents_sz = strlen(op->create.symlink);
948e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSymlink,
94930062bd1SDavid Howells 				   sizeof(__be32) +
95030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
95130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
952e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
95330062bd1SDavid Howells 				   xdr_strlen(contents_sz) +
95430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
95530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
95630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
95730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
95830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
95930062bd1SDavid Howells 	if (!call)
960e49c7b2fSDavid Howells 		return afs_op_nomem(op);
96130062bd1SDavid Howells 
96230062bd1SDavid Howells 	/* marshall the parameters */
96330062bd1SDavid Howells 	bp = call->request;
96430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSYMLINK);
96530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
966e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
967e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
968e49c7b2fSDavid Howells 	bp = xdr_encode_string(bp, op->create.symlink, contents_sz);
96952af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &mode, &op->mtime);
97030062bd1SDavid Howells 	yfs_check_req(call, bp);
97130062bd1SDavid Howells 
972e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
973e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
97430062bd1SDavid Howells }
97530062bd1SDavid Howells 
97630062bd1SDavid Howells /*
97730062bd1SDavid Howells  * Deliver reply data to a YFS.Rename operation.
97830062bd1SDavid Howells  */
yfs_deliver_fs_rename(struct afs_call * call)97930062bd1SDavid Howells static int yfs_deliver_fs_rename(struct afs_call *call)
98030062bd1SDavid Howells {
981e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
982e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
983e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
98430062bd1SDavid Howells 	const __be32 *bp;
98530062bd1SDavid Howells 	int ret;
98630062bd1SDavid Howells 
98730062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
98830062bd1SDavid Howells 
98930062bd1SDavid Howells 	ret = afs_transfer_reply(call);
99030062bd1SDavid Howells 	if (ret < 0)
99130062bd1SDavid Howells 		return ret;
99230062bd1SDavid Howells 
99330062bd1SDavid Howells 	bp = call->buffer;
99438355eecSDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
99538355eecSDavid Howells 	 * report, so we just decode it twice.
99638355eecSDavid Howells 	 */
997e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &orig_dvp->scb);
998e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &new_dvp->scb);
999e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
100030062bd1SDavid Howells 	_leave(" = 0 [done]");
100130062bd1SDavid Howells 	return 0;
100230062bd1SDavid Howells }
100330062bd1SDavid Howells 
100430062bd1SDavid Howells /*
100530062bd1SDavid Howells  * YFS.Rename operation type
100630062bd1SDavid Howells  */
100730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRename = {
100830062bd1SDavid Howells 	.name		= "FS.Rename",
100930062bd1SDavid Howells 	.op		= yfs_FS_Rename,
101030062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_rename,
101130062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
101230062bd1SDavid Howells };
101330062bd1SDavid Howells 
101430062bd1SDavid Howells /*
101530062bd1SDavid Howells  * Rename a file or directory.
101630062bd1SDavid Howells  */
yfs_fs_rename(struct afs_operation * op)1017e49c7b2fSDavid Howells void yfs_fs_rename(struct afs_operation *op)
101830062bd1SDavid Howells {
1019e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
1020e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
1021e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
1022e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
102330062bd1SDavid Howells 	struct afs_call *call;
102430062bd1SDavid Howells 	__be32 *bp;
102530062bd1SDavid Howells 
102630062bd1SDavid Howells 	_enter("");
102730062bd1SDavid Howells 
1028e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRename,
102930062bd1SDavid Howells 				   sizeof(__be32) +
103030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
103130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1032e49c7b2fSDavid Howells 				   xdr_strlen(orig_name->len) +
103330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1034e49c7b2fSDavid Howells 				   xdr_strlen(new_name->len),
103530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
103630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
103730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
103830062bd1SDavid Howells 	if (!call)
1039e49c7b2fSDavid Howells 		return afs_op_nomem(op);
104030062bd1SDavid Howells 
104130062bd1SDavid Howells 	/* marshall the parameters */
104230062bd1SDavid Howells 	bp = call->request;
104330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRENAME);
104430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1045e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &orig_dvp->fid);
1046e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, orig_name);
1047e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &new_dvp->fid);
1048e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, new_name);
104930062bd1SDavid Howells 	yfs_check_req(call, bp);
105030062bd1SDavid Howells 
1051e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1052e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
105330062bd1SDavid Howells }
105430062bd1SDavid Howells 
105530062bd1SDavid Howells /*
105630062bd1SDavid Howells  * YFS.StoreData64 operation type.
105730062bd1SDavid Howells  */
105830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64 = {
105930062bd1SDavid Howells 	.name		= "YFS.StoreData64",
106030062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1061a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
106230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
106330062bd1SDavid Howells };
106430062bd1SDavid Howells 
106530062bd1SDavid Howells /*
106630062bd1SDavid Howells  * Store a set of pages to a large file.
106730062bd1SDavid Howells  */
yfs_fs_store_data(struct afs_operation * op)1068e49c7b2fSDavid Howells void yfs_fs_store_data(struct afs_operation *op)
106930062bd1SDavid Howells {
1070e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
107130062bd1SDavid Howells 	struct afs_call *call;
107230062bd1SDavid Howells 	__be32 *bp;
107330062bd1SDavid Howells 
107430062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1075e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
107630062bd1SDavid Howells 
107730062bd1SDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
1078bd80d8a8SDavid Howells 	       (unsigned long long)op->store.size,
1079bd80d8a8SDavid Howells 	       (unsigned long long)op->store.pos,
1080bd80d8a8SDavid Howells 	       (unsigned long long)op->store.i_size);
108130062bd1SDavid Howells 
1082e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64,
108330062bd1SDavid Howells 				   sizeof(__be32) +
108430062bd1SDavid Howells 				   sizeof(__be32) +
108530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
108630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
108730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
108830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
108930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
109030062bd1SDavid Howells 	if (!call)
1091e49c7b2fSDavid Howells 		return afs_op_nomem(op);
109230062bd1SDavid Howells 
1093bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
109430062bd1SDavid Howells 
109530062bd1SDavid Howells 	/* marshall the parameters */
109630062bd1SDavid Howells 	bp = call->request;
109730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
109830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1099e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
110052af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, NULL, &op->mtime);
1101bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.pos);
1102bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.size);
1103bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.i_size);
110430062bd1SDavid Howells 	yfs_check_req(call, bp);
110530062bd1SDavid Howells 
1106e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1107e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
110830062bd1SDavid Howells }
110930062bd1SDavid Howells 
111030062bd1SDavid Howells /*
111130062bd1SDavid Howells  * YFS.StoreStatus operation type
111230062bd1SDavid Howells  */
111330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreStatus = {
111430062bd1SDavid Howells 	.name		= "YFS.StoreStatus",
111530062bd1SDavid Howells 	.op		= yfs_FS_StoreStatus,
1116a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
111730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
111830062bd1SDavid Howells };
111930062bd1SDavid Howells 
112030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = {
112130062bd1SDavid Howells 	.name		= "YFS.StoreData64",
112230062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1123a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
112430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
112530062bd1SDavid Howells };
112630062bd1SDavid Howells 
112730062bd1SDavid Howells /*
112830062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 rather than
112930062bd1SDavid Howells  * YFS.StoreStatus so as to alter the file size also.
113030062bd1SDavid Howells  */
yfs_fs_setattr_size(struct afs_operation * op)1131e49c7b2fSDavid Howells static void yfs_fs_setattr_size(struct afs_operation *op)
113230062bd1SDavid Howells {
1133e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
113430062bd1SDavid Howells 	struct afs_call *call;
1135e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
113630062bd1SDavid Howells 	__be32 *bp;
113730062bd1SDavid Howells 
113830062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1139e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
114030062bd1SDavid Howells 
1141e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64_as_Status,
114230062bd1SDavid Howells 				   sizeof(__be32) * 2 +
114330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
114430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
114530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
114630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
114730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
114830062bd1SDavid Howells 	if (!call)
1149e49c7b2fSDavid Howells 		return afs_op_nomem(op);
115030062bd1SDavid Howells 
115130062bd1SDavid Howells 	/* marshall the parameters */
115230062bd1SDavid Howells 	bp = call->request;
115330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
115430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1155e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
115630062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
11578c7ae38dSDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* position of start of write */
115830062bd1SDavid Howells 	bp = xdr_encode_u64(bp, 0);		/* size of write */
115930062bd1SDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* new file length */
116030062bd1SDavid Howells 	yfs_check_req(call, bp);
116130062bd1SDavid Howells 
1162e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1163e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
116430062bd1SDavid Howells }
116530062bd1SDavid Howells 
116630062bd1SDavid Howells /*
116730062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 if there's a change in
116830062bd1SDavid Howells  * file size, and YFS.StoreStatus otherwise.
116930062bd1SDavid Howells  */
yfs_fs_setattr(struct afs_operation * op)1170e49c7b2fSDavid Howells void yfs_fs_setattr(struct afs_operation *op)
117130062bd1SDavid Howells {
1172e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
117330062bd1SDavid Howells 	struct afs_call *call;
1174e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
117530062bd1SDavid Howells 	__be32 *bp;
117630062bd1SDavid Howells 
117730062bd1SDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1178e49c7b2fSDavid Howells 		return yfs_fs_setattr_size(op);
117930062bd1SDavid Howells 
118030062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1181e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
118230062bd1SDavid Howells 
1183e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreStatus,
118430062bd1SDavid Howells 				   sizeof(__be32) * 2 +
118530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
118630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
118730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
118830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
118930062bd1SDavid Howells 	if (!call)
1190e49c7b2fSDavid Howells 		return afs_op_nomem(op);
119130062bd1SDavid Howells 
119230062bd1SDavid Howells 	/* marshall the parameters */
119330062bd1SDavid Howells 	bp = call->request;
119430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTORESTATUS);
119530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1196e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
119730062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
119830062bd1SDavid Howells 	yfs_check_req(call, bp);
119930062bd1SDavid Howells 
1200e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1201e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
120230062bd1SDavid Howells }
120330062bd1SDavid Howells 
120430062bd1SDavid Howells /*
120530062bd1SDavid Howells  * Deliver reply data to a YFS.GetVolumeStatus operation.
120630062bd1SDavid Howells  */
yfs_deliver_fs_get_volume_status(struct afs_call * call)120730062bd1SDavid Howells static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
120830062bd1SDavid Howells {
1209e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
121030062bd1SDavid Howells 	const __be32 *bp;
121130062bd1SDavid Howells 	char *p;
121230062bd1SDavid Howells 	u32 size;
121330062bd1SDavid Howells 	int ret;
121430062bd1SDavid Howells 
121530062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
121630062bd1SDavid Howells 
121730062bd1SDavid Howells 	switch (call->unmarshall) {
121830062bd1SDavid Howells 	case 0:
121930062bd1SDavid Howells 		call->unmarshall++;
122030062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchVolumeStatus));
1221df561f66SGustavo A. R. Silva 		fallthrough;
122230062bd1SDavid Howells 
122335a3a90cSGustavo A. R. Silva 		/* extract the returned status record */
122430062bd1SDavid Howells 	case 1:
122530062bd1SDavid Howells 		_debug("extract status");
122630062bd1SDavid Howells 		ret = afs_extract_data(call, true);
122730062bd1SDavid Howells 		if (ret < 0)
122830062bd1SDavid Howells 			return ret;
122930062bd1SDavid Howells 
123030062bd1SDavid Howells 		bp = call->buffer;
1231e49c7b2fSDavid Howells 		xdr_decode_YFSFetchVolumeStatus(&bp, &op->volstatus.vs);
123230062bd1SDavid Howells 		call->unmarshall++;
123330062bd1SDavid Howells 		afs_extract_to_tmp(call);
1234df561f66SGustavo A. R. Silva 		fallthrough;
123530062bd1SDavid Howells 
123635a3a90cSGustavo A. R. Silva 		/* extract the volume name length */
123730062bd1SDavid Howells 	case 2:
123830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
123930062bd1SDavid Howells 		if (ret < 0)
124030062bd1SDavid Howells 			return ret;
124130062bd1SDavid Howells 
124230062bd1SDavid Howells 		call->count = ntohl(call->tmp);
124330062bd1SDavid Howells 		_debug("volname length: %u", call->count);
124430062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
12457126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
124630062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1247ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
124830062bd1SDavid Howells 		call->unmarshall++;
1249df561f66SGustavo A. R. Silva 		fallthrough;
125030062bd1SDavid Howells 
125135a3a90cSGustavo A. R. Silva 		/* extract the volume name */
125230062bd1SDavid Howells 	case 3:
125330062bd1SDavid Howells 		_debug("extract volname");
125430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
125530062bd1SDavid Howells 		if (ret < 0)
125630062bd1SDavid Howells 			return ret;
125730062bd1SDavid Howells 
1258ffba718eSDavid Howells 		p = call->buffer;
125930062bd1SDavid Howells 		p[call->count] = 0;
126030062bd1SDavid Howells 		_debug("volname '%s'", p);
126130062bd1SDavid Howells 		afs_extract_to_tmp(call);
126230062bd1SDavid Howells 		call->unmarshall++;
1263df561f66SGustavo A. R. Silva 		fallthrough;
126430062bd1SDavid Howells 
126535a3a90cSGustavo A. R. Silva 		/* extract the offline message length */
126630062bd1SDavid Howells 	case 4:
126730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
126830062bd1SDavid Howells 		if (ret < 0)
126930062bd1SDavid Howells 			return ret;
127030062bd1SDavid Howells 
127130062bd1SDavid Howells 		call->count = ntohl(call->tmp);
127230062bd1SDavid Howells 		_debug("offline msg length: %u", call->count);
127330062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
12747126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
127530062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1276ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
127730062bd1SDavid Howells 		call->unmarshall++;
1278df561f66SGustavo A. R. Silva 		fallthrough;
127930062bd1SDavid Howells 
128035a3a90cSGustavo A. R. Silva 		/* extract the offline message */
128130062bd1SDavid Howells 	case 5:
128230062bd1SDavid Howells 		_debug("extract offline");
128330062bd1SDavid Howells 		ret = afs_extract_data(call, true);
128430062bd1SDavid Howells 		if (ret < 0)
128530062bd1SDavid Howells 			return ret;
128630062bd1SDavid Howells 
1287ffba718eSDavid Howells 		p = call->buffer;
128830062bd1SDavid Howells 		p[call->count] = 0;
128930062bd1SDavid Howells 		_debug("offline '%s'", p);
129030062bd1SDavid Howells 
129130062bd1SDavid Howells 		afs_extract_to_tmp(call);
129230062bd1SDavid Howells 		call->unmarshall++;
1293df561f66SGustavo A. R. Silva 		fallthrough;
129430062bd1SDavid Howells 
129535a3a90cSGustavo A. R. Silva 		/* extract the message of the day length */
129630062bd1SDavid Howells 	case 6:
129730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
129830062bd1SDavid Howells 		if (ret < 0)
129930062bd1SDavid Howells 			return ret;
130030062bd1SDavid Howells 
130130062bd1SDavid Howells 		call->count = ntohl(call->tmp);
130230062bd1SDavid Howells 		_debug("motd length: %u", call->count);
130330062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
13047126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
130530062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1306ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
130730062bd1SDavid Howells 		call->unmarshall++;
1308df561f66SGustavo A. R. Silva 		fallthrough;
130930062bd1SDavid Howells 
131035a3a90cSGustavo A. R. Silva 		/* extract the message of the day */
131130062bd1SDavid Howells 	case 7:
131230062bd1SDavid Howells 		_debug("extract motd");
131330062bd1SDavid Howells 		ret = afs_extract_data(call, false);
131430062bd1SDavid Howells 		if (ret < 0)
131530062bd1SDavid Howells 			return ret;
131630062bd1SDavid Howells 
1317ffba718eSDavid Howells 		p = call->buffer;
131830062bd1SDavid Howells 		p[call->count] = 0;
131930062bd1SDavid Howells 		_debug("motd '%s'", p);
132030062bd1SDavid Howells 
132130062bd1SDavid Howells 		call->unmarshall++;
1322df561f66SGustavo A. R. Silva 		fallthrough;
132335a3a90cSGustavo A. R. Silva 
132430062bd1SDavid Howells 	case 8:
132530062bd1SDavid Howells 		break;
132630062bd1SDavid Howells 	}
132730062bd1SDavid Howells 
132830062bd1SDavid Howells 	_leave(" = 0 [done]");
132930062bd1SDavid Howells 	return 0;
133030062bd1SDavid Howells }
133130062bd1SDavid Howells 
133230062bd1SDavid Howells /*
133330062bd1SDavid Howells  * YFS.GetVolumeStatus operation type
133430062bd1SDavid Howells  */
133530062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSGetVolumeStatus = {
133630062bd1SDavid Howells 	.name		= "YFS.GetVolumeStatus",
133730062bd1SDavid Howells 	.op		= yfs_FS_GetVolumeStatus,
133830062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_get_volume_status,
1339ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
134030062bd1SDavid Howells };
134130062bd1SDavid Howells 
134230062bd1SDavid Howells /*
134330062bd1SDavid Howells  * fetch the status of a volume
134430062bd1SDavid Howells  */
yfs_fs_get_volume_status(struct afs_operation * op)1345e49c7b2fSDavid Howells void yfs_fs_get_volume_status(struct afs_operation *op)
134630062bd1SDavid Howells {
1347e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
134830062bd1SDavid Howells 	struct afs_call *call;
134930062bd1SDavid Howells 	__be32 *bp;
135030062bd1SDavid Howells 
135130062bd1SDavid Howells 	_enter("");
135230062bd1SDavid Howells 
1353e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSGetVolumeStatus,
135430062bd1SDavid Howells 				   sizeof(__be32) * 2 +
135530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64),
1356ffba718eSDavid Howells 				   max_t(size_t,
135730062bd1SDavid Howells 					 sizeof(struct yfs_xdr_YFSFetchVolumeStatus) +
1358ffba718eSDavid Howells 					 sizeof(__be32),
1359ffba718eSDavid Howells 					 AFSOPAQUEMAX + 1));
1360ffba718eSDavid Howells 	if (!call)
1361e49c7b2fSDavid Howells 		return afs_op_nomem(op);
136230062bd1SDavid Howells 
136330062bd1SDavid Howells 	/* marshall the parameters */
136430062bd1SDavid Howells 	bp = call->request;
136530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSGETVOLUMESTATUS);
136630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1367e49c7b2fSDavid Howells 	bp = xdr_encode_u64(bp, vp->fid.vid);
136830062bd1SDavid Howells 	yfs_check_req(call, bp);
136930062bd1SDavid Howells 
1370e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1371e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
137230062bd1SDavid Howells }
137330062bd1SDavid Howells 
137430062bd1SDavid Howells /*
137530062bd1SDavid Howells  * YFS.SetLock operation type
137630062bd1SDavid Howells  */
137730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSetLock = {
137830062bd1SDavid Howells 	.name		= "YFS.SetLock",
137930062bd1SDavid Howells 	.op		= yfs_FS_SetLock,
1380f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1381a690f60aSDavid Howells 	.done		= afs_lock_op_done,
138230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
138330062bd1SDavid Howells };
138430062bd1SDavid Howells 
138530062bd1SDavid Howells /*
138630062bd1SDavid Howells  * YFS.ExtendLock operation type
138730062bd1SDavid Howells  */
138830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSExtendLock = {
138930062bd1SDavid Howells 	.name		= "YFS.ExtendLock",
139030062bd1SDavid Howells 	.op		= yfs_FS_ExtendLock,
1391f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1392a690f60aSDavid Howells 	.done		= afs_lock_op_done,
139330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
139430062bd1SDavid Howells };
139530062bd1SDavid Howells 
139630062bd1SDavid Howells /*
139730062bd1SDavid Howells  * YFS.ReleaseLock operation type
139830062bd1SDavid Howells  */
139930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSReleaseLock = {
140030062bd1SDavid Howells 	.name		= "YFS.ReleaseLock",
140130062bd1SDavid Howells 	.op		= yfs_FS_ReleaseLock,
1402f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
140330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
140430062bd1SDavid Howells };
140530062bd1SDavid Howells 
140630062bd1SDavid Howells /*
140730062bd1SDavid Howells  * Set a lock on a file
140830062bd1SDavid Howells  */
yfs_fs_set_lock(struct afs_operation * op)1409e49c7b2fSDavid Howells void yfs_fs_set_lock(struct afs_operation *op)
141030062bd1SDavid Howells {
1411e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
141230062bd1SDavid Howells 	struct afs_call *call;
141330062bd1SDavid Howells 	__be32 *bp;
141430062bd1SDavid Howells 
141530062bd1SDavid Howells 	_enter("");
141630062bd1SDavid Howells 
1417e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSetLock,
141830062bd1SDavid Howells 				   sizeof(__be32) * 2 +
141930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
142030062bd1SDavid Howells 				   sizeof(__be32),
142130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
142230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
142330062bd1SDavid Howells 	if (!call)
1424e49c7b2fSDavid Howells 		return afs_op_nomem(op);
142530062bd1SDavid Howells 
142630062bd1SDavid Howells 	/* marshall the parameters */
142730062bd1SDavid Howells 	bp = call->request;
142830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSETLOCK);
142930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1430e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1431e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->lock.type);
143230062bd1SDavid Howells 	yfs_check_req(call, bp);
143330062bd1SDavid Howells 
1434e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1435e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
143630062bd1SDavid Howells }
143730062bd1SDavid Howells 
143830062bd1SDavid Howells /*
143930062bd1SDavid Howells  * extend a lock on a file
144030062bd1SDavid Howells  */
yfs_fs_extend_lock(struct afs_operation * op)1441e49c7b2fSDavid Howells void yfs_fs_extend_lock(struct afs_operation *op)
144230062bd1SDavid Howells {
1443e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
144430062bd1SDavid Howells 	struct afs_call *call;
144530062bd1SDavid Howells 	__be32 *bp;
144630062bd1SDavid Howells 
144730062bd1SDavid Howells 	_enter("");
144830062bd1SDavid Howells 
1449e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSExtendLock,
145030062bd1SDavid Howells 				   sizeof(__be32) * 2 +
145130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
145230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
145330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
145430062bd1SDavid Howells 	if (!call)
1455e49c7b2fSDavid Howells 		return afs_op_nomem(op);
145630062bd1SDavid Howells 
145730062bd1SDavid Howells 	/* marshall the parameters */
145830062bd1SDavid Howells 	bp = call->request;
145930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSEXTENDLOCK);
146030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1461e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
146230062bd1SDavid Howells 	yfs_check_req(call, bp);
146330062bd1SDavid Howells 
1464e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1465e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
146630062bd1SDavid Howells }
146730062bd1SDavid Howells 
146830062bd1SDavid Howells /*
146930062bd1SDavid Howells  * release a lock on a file
147030062bd1SDavid Howells  */
yfs_fs_release_lock(struct afs_operation * op)1471e49c7b2fSDavid Howells void yfs_fs_release_lock(struct afs_operation *op)
147230062bd1SDavid Howells {
1473e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
147430062bd1SDavid Howells 	struct afs_call *call;
147530062bd1SDavid Howells 	__be32 *bp;
147630062bd1SDavid Howells 
147730062bd1SDavid Howells 	_enter("");
147830062bd1SDavid Howells 
1479e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSReleaseLock,
148030062bd1SDavid Howells 				   sizeof(__be32) * 2 +
148130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
148230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
148330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
148430062bd1SDavid Howells 	if (!call)
1485e49c7b2fSDavid Howells 		return afs_op_nomem(op);
148630062bd1SDavid Howells 
148730062bd1SDavid Howells 	/* marshall the parameters */
148830062bd1SDavid Howells 	bp = call->request;
148930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRELEASELOCK);
149030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1491e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
149230062bd1SDavid Howells 	yfs_check_req(call, bp);
149330062bd1SDavid Howells 
1494e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1495e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
149630062bd1SDavid Howells }
149730062bd1SDavid Howells 
149830062bd1SDavid Howells /*
14999bd87ec6SDavid Howells  * Deliver a reply to YFS.FetchStatus
15009bd87ec6SDavid Howells  */
yfs_deliver_fs_fetch_status(struct afs_call * call)15019bd87ec6SDavid Howells static int yfs_deliver_fs_fetch_status(struct afs_call *call)
15029bd87ec6SDavid Howells {
15039bd87ec6SDavid Howells 	struct afs_operation *op = call->op;
15049bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
15059bd87ec6SDavid Howells 	const __be32 *bp;
15069bd87ec6SDavid Howells 	int ret;
15079bd87ec6SDavid Howells 
15089bd87ec6SDavid Howells 	ret = afs_transfer_reply(call);
15099bd87ec6SDavid Howells 	if (ret < 0)
15109bd87ec6SDavid Howells 		return ret;
15119bd87ec6SDavid Howells 
15129bd87ec6SDavid Howells 	/* unmarshall the reply once we've received all of it */
15139bd87ec6SDavid Howells 	bp = call->buffer;
15149bd87ec6SDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
15159bd87ec6SDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
15169bd87ec6SDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
15179bd87ec6SDavid Howells 
15189bd87ec6SDavid Howells 	_leave(" = 0 [done]");
15199bd87ec6SDavid Howells 	return 0;
15209bd87ec6SDavid Howells }
15219bd87ec6SDavid Howells 
15229bd87ec6SDavid Howells /*
152330062bd1SDavid Howells  * YFS.FetchStatus operation type
152430062bd1SDavid Howells  */
152530062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchStatus = {
152630062bd1SDavid Howells 	.name		= "YFS.FetchStatus",
152730062bd1SDavid Howells 	.op		= yfs_FS_FetchStatus,
15289bd87ec6SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_status,
152930062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
153030062bd1SDavid Howells };
153130062bd1SDavid Howells 
153230062bd1SDavid Howells /*
153330062bd1SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
153430062bd1SDavid Howells  */
yfs_fs_fetch_status(struct afs_operation * op)1535e49c7b2fSDavid Howells void yfs_fs_fetch_status(struct afs_operation *op)
153630062bd1SDavid Howells {
15379bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
153830062bd1SDavid Howells 	struct afs_call *call;
153930062bd1SDavid Howells 	__be32 *bp;
154030062bd1SDavid Howells 
154130062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1542e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
154330062bd1SDavid Howells 
1544e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchStatus,
154530062bd1SDavid Howells 				   sizeof(__be32) * 2 +
154630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
154730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
154830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
154930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1550e49c7b2fSDavid Howells 	if (!call)
1551e49c7b2fSDavid Howells 		return afs_op_nomem(op);
155230062bd1SDavid Howells 
155330062bd1SDavid Howells 	/* marshall the parameters */
155430062bd1SDavid Howells 	bp = call->request;
155530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHSTATUS);
155630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1557e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
155830062bd1SDavid Howells 	yfs_check_req(call, bp);
155930062bd1SDavid Howells 
1560e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1561e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
156230062bd1SDavid Howells }
156330062bd1SDavid Howells 
156430062bd1SDavid Howells /*
156530062bd1SDavid Howells  * Deliver reply data to an YFS.InlineBulkStatus call
156630062bd1SDavid Howells  */
yfs_deliver_fs_inline_bulk_status(struct afs_call * call)156730062bd1SDavid Howells static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
156830062bd1SDavid Howells {
1569e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
157087182759SDavid Howells 	struct afs_status_cb *scb;
157130062bd1SDavid Howells 	const __be32 *bp;
157230062bd1SDavid Howells 	u32 tmp;
157330062bd1SDavid Howells 	int ret;
157430062bd1SDavid Howells 
157530062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
157630062bd1SDavid Howells 
157730062bd1SDavid Howells 	switch (call->unmarshall) {
157830062bd1SDavid Howells 	case 0:
157930062bd1SDavid Howells 		afs_extract_to_tmp(call);
158030062bd1SDavid Howells 		call->unmarshall++;
1581df561f66SGustavo A. R. Silva 		fallthrough;
158230062bd1SDavid Howells 
158330062bd1SDavid Howells 		/* Extract the file status count and array in two steps */
158430062bd1SDavid Howells 	case 1:
158530062bd1SDavid Howells 		_debug("extract status count");
158630062bd1SDavid Howells 		ret = afs_extract_data(call, true);
158730062bd1SDavid Howells 		if (ret < 0)
158830062bd1SDavid Howells 			return ret;
158930062bd1SDavid Howells 
159030062bd1SDavid Howells 		tmp = ntohl(call->tmp);
1591e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1592e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
15937126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
159430062bd1SDavid Howells 
159530062bd1SDavid Howells 		call->count = 0;
159630062bd1SDavid Howells 		call->unmarshall++;
159730062bd1SDavid Howells 	more_counts:
159830062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchStatus));
1599df561f66SGustavo A. R. Silva 		fallthrough;
160035a3a90cSGustavo A. R. Silva 
160130062bd1SDavid Howells 	case 2:
160230062bd1SDavid Howells 		_debug("extract status array %u", call->count);
160330062bd1SDavid Howells 		ret = afs_extract_data(call, true);
160430062bd1SDavid Howells 		if (ret < 0)
160530062bd1SDavid Howells 			return ret;
160630062bd1SDavid Howells 
1607e49c7b2fSDavid Howells 		switch (call->count) {
1608e49c7b2fSDavid Howells 		case 0:
1609e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1610e49c7b2fSDavid Howells 			break;
1611e49c7b2fSDavid Howells 		case 1:
1612e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1613e49c7b2fSDavid Howells 			break;
1614e49c7b2fSDavid Howells 		default:
1615e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1616e49c7b2fSDavid Howells 			break;
1617e49c7b2fSDavid Howells 		}
1618e49c7b2fSDavid Howells 
161930062bd1SDavid Howells 		bp = call->buffer;
162038355eecSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, scb);
162130062bd1SDavid Howells 
162230062bd1SDavid Howells 		call->count++;
1623e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
162430062bd1SDavid Howells 			goto more_counts;
162530062bd1SDavid Howells 
162630062bd1SDavid Howells 		call->count = 0;
162730062bd1SDavid Howells 		call->unmarshall++;
162830062bd1SDavid Howells 		afs_extract_to_tmp(call);
1629df561f66SGustavo A. R. Silva 		fallthrough;
163030062bd1SDavid Howells 
163130062bd1SDavid Howells 		/* Extract the callback count and array in two steps */
163230062bd1SDavid Howells 	case 3:
163330062bd1SDavid Howells 		_debug("extract CB count");
163430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
163530062bd1SDavid Howells 		if (ret < 0)
163630062bd1SDavid Howells 			return ret;
163730062bd1SDavid Howells 
163830062bd1SDavid Howells 		tmp = ntohl(call->tmp);
163930062bd1SDavid Howells 		_debug("CB count: %u", tmp);
1640e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
16417126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
164230062bd1SDavid Howells 		call->count = 0;
164330062bd1SDavid Howells 		call->unmarshall++;
164430062bd1SDavid Howells 	more_cbs:
164530062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSCallBack));
1646df561f66SGustavo A. R. Silva 		fallthrough;
164735a3a90cSGustavo A. R. Silva 
164830062bd1SDavid Howells 	case 4:
164930062bd1SDavid Howells 		_debug("extract CB array");
165030062bd1SDavid Howells 		ret = afs_extract_data(call, true);
165130062bd1SDavid Howells 		if (ret < 0)
165230062bd1SDavid Howells 			return ret;
165330062bd1SDavid Howells 
165430062bd1SDavid Howells 		_debug("unmarshall CB array");
1655e49c7b2fSDavid Howells 		switch (call->count) {
1656e49c7b2fSDavid Howells 		case 0:
1657e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1658e49c7b2fSDavid Howells 			break;
1659e49c7b2fSDavid Howells 		case 1:
1660e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1661e49c7b2fSDavid Howells 			break;
1662e49c7b2fSDavid Howells 		default:
1663e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1664e49c7b2fSDavid Howells 			break;
1665e49c7b2fSDavid Howells 		}
1666e49c7b2fSDavid Howells 
166730062bd1SDavid Howells 		bp = call->buffer;
1668a58823acSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, scb);
166930062bd1SDavid Howells 		call->count++;
1670e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
167130062bd1SDavid Howells 			goto more_cbs;
167230062bd1SDavid Howells 
167330062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSVolSync));
167430062bd1SDavid Howells 		call->unmarshall++;
1675df561f66SGustavo A. R. Silva 		fallthrough;
167635a3a90cSGustavo A. R. Silva 
167730062bd1SDavid Howells 	case 5:
167830062bd1SDavid Howells 		ret = afs_extract_data(call, false);
167930062bd1SDavid Howells 		if (ret < 0)
168030062bd1SDavid Howells 			return ret;
168130062bd1SDavid Howells 
168230062bd1SDavid Howells 		bp = call->buffer;
1683e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
168430062bd1SDavid Howells 
168530062bd1SDavid Howells 		call->unmarshall++;
1686df561f66SGustavo A. R. Silva 		fallthrough;
168735a3a90cSGustavo A. R. Silva 
168830062bd1SDavid Howells 	case 6:
168930062bd1SDavid Howells 		break;
169030062bd1SDavid Howells 	}
169130062bd1SDavid Howells 
169230062bd1SDavid Howells 	_leave(" = 0 [done]");
169330062bd1SDavid Howells 	return 0;
169430062bd1SDavid Howells }
169530062bd1SDavid Howells 
169630062bd1SDavid Howells /*
169730062bd1SDavid Howells  * FS.InlineBulkStatus operation type
169830062bd1SDavid Howells  */
169930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
170030062bd1SDavid Howells 	.name		= "YFS.InlineBulkStatus",
170130062bd1SDavid Howells 	.op		= yfs_FS_InlineBulkStatus,
170230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_inline_bulk_status,
170330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
170430062bd1SDavid Howells };
170530062bd1SDavid Howells 
170630062bd1SDavid Howells /*
170730062bd1SDavid Howells  * Fetch the status information for up to 1024 files
170830062bd1SDavid Howells  */
yfs_fs_inline_bulk_status(struct afs_operation * op)1709e49c7b2fSDavid Howells void yfs_fs_inline_bulk_status(struct afs_operation *op)
171030062bd1SDavid Howells {
1711e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1712e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
171330062bd1SDavid Howells 	struct afs_call *call;
171430062bd1SDavid Howells 	__be32 *bp;
171530062bd1SDavid Howells 	int i;
171630062bd1SDavid Howells 
171730062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1718e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
171930062bd1SDavid Howells 
1720e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSInlineBulkStatus,
172130062bd1SDavid Howells 				   sizeof(__be32) +
172230062bd1SDavid Howells 				   sizeof(__be32) +
172330062bd1SDavid Howells 				   sizeof(__be32) +
1724e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) * op->nr_files,
172530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus));
1726e49c7b2fSDavid Howells 	if (!call)
1727e49c7b2fSDavid Howells 		return afs_op_nomem(op);
172830062bd1SDavid Howells 
172930062bd1SDavid Howells 	/* marshall the parameters */
173030062bd1SDavid Howells 	bp = call->request;
173130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSINLINEBULKSTATUS);
173230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPCFlags */
1733e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->nr_files);
1734e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
1735e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1736e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++)
1737e49c7b2fSDavid Howells 		bp = xdr_encode_YFSFid(bp, &op->more_files[i].fid);
173830062bd1SDavid Howells 	yfs_check_req(call, bp);
173930062bd1SDavid Howells 
1740e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1741e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
174230062bd1SDavid Howells }
1743ae46578bSDavid Howells 
1744ae46578bSDavid Howells /*
1745ae46578bSDavid Howells  * Deliver reply data to an YFS.FetchOpaqueACL.
1746ae46578bSDavid Howells  */
yfs_deliver_fs_fetch_opaque_acl(struct afs_call * call)1747ae46578bSDavid Howells static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
1748ae46578bSDavid Howells {
1749e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1750e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1751e49c7b2fSDavid Howells 	struct yfs_acl *yacl = op->yacl;
1752ae46578bSDavid Howells 	struct afs_acl *acl;
1753ae46578bSDavid Howells 	const __be32 *bp;
1754ae46578bSDavid Howells 	unsigned int size;
1755ae46578bSDavid Howells 	int ret;
1756ae46578bSDavid Howells 
1757ae46578bSDavid Howells 	_enter("{%u}", call->unmarshall);
1758ae46578bSDavid Howells 
1759ae46578bSDavid Howells 	switch (call->unmarshall) {
1760ae46578bSDavid Howells 	case 0:
1761ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1762ae46578bSDavid Howells 		call->unmarshall++;
1763df561f66SGustavo A. R. Silva 		fallthrough;
1764ae46578bSDavid Howells 
1765ae46578bSDavid Howells 		/* Extract the file ACL length */
1766ae46578bSDavid Howells 	case 1:
1767ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1768ae46578bSDavid Howells 		if (ret < 0)
1769ae46578bSDavid Howells 			return ret;
1770ae46578bSDavid Howells 
1771ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1772ae46578bSDavid Howells 		size = round_up(size, 4);
1773ae46578bSDavid Howells 
1774ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_ACL) {
1775ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1776ae46578bSDavid Howells 			if (!acl)
1777ae46578bSDavid Howells 				return -ENOMEM;
1778ae46578bSDavid Howells 			yacl->acl = acl;
1779ae46578bSDavid Howells 			acl->size = call->count2;
1780ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1781ae46578bSDavid Howells 		} else {
178223a28913SDavid Howells 			afs_extract_discard(call, size);
1783ae46578bSDavid Howells 		}
1784ae46578bSDavid Howells 		call->unmarshall++;
1785df561f66SGustavo A. R. Silva 		fallthrough;
1786ae46578bSDavid Howells 
1787ae46578bSDavid Howells 		/* Extract the file ACL */
1788ae46578bSDavid Howells 	case 2:
1789ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1790ae46578bSDavid Howells 		if (ret < 0)
1791ae46578bSDavid Howells 			return ret;
1792ae46578bSDavid Howells 
1793ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1794ae46578bSDavid Howells 		call->unmarshall++;
1795df561f66SGustavo A. R. Silva 		fallthrough;
1796ae46578bSDavid Howells 
1797ae46578bSDavid Howells 		/* Extract the volume ACL length */
1798ae46578bSDavid Howells 	case 3:
1799ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1800ae46578bSDavid Howells 		if (ret < 0)
1801ae46578bSDavid Howells 			return ret;
1802ae46578bSDavid Howells 
1803ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1804ae46578bSDavid Howells 		size = round_up(size, 4);
1805ae46578bSDavid Howells 
1806ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_VOL_ACL) {
1807ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1808ae46578bSDavid Howells 			if (!acl)
1809ae46578bSDavid Howells 				return -ENOMEM;
1810ae46578bSDavid Howells 			yacl->vol_acl = acl;
1811ae46578bSDavid Howells 			acl->size = call->count2;
1812ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1813ae46578bSDavid Howells 		} else {
181423a28913SDavid Howells 			afs_extract_discard(call, size);
1815ae46578bSDavid Howells 		}
1816ae46578bSDavid Howells 		call->unmarshall++;
1817df561f66SGustavo A. R. Silva 		fallthrough;
1818ae46578bSDavid Howells 
1819ae46578bSDavid Howells 		/* Extract the volume ACL */
1820ae46578bSDavid Howells 	case 4:
1821ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1822ae46578bSDavid Howells 		if (ret < 0)
1823ae46578bSDavid Howells 			return ret;
1824ae46578bSDavid Howells 
1825ae46578bSDavid Howells 		afs_extract_to_buf(call,
1826ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1827ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1828ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1829ae46578bSDavid Howells 		call->unmarshall++;
1830df561f66SGustavo A. R. Silva 		fallthrough;
1831ae46578bSDavid Howells 
1832ae46578bSDavid Howells 		/* extract the metadata */
1833ae46578bSDavid Howells 	case 5:
1834ae46578bSDavid Howells 		ret = afs_extract_data(call, false);
1835ae46578bSDavid Howells 		if (ret < 0)
1836ae46578bSDavid Howells 			return ret;
1837ae46578bSDavid Howells 
1838ae46578bSDavid Howells 		bp = call->buffer;
1839ae46578bSDavid Howells 		yacl->inherit_flag = ntohl(*bp++);
1840ae46578bSDavid Howells 		yacl->num_cleaned = ntohl(*bp++);
1841e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
1842e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
1843ae46578bSDavid Howells 
1844ae46578bSDavid Howells 		call->unmarshall++;
1845df561f66SGustavo A. R. Silva 		fallthrough;
1846ae46578bSDavid Howells 
1847ae46578bSDavid Howells 	case 6:
1848ae46578bSDavid Howells 		break;
1849ae46578bSDavid Howells 	}
1850ae46578bSDavid Howells 
1851ae46578bSDavid Howells 	_leave(" = 0 [done]");
1852ae46578bSDavid Howells 	return 0;
1853ae46578bSDavid Howells }
1854ae46578bSDavid Howells 
yfs_free_opaque_acl(struct yfs_acl * yacl)1855ae46578bSDavid Howells void yfs_free_opaque_acl(struct yfs_acl *yacl)
1856ae46578bSDavid Howells {
1857ae46578bSDavid Howells 	if (yacl) {
1858ae46578bSDavid Howells 		kfree(yacl->acl);
1859ae46578bSDavid Howells 		kfree(yacl->vol_acl);
1860ae46578bSDavid Howells 		kfree(yacl);
1861ae46578bSDavid Howells 	}
1862ae46578bSDavid Howells }
1863ae46578bSDavid Howells 
1864ae46578bSDavid Howells /*
1865ae46578bSDavid Howells  * YFS.FetchOpaqueACL operation type
1866ae46578bSDavid Howells  */
1867ae46578bSDavid Howells static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
1868ae46578bSDavid Howells 	.name		= "YFS.FetchOpaqueACL",
1869ae46578bSDavid Howells 	.op		= yfs_FS_FetchOpaqueACL,
1870ae46578bSDavid Howells 	.deliver	= yfs_deliver_fs_fetch_opaque_acl,
1871773e0c40SDavid Howells 	.destructor	= afs_flat_call_destructor,
1872ae46578bSDavid Howells };
1873ae46578bSDavid Howells 
1874ae46578bSDavid Howells /*
1875ae46578bSDavid Howells  * Fetch the YFS advanced ACLs for a file.
1876ae46578bSDavid Howells  */
yfs_fs_fetch_opaque_acl(struct afs_operation * op)1877e49c7b2fSDavid Howells void yfs_fs_fetch_opaque_acl(struct afs_operation *op)
1878ae46578bSDavid Howells {
1879e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1880ae46578bSDavid Howells 	struct afs_call *call;
1881ae46578bSDavid Howells 	__be32 *bp;
1882ae46578bSDavid Howells 
1883ae46578bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1884e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1885ae46578bSDavid Howells 
1886e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchOpaqueACL,
1887ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1888ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
1889ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1890ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1891ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1892e49c7b2fSDavid Howells 	if (!call)
1893e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1894ae46578bSDavid Howells 
1895ae46578bSDavid Howells 	/* marshall the parameters */
1896ae46578bSDavid Howells 	bp = call->request;
1897ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHOPAQUEACL);
1898ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1899e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1900ae46578bSDavid Howells 	yfs_check_req(call, bp);
1901ae46578bSDavid Howells 
1902e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1903e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
1904ae46578bSDavid Howells }
1905f5e45463SDavid Howells 
1906f5e45463SDavid Howells /*
1907f5e45463SDavid Howells  * YFS.StoreOpaqueACL2 operation type
1908f5e45463SDavid Howells  */
1909f5e45463SDavid Howells static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
1910f5e45463SDavid Howells 	.name		= "YFS.StoreOpaqueACL2",
1911f5e45463SDavid Howells 	.op		= yfs_FS_StoreOpaqueACL2,
1912f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1913f5e45463SDavid Howells 	.destructor	= afs_flat_call_destructor,
1914f5e45463SDavid Howells };
1915f5e45463SDavid Howells 
1916f5e45463SDavid Howells /*
1917f5e45463SDavid Howells  * Fetch the YFS ACL for a file.
1918f5e45463SDavid Howells  */
yfs_fs_store_opaque_acl2(struct afs_operation * op)1919e49c7b2fSDavid Howells void yfs_fs_store_opaque_acl2(struct afs_operation *op)
1920f5e45463SDavid Howells {
1921e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1922f5e45463SDavid Howells 	struct afs_call *call;
1923e49c7b2fSDavid Howells 	struct afs_acl *acl = op->acl;
1924f5e45463SDavid Howells 	size_t size;
1925f5e45463SDavid Howells 	__be32 *bp;
1926f5e45463SDavid Howells 
1927f5e45463SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1928e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1929f5e45463SDavid Howells 
1930f5e45463SDavid Howells 	size = round_up(acl->size, 4);
1931e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreOpaqueACL2,
1932f5e45463SDavid Howells 				   sizeof(__be32) * 2 +
1933f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1934f5e45463SDavid Howells 				   sizeof(__be32) + size,
1935f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1936f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1937e49c7b2fSDavid Howells 	if (!call)
1938e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1939f5e45463SDavid Howells 
1940f5e45463SDavid Howells 	/* marshall the parameters */
1941f5e45463SDavid Howells 	bp = call->request;
1942f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
1943f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1944e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1945f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, acl->size);
1946f5e45463SDavid Howells 	memcpy(bp, acl->data, acl->size);
1947f5e45463SDavid Howells 	if (acl->size != size)
1948f5e45463SDavid Howells 		memset((void *)bp + acl->size, 0, size - acl->size);
1949c80afa1dSDavid Howells 	bp += size / sizeof(__be32);
1950f5e45463SDavid Howells 	yfs_check_req(call, bp);
1951f5e45463SDavid Howells 
1952e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1953e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
195430062bd1SDavid Howells }
1955