xref: /linux/fs/afs/yfsclient.c (revision 35219bc5c71f4197c8bd10297597de797c1eece5)
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;
24816069e13SDavid Howells 	u64 creation, update;
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;
25416069e13SDavid Howells 		update = xdr_to_u64(x->vol_update_date);
25516069e13SDavid Howells 		do_div(update, 10 * 1000 * 1000);
25616069e13SDavid Howells 		volsync->update = update;
25730062bd1SDavid Howells 	}
25830062bd1SDavid Howells 
25930062bd1SDavid Howells 	*_bp += xdr_size(x);
26030062bd1SDavid Howells }
26130062bd1SDavid Howells 
26230062bd1SDavid Howells /*
26330062bd1SDavid Howells  * Encode the requested attributes into a YFSStoreStatus block
26430062bd1SDavid Howells  */
xdr_encode_YFS_StoreStatus(__be32 * bp,struct iattr * attr)26530062bd1SDavid Howells static __be32 *xdr_encode_YFS_StoreStatus(__be32 *bp, struct iattr *attr)
26630062bd1SDavid Howells {
26730062bd1SDavid Howells 	struct yfs_xdr_YFSStoreStatus *x = (void *)bp;
26830062bd1SDavid Howells 	s64 mtime = 0, owner = 0, group = 0;
26930062bd1SDavid Howells 	u32 mask = 0, mode = 0;
27030062bd1SDavid Howells 
27130062bd1SDavid Howells 	mask = 0;
27230062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
27330062bd1SDavid Howells 		mask |= AFS_SET_MTIME;
27430062bd1SDavid Howells 		mtime = linux_to_yfs_time(&attr->ia_mtime);
27530062bd1SDavid Howells 	}
27630062bd1SDavid Howells 
27730062bd1SDavid Howells 	if (attr->ia_valid & ATTR_UID) {
27830062bd1SDavid Howells 		mask |= AFS_SET_OWNER;
27930062bd1SDavid Howells 		owner = from_kuid(&init_user_ns, attr->ia_uid);
28030062bd1SDavid Howells 	}
28130062bd1SDavid Howells 
28230062bd1SDavid Howells 	if (attr->ia_valid & ATTR_GID) {
28330062bd1SDavid Howells 		mask |= AFS_SET_GROUP;
28430062bd1SDavid Howells 		group = from_kgid(&init_user_ns, attr->ia_gid);
28530062bd1SDavid Howells 	}
28630062bd1SDavid Howells 
28730062bd1SDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
28830062bd1SDavid Howells 		mask |= AFS_SET_MODE;
28930062bd1SDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
29030062bd1SDavid Howells 	}
29130062bd1SDavid Howells 
29230062bd1SDavid Howells 	x->mask		= htonl(mask);
29330062bd1SDavid Howells 	x->mode		= htonl(mode);
29430062bd1SDavid Howells 	x->mtime_client	= u64_to_xdr(mtime);
29530062bd1SDavid Howells 	x->owner	= u64_to_xdr(owner);
29630062bd1SDavid Howells 	x->group	= u64_to_xdr(group);
29730062bd1SDavid Howells 	return bp + xdr_size(x);
29830062bd1SDavid Howells }
29930062bd1SDavid Howells 
30030062bd1SDavid Howells /*
30130062bd1SDavid Howells  * Decode a YFSFetchVolumeStatus block.
30230062bd1SDavid Howells  */
xdr_decode_YFSFetchVolumeStatus(const __be32 ** _bp,struct afs_volume_status * vs)30330062bd1SDavid Howells static void xdr_decode_YFSFetchVolumeStatus(const __be32 **_bp,
30430062bd1SDavid Howells 					    struct afs_volume_status *vs)
30530062bd1SDavid Howells {
30630062bd1SDavid Howells 	const struct yfs_xdr_YFSFetchVolumeStatus *x = (const void *)*_bp;
30730062bd1SDavid Howells 	u32 flags;
30830062bd1SDavid Howells 
30930062bd1SDavid Howells 	vs->vid			= xdr_to_u64(x->vid);
31030062bd1SDavid Howells 	vs->parent_id		= xdr_to_u64(x->parent_id);
31130062bd1SDavid Howells 	flags			= ntohl(x->flags);
31230062bd1SDavid Howells 	vs->online		= flags & yfs_FVSOnline;
31330062bd1SDavid Howells 	vs->in_service		= flags & yfs_FVSInservice;
31430062bd1SDavid Howells 	vs->blessed		= flags & yfs_FVSBlessed;
31530062bd1SDavid Howells 	vs->needs_salvage	= flags & yfs_FVSNeedsSalvage;
31630062bd1SDavid Howells 	vs->type		= ntohl(x->type);
31730062bd1SDavid Howells 	vs->min_quota		= 0;
31830062bd1SDavid Howells 	vs->max_quota		= xdr_to_u64(x->max_quota);
31930062bd1SDavid Howells 	vs->blocks_in_use	= xdr_to_u64(x->blocks_in_use);
32030062bd1SDavid Howells 	vs->part_blocks_avail	= xdr_to_u64(x->part_blocks_avail);
32130062bd1SDavid Howells 	vs->part_max_blocks	= xdr_to_u64(x->part_max_blocks);
32230062bd1SDavid Howells 	vs->vol_copy_date	= xdr_to_u64(x->vol_copy_date);
32330062bd1SDavid Howells 	vs->vol_backup_date	= xdr_to_u64(x->vol_backup_date);
32430062bd1SDavid Howells 	*_bp += sizeof(*x) / sizeof(__be32);
32530062bd1SDavid Howells }
32630062bd1SDavid Howells 
32730062bd1SDavid Howells /*
328a58823acSDavid Howells  * Deliver reply data to operations that just return a file status and a volume
329a58823acSDavid Howells  * sync record.
330a58823acSDavid Howells  */
yfs_deliver_status_and_volsync(struct afs_call * call)331a58823acSDavid Howells static int yfs_deliver_status_and_volsync(struct afs_call *call)
332a58823acSDavid Howells {
333e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
334a58823acSDavid Howells 	const __be32 *bp;
335a58823acSDavid Howells 	int ret;
336a58823acSDavid Howells 
337a58823acSDavid Howells 	ret = afs_transfer_reply(call);
338a58823acSDavid Howells 	if (ret < 0)
339a58823acSDavid Howells 		return ret;
340a58823acSDavid Howells 
341a58823acSDavid Howells 	bp = call->buffer;
342e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &op->file[0].scb);
343e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
34430062bd1SDavid Howells 
34530062bd1SDavid Howells 	_leave(" = 0 [done]");
34630062bd1SDavid Howells 	return 0;
34730062bd1SDavid Howells }
34830062bd1SDavid Howells 
34930062bd1SDavid Howells /*
35030062bd1SDavid Howells  * Deliver reply data to an YFS.FetchData64.
35130062bd1SDavid Howells  */
yfs_deliver_fs_fetch_data64(struct afs_call * call)35230062bd1SDavid Howells static int yfs_deliver_fs_fetch_data64(struct afs_call *call)
35330062bd1SDavid Howells {
354e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
355e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
356e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
35730062bd1SDavid Howells 	const __be32 *bp;
358*ee4cdf7bSDavid Howells 	size_t count_before;
35930062bd1SDavid Howells 	int ret;
36030062bd1SDavid Howells 
361f105da1aSDavid Howells 	_enter("{%u,%zu, %zu/%llu}",
362f105da1aSDavid Howells 	       call->unmarshall, call->iov_len, iov_iter_count(call->iter),
363f105da1aSDavid Howells 	       req->actual_len);
36430062bd1SDavid Howells 
36530062bd1SDavid Howells 	switch (call->unmarshall) {
36630062bd1SDavid Howells 	case 0:
36730062bd1SDavid Howells 		req->actual_len = 0;
36830062bd1SDavid Howells 		afs_extract_to_tmp64(call);
36930062bd1SDavid Howells 		call->unmarshall++;
370df561f66SGustavo A. R. Silva 		fallthrough;
37130062bd1SDavid Howells 
372c4508464SDavid Howells 		/* Extract the returned data length into ->actual_len.  This
373c4508464SDavid Howells 		 * may indicate more or less data than was requested will be
374c4508464SDavid Howells 		 * returned.
375c4508464SDavid Howells 		 */
37630062bd1SDavid Howells 	case 1:
37730062bd1SDavid Howells 		_debug("extract data length");
37830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
37930062bd1SDavid Howells 		if (ret < 0)
38030062bd1SDavid Howells 			return ret;
38130062bd1SDavid Howells 
38230062bd1SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
38330062bd1SDavid Howells 		_debug("DATA length: %llu", req->actual_len);
384c4508464SDavid Howells 
385c4508464SDavid Howells 		if (req->actual_len == 0)
38630062bd1SDavid Howells 			goto no_more_data;
38730062bd1SDavid Howells 
388c4508464SDavid Howells 		call->iter = req->iter;
389c4508464SDavid Howells 		call->iov_len = min(req->actual_len, req->len);
39030062bd1SDavid Howells 		call->unmarshall++;
391df561f66SGustavo A. R. Silva 		fallthrough;
39230062bd1SDavid Howells 
39335a3a90cSGustavo A. R. Silva 		/* extract the returned data */
39430062bd1SDavid Howells 	case 2:
395*ee4cdf7bSDavid Howells 		count_before = call->iov_len;
396*ee4cdf7bSDavid Howells 		_debug("extract data %zu/%llu", count_before, req->actual_len);
39730062bd1SDavid Howells 
39830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
399*ee4cdf7bSDavid Howells 		if (req->subreq) {
400*ee4cdf7bSDavid Howells 			req->subreq->transferred += count_before - call->iov_len;
401*ee4cdf7bSDavid Howells 			netfs_read_subreq_progress(req->subreq, false);
402*ee4cdf7bSDavid Howells 		}
40330062bd1SDavid Howells 		if (ret < 0)
40430062bd1SDavid Howells 			return ret;
40530062bd1SDavid Howells 
406c4508464SDavid Howells 		call->iter = &call->def_iter;
40730062bd1SDavid Howells 		if (req->actual_len <= req->len)
40830062bd1SDavid Howells 			goto no_more_data;
40930062bd1SDavid Howells 
41030062bd1SDavid Howells 		/* Discard any excess data the server gave us */
41123a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
41230062bd1SDavid Howells 		call->unmarshall = 3;
413df561f66SGustavo A. R. Silva 		fallthrough;
41435a3a90cSGustavo A. R. Silva 
41530062bd1SDavid Howells 	case 3:
41630062bd1SDavid Howells 		_debug("extract discard %zu/%llu",
417fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
41830062bd1SDavid Howells 
41930062bd1SDavid Howells 		ret = afs_extract_data(call, true);
42030062bd1SDavid Howells 		if (ret < 0)
42130062bd1SDavid Howells 			return ret;
42230062bd1SDavid Howells 
42330062bd1SDavid Howells 	no_more_data:
42430062bd1SDavid Howells 		call->unmarshall = 4;
42530062bd1SDavid Howells 		afs_extract_to_buf(call,
42630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
42730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
42830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
429df561f66SGustavo A. R. Silva 		fallthrough;
43030062bd1SDavid Howells 
43135a3a90cSGustavo A. R. Silva 		/* extract the metadata */
43230062bd1SDavid Howells 	case 4:
43330062bd1SDavid Howells 		ret = afs_extract_data(call, false);
43430062bd1SDavid Howells 		if (ret < 0)
43530062bd1SDavid Howells 			return ret;
43630062bd1SDavid Howells 
43730062bd1SDavid Howells 		bp = call->buffer;
438e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
439e49c7b2fSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, &vp->scb);
440e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
44130062bd1SDavid Howells 
442e49c7b2fSDavid Howells 		req->data_version = vp->scb.status.data_version;
443e49c7b2fSDavid Howells 		req->file_size = vp->scb.status.size;
444a58823acSDavid Howells 
44530062bd1SDavid Howells 		call->unmarshall++;
446df561f66SGustavo A. R. Silva 		fallthrough;
44735a3a90cSGustavo A. R. Silva 
44830062bd1SDavid Howells 	case 5:
44930062bd1SDavid Howells 		break;
45030062bd1SDavid Howells 	}
45130062bd1SDavid Howells 
45230062bd1SDavid Howells 	_leave(" = 0 [done]");
45330062bd1SDavid Howells 	return 0;
45430062bd1SDavid Howells }
45530062bd1SDavid Howells 
45630062bd1SDavid Howells /*
45730062bd1SDavid Howells  * YFS.FetchData64 operation type
45830062bd1SDavid Howells  */
45930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchData64 = {
46030062bd1SDavid Howells 	.name		= "YFS.FetchData64",
46130062bd1SDavid Howells 	.op		= yfs_FS_FetchData64,
46230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_data64,
463e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
46430062bd1SDavid Howells };
46530062bd1SDavid Howells 
46630062bd1SDavid Howells /*
46730062bd1SDavid Howells  * Fetch data from a file.
46830062bd1SDavid Howells  */
yfs_fs_fetch_data(struct afs_operation * op)469e49c7b2fSDavid Howells void yfs_fs_fetch_data(struct afs_operation *op)
47030062bd1SDavid Howells {
471e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
472e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
47330062bd1SDavid Howells 	struct afs_call *call;
47430062bd1SDavid Howells 	__be32 *bp;
47530062bd1SDavid Howells 
47630062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%llx,%llx",
477e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode,
47830062bd1SDavid Howells 	       req->pos, req->len);
47930062bd1SDavid Howells 
480e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchData64,
48130062bd1SDavid Howells 				   sizeof(__be32) * 2 +
48230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
48330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 2,
48430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
48530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
48630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
48730062bd1SDavid Howells 	if (!call)
488e49c7b2fSDavid Howells 		return afs_op_nomem(op);
48930062bd1SDavid Howells 
490c4508464SDavid Howells 	req->call_debug_id = call->debug_id;
491c4508464SDavid Howells 
49230062bd1SDavid Howells 	/* marshall the parameters */
49330062bd1SDavid Howells 	bp = call->request;
49430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHDATA64);
49530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
496e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
49730062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->pos);
49830062bd1SDavid Howells 	bp = xdr_encode_u64(bp, req->len);
49930062bd1SDavid Howells 	yfs_check_req(call, bp);
50030062bd1SDavid Howells 
501abcbd3bfSDavid Howells 	call->fid = vp->fid;
502e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
503e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
50430062bd1SDavid Howells }
50530062bd1SDavid Howells 
50630062bd1SDavid Howells /*
50730062bd1SDavid Howells  * Deliver reply data for YFS.CreateFile or YFS.MakeDir.
50830062bd1SDavid Howells  */
yfs_deliver_fs_create_vnode(struct afs_call * call)50930062bd1SDavid Howells static int yfs_deliver_fs_create_vnode(struct afs_call *call)
51030062bd1SDavid Howells {
511e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
512e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
513e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
51430062bd1SDavid Howells 	const __be32 *bp;
51530062bd1SDavid Howells 	int ret;
51630062bd1SDavid Howells 
51730062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
51830062bd1SDavid Howells 
51930062bd1SDavid Howells 	ret = afs_transfer_reply(call);
52030062bd1SDavid Howells 	if (ret < 0)
52130062bd1SDavid Howells 		return ret;
52230062bd1SDavid Howells 
52330062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
52430062bd1SDavid Howells 	bp = call->buffer;
525e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &op->file[1].fid);
526e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
527e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
528e49c7b2fSDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
529e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
53030062bd1SDavid Howells 
53130062bd1SDavid Howells 	_leave(" = 0 [done]");
53230062bd1SDavid Howells 	return 0;
53330062bd1SDavid Howells }
53430062bd1SDavid Howells 
53530062bd1SDavid Howells /*
53630062bd1SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
53730062bd1SDavid Howells  */
53830062bd1SDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
53930062bd1SDavid Howells 	.name		= "YFS.CreateFile",
54030062bd1SDavid Howells 	.op		= yfs_FS_CreateFile,
54130062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
54230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
54330062bd1SDavid Howells };
54430062bd1SDavid Howells 
54530062bd1SDavid Howells /*
54630062bd1SDavid Howells  * Create a file.
54730062bd1SDavid Howells  */
yfs_fs_create_file(struct afs_operation * op)548e49c7b2fSDavid Howells void yfs_fs_create_file(struct afs_operation *op)
54930062bd1SDavid Howells {
550e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
551e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
55230062bd1SDavid Howells 	struct afs_call *call;
553e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
55430062bd1SDavid Howells 	__be32 *bp;
55530062bd1SDavid Howells 
55630062bd1SDavid Howells 	_enter("");
55730062bd1SDavid Howells 
55830062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
55930062bd1SDavid Howells 		 sizeof(__be32) +
56030062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
561e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
56230062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus) +
56330062bd1SDavid Howells 		 sizeof(__be32));
56430062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
56530062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
56630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
56730062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
56830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
56930062bd1SDavid Howells 
570e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile, reqsz, rplsz);
57130062bd1SDavid Howells 	if (!call)
572e49c7b2fSDavid Howells 		return afs_op_nomem(op);
57330062bd1SDavid Howells 
57430062bd1SDavid Howells 	/* marshall the parameters */
57530062bd1SDavid Howells 	bp = call->request;
57630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSCREATEFILE);
57730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
578e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
579e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
58052af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &op->create.mode, &op->mtime);
5815edc22ccSMarc Dionne 	bp = xdr_encode_u32(bp, yfs_LockNone); /* ViceLockType */
58230062bd1SDavid Howells 	yfs_check_req(call, bp);
58330062bd1SDavid Howells 
584abcbd3bfSDavid Howells 	call->fid = dvp->fid;
585e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
586e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
58730062bd1SDavid Howells }
58830062bd1SDavid Howells 
58930062bd1SDavid Howells static const struct afs_call_type yfs_RXFSMakeDir = {
59030062bd1SDavid Howells 	.name		= "YFS.MakeDir",
59130062bd1SDavid Howells 	.op		= yfs_FS_MakeDir,
59230062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_create_vnode,
59330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
59430062bd1SDavid Howells };
59530062bd1SDavid Howells 
59630062bd1SDavid Howells /*
59730062bd1SDavid Howells  * Make a directory.
59830062bd1SDavid Howells  */
yfs_fs_make_dir(struct afs_operation * op)599e49c7b2fSDavid Howells void yfs_fs_make_dir(struct afs_operation *op)
60030062bd1SDavid Howells {
601e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
602e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
60330062bd1SDavid Howells 	struct afs_call *call;
604e49c7b2fSDavid Howells 	size_t reqsz, rplsz;
60530062bd1SDavid Howells 	__be32 *bp;
60630062bd1SDavid Howells 
60730062bd1SDavid Howells 	_enter("");
60830062bd1SDavid Howells 
60930062bd1SDavid Howells 	reqsz = (sizeof(__be32) +
61030062bd1SDavid Howells 		 sizeof(struct yfs_xdr_RPCFlags) +
61130062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFid) +
612e49c7b2fSDavid Howells 		 xdr_strlen(name->len) +
61330062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSStoreStatus));
61430062bd1SDavid Howells 	rplsz = (sizeof(struct yfs_xdr_YFSFid) +
61530062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
61630062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSFetchStatus) +
61730062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSCallBack) +
61830062bd1SDavid Howells 		 sizeof(struct yfs_xdr_YFSVolSync));
61930062bd1SDavid Howells 
620e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXFSMakeDir, reqsz, rplsz);
62130062bd1SDavid Howells 	if (!call)
622e49c7b2fSDavid Howells 		return afs_op_nomem(op);
62330062bd1SDavid Howells 
62430062bd1SDavid Howells 	/* marshall the parameters */
62530062bd1SDavid Howells 	bp = call->request;
62630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSMAKEDIR);
62730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
628e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
629e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
63052af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &op->create.mode, &op->mtime);
63130062bd1SDavid Howells 	yfs_check_req(call, bp);
63230062bd1SDavid Howells 
633abcbd3bfSDavid Howells 	call->fid = dvp->fid;
634e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
635e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
63630062bd1SDavid Howells }
63730062bd1SDavid Howells 
63830062bd1SDavid Howells /*
63930062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile2 operation.
64030062bd1SDavid Howells  */
yfs_deliver_fs_remove_file2(struct afs_call * call)64130062bd1SDavid Howells static int yfs_deliver_fs_remove_file2(struct afs_call *call)
64230062bd1SDavid Howells {
643e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
644e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
645e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
64630062bd1SDavid Howells 	struct afs_fid fid;
64730062bd1SDavid Howells 	const __be32 *bp;
64830062bd1SDavid Howells 	int ret;
64930062bd1SDavid Howells 
65030062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
65130062bd1SDavid Howells 
65230062bd1SDavid Howells 	ret = afs_transfer_reply(call);
65330062bd1SDavid Howells 	if (ret < 0)
65430062bd1SDavid Howells 		return ret;
65530062bd1SDavid Howells 
65630062bd1SDavid Howells 	bp = call->buffer;
657e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
65830062bd1SDavid Howells 	xdr_decode_YFSFid(&bp, &fid);
659e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
66030062bd1SDavid Howells 	/* Was deleted if vnode->status.abort_code == VNOVNODE. */
66130062bd1SDavid Howells 
662e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
66330062bd1SDavid Howells 	return 0;
66430062bd1SDavid Howells }
66530062bd1SDavid Howells 
yfs_done_fs_remove_file2(struct afs_call * call)666e49c7b2fSDavid Howells static void yfs_done_fs_remove_file2(struct afs_call *call)
667e49c7b2fSDavid Howells {
668e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
669e49c7b2fSDavid Howells 	    call->abort_code == RX_INVALID_OPERATION) {
670e49c7b2fSDavid Howells 		set_bit(AFS_SERVER_FL_NO_RM2, &call->server->flags);
671e49c7b2fSDavid Howells 		call->op->flags |= AFS_OPERATION_DOWNGRADE;
672e49c7b2fSDavid Howells 	}
673e49c7b2fSDavid Howells }
674e49c7b2fSDavid Howells 
67530062bd1SDavid Howells /*
67630062bd1SDavid Howells  * YFS.RemoveFile2 operation type.
67730062bd1SDavid Howells  */
67830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile2 = {
67930062bd1SDavid Howells 	.name		= "YFS.RemoveFile2",
68030062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile2,
68130062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove_file2,
682e49c7b2fSDavid Howells 	.done		= yfs_done_fs_remove_file2,
68330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
68430062bd1SDavid Howells };
68530062bd1SDavid Howells 
68630062bd1SDavid Howells /*
68730062bd1SDavid Howells  * Remove a file and retrieve new file status.
68830062bd1SDavid Howells  */
yfs_fs_remove_file2(struct afs_operation * op)689e49c7b2fSDavid Howells void yfs_fs_remove_file2(struct afs_operation *op)
69030062bd1SDavid Howells {
691e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
692e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
69330062bd1SDavid Howells 	struct afs_call *call;
69430062bd1SDavid Howells 	__be32 *bp;
69530062bd1SDavid Howells 
69630062bd1SDavid Howells 	_enter("");
69730062bd1SDavid Howells 
698e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile2,
69930062bd1SDavid Howells 				   sizeof(__be32) +
70030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
70130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
702e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
70330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
70430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
70530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
70630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
70730062bd1SDavid Howells 	if (!call)
708e49c7b2fSDavid Howells 		return afs_op_nomem(op);
70930062bd1SDavid Howells 
71030062bd1SDavid Howells 	/* marshall the parameters */
71130062bd1SDavid Howells 	bp = call->request;
71230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE2);
71330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
714e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
715e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
71630062bd1SDavid Howells 	yfs_check_req(call, bp);
71730062bd1SDavid Howells 
718abcbd3bfSDavid Howells 	call->fid = dvp->fid;
719e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
720e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
72130062bd1SDavid Howells }
72230062bd1SDavid Howells 
72330062bd1SDavid Howells /*
72430062bd1SDavid Howells  * Deliver reply data to a YFS.RemoveFile or YFS.RemoveDir operation.
72530062bd1SDavid Howells  */
yfs_deliver_fs_remove(struct afs_call * call)72630062bd1SDavid Howells static int yfs_deliver_fs_remove(struct afs_call *call)
72730062bd1SDavid Howells {
728e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
729e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
73030062bd1SDavid Howells 	const __be32 *bp;
73130062bd1SDavid Howells 	int ret;
73230062bd1SDavid Howells 
73330062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
73430062bd1SDavid Howells 
73530062bd1SDavid Howells 	ret = afs_transfer_reply(call);
73630062bd1SDavid Howells 	if (ret < 0)
73730062bd1SDavid Howells 		return ret;
73830062bd1SDavid Howells 
73930062bd1SDavid Howells 	bp = call->buffer;
740e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
741e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
74230062bd1SDavid Howells 	return 0;
74330062bd1SDavid Howells }
74430062bd1SDavid Howells 
74530062bd1SDavid Howells /*
74630062bd1SDavid Howells  * FS.RemoveDir and FS.RemoveFile operation types.
74730062bd1SDavid Howells  */
74830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveFile = {
74930062bd1SDavid Howells 	.name		= "YFS.RemoveFile",
75030062bd1SDavid Howells 	.op		= yfs_FS_RemoveFile,
75130062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
75230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
75330062bd1SDavid Howells };
75430062bd1SDavid Howells 
755e49c7b2fSDavid Howells /*
756e49c7b2fSDavid Howells  * Remove a file.
757e49c7b2fSDavid Howells  */
yfs_fs_remove_file(struct afs_operation * op)758e49c7b2fSDavid Howells void yfs_fs_remove_file(struct afs_operation *op)
759e49c7b2fSDavid Howells {
760e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
761e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
762e49c7b2fSDavid Howells 	struct afs_call *call;
763e49c7b2fSDavid Howells 	__be32 *bp;
764e49c7b2fSDavid Howells 
765e49c7b2fSDavid Howells 	_enter("");
766e49c7b2fSDavid Howells 
76720325960SDavid Howells 	if (!test_bit(AFS_SERVER_FL_NO_RM2, &op->server->flags))
768e49c7b2fSDavid Howells 		return yfs_fs_remove_file2(op);
769e49c7b2fSDavid Howells 
770e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveFile,
771e49c7b2fSDavid Howells 				   sizeof(__be32) +
772e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
773e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
774e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
775e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
776e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
777e49c7b2fSDavid Howells 	if (!call)
778e49c7b2fSDavid Howells 		return afs_op_nomem(op);
779e49c7b2fSDavid Howells 
780e49c7b2fSDavid Howells 	/* marshall the parameters */
781e49c7b2fSDavid Howells 	bp = call->request;
782e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEFILE);
783e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
784e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
785e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
786e49c7b2fSDavid Howells 	yfs_check_req(call, bp);
787e49c7b2fSDavid Howells 
788abcbd3bfSDavid Howells 	call->fid = dvp->fid;
789e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
790e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
791e49c7b2fSDavid Howells }
792e49c7b2fSDavid Howells 
79330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRemoveDir = {
79430062bd1SDavid Howells 	.name		= "YFS.RemoveDir",
79530062bd1SDavid Howells 	.op		= yfs_FS_RemoveDir,
79630062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_remove,
79730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
79830062bd1SDavid Howells };
79930062bd1SDavid Howells 
80030062bd1SDavid Howells /*
801e49c7b2fSDavid Howells  * Remove a directory.
80230062bd1SDavid Howells  */
yfs_fs_remove_dir(struct afs_operation * op)803e49c7b2fSDavid Howells void yfs_fs_remove_dir(struct afs_operation *op)
80430062bd1SDavid Howells {
805e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
806e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
80730062bd1SDavid Howells 	struct afs_call *call;
80830062bd1SDavid Howells 	__be32 *bp;
80930062bd1SDavid Howells 
81030062bd1SDavid Howells 	_enter("");
81130062bd1SDavid Howells 
812e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRemoveDir,
81330062bd1SDavid Howells 				   sizeof(__be32) +
81430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
81530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
816e49c7b2fSDavid Howells 				   xdr_strlen(name->len),
81730062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
81830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
81930062bd1SDavid Howells 	if (!call)
820e49c7b2fSDavid Howells 		return afs_op_nomem(op);
82130062bd1SDavid Howells 
82230062bd1SDavid Howells 	/* marshall the parameters */
82330062bd1SDavid Howells 	bp = call->request;
824e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, YFSREMOVEDIR);
82530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
826e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
827e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
82830062bd1SDavid Howells 	yfs_check_req(call, bp);
82930062bd1SDavid Howells 
830abcbd3bfSDavid Howells 	call->fid = dvp->fid;
831e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
832e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
83330062bd1SDavid Howells }
83430062bd1SDavid Howells 
83530062bd1SDavid Howells /*
83630062bd1SDavid Howells  * Deliver reply data to a YFS.Link operation.
83730062bd1SDavid Howells  */
yfs_deliver_fs_link(struct afs_call * call)83830062bd1SDavid Howells static int yfs_deliver_fs_link(struct afs_call *call)
83930062bd1SDavid Howells {
840e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
841e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
842e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
84330062bd1SDavid Howells 	const __be32 *bp;
84430062bd1SDavid Howells 	int ret;
84530062bd1SDavid Howells 
84630062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
84730062bd1SDavid Howells 
84830062bd1SDavid Howells 	ret = afs_transfer_reply(call);
84930062bd1SDavid Howells 	if (ret < 0)
85030062bd1SDavid Howells 		return ret;
85130062bd1SDavid Howells 
85230062bd1SDavid Howells 	bp = call->buffer;
853e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
854e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
855e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
85630062bd1SDavid Howells 	_leave(" = 0 [done]");
85730062bd1SDavid Howells 	return 0;
85830062bd1SDavid Howells }
85930062bd1SDavid Howells 
86030062bd1SDavid Howells /*
86130062bd1SDavid Howells  * YFS.Link operation type.
86230062bd1SDavid Howells  */
86330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSLink = {
86430062bd1SDavid Howells 	.name		= "YFS.Link",
86530062bd1SDavid Howells 	.op		= yfs_FS_Link,
86630062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_link,
86730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
86830062bd1SDavid Howells };
86930062bd1SDavid Howells 
87030062bd1SDavid Howells /*
87130062bd1SDavid Howells  * Make a hard link.
87230062bd1SDavid Howells  */
yfs_fs_link(struct afs_operation * op)873e49c7b2fSDavid Howells void yfs_fs_link(struct afs_operation *op)
87430062bd1SDavid Howells {
875e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
876e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
877e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
87830062bd1SDavid Howells 	struct afs_call *call;
87930062bd1SDavid Howells 	__be32 *bp;
88030062bd1SDavid Howells 
88130062bd1SDavid Howells 	_enter("");
88230062bd1SDavid Howells 
883e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSLink,
88430062bd1SDavid Howells 				   sizeof(__be32) +
88530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
88630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
887e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
88830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
88930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
89030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
89130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
89230062bd1SDavid Howells 	if (!call)
893e49c7b2fSDavid Howells 		return afs_op_nomem(op);
89430062bd1SDavid Howells 
89530062bd1SDavid Howells 	/* marshall the parameters */
89630062bd1SDavid Howells 	bp = call->request;
89730062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSLINK);
89830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
899e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
900e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
901e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
90230062bd1SDavid Howells 	yfs_check_req(call, bp);
90330062bd1SDavid Howells 
904abcbd3bfSDavid Howells 	call->fid = vp->fid;
905e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
906e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
90730062bd1SDavid Howells }
90830062bd1SDavid Howells 
90930062bd1SDavid Howells /*
91030062bd1SDavid Howells  * Deliver reply data to a YFS.Symlink operation.
91130062bd1SDavid Howells  */
yfs_deliver_fs_symlink(struct afs_call * call)91230062bd1SDavid Howells static int yfs_deliver_fs_symlink(struct afs_call *call)
91330062bd1SDavid Howells {
914e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
915e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
916e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
91730062bd1SDavid Howells 	const __be32 *bp;
91830062bd1SDavid Howells 	int ret;
91930062bd1SDavid Howells 
92030062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
92130062bd1SDavid Howells 
92230062bd1SDavid Howells 	ret = afs_transfer_reply(call);
92330062bd1SDavid Howells 	if (ret < 0)
92430062bd1SDavid Howells 		return ret;
92530062bd1SDavid Howells 
92630062bd1SDavid Howells 	/* unmarshall the reply once we've received all of it */
92730062bd1SDavid Howells 	bp = call->buffer;
928e49c7b2fSDavid Howells 	xdr_decode_YFSFid(&bp, &vp->fid);
929e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
930e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &dvp->scb);
931e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
93230062bd1SDavid Howells 
93330062bd1SDavid Howells 	_leave(" = 0 [done]");
93430062bd1SDavid Howells 	return 0;
93530062bd1SDavid Howells }
93630062bd1SDavid Howells 
93730062bd1SDavid Howells /*
93830062bd1SDavid Howells  * YFS.Symlink operation type
93930062bd1SDavid Howells  */
94030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSymlink = {
94130062bd1SDavid Howells 	.name		= "YFS.Symlink",
94230062bd1SDavid Howells 	.op		= yfs_FS_Symlink,
94330062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_symlink,
94430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
94530062bd1SDavid Howells };
94630062bd1SDavid Howells 
94730062bd1SDavid Howells /*
94830062bd1SDavid Howells  * Create a symbolic link.
94930062bd1SDavid Howells  */
yfs_fs_symlink(struct afs_operation * op)950e49c7b2fSDavid Howells void yfs_fs_symlink(struct afs_operation *op)
95130062bd1SDavid Howells {
952e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
953e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
95430062bd1SDavid Howells 	struct afs_call *call;
955e49c7b2fSDavid Howells 	size_t contents_sz;
95652af7105SMarc Dionne 	mode_t mode = 0777;
95730062bd1SDavid Howells 	__be32 *bp;
95830062bd1SDavid Howells 
95930062bd1SDavid Howells 	_enter("");
96030062bd1SDavid Howells 
961e49c7b2fSDavid Howells 	contents_sz = strlen(op->create.symlink);
962e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSymlink,
96330062bd1SDavid Howells 				   sizeof(__be32) +
96430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
96530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
966e49c7b2fSDavid Howells 				   xdr_strlen(name->len) +
96730062bd1SDavid Howells 				   xdr_strlen(contents_sz) +
96830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
96930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
97030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
97130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
97230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
97330062bd1SDavid Howells 	if (!call)
974e49c7b2fSDavid Howells 		return afs_op_nomem(op);
97530062bd1SDavid Howells 
97630062bd1SDavid Howells 	/* marshall the parameters */
97730062bd1SDavid Howells 	bp = call->request;
97830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSYMLINK);
97930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
980e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
981e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, name);
982e49c7b2fSDavid Howells 	bp = xdr_encode_string(bp, op->create.symlink, contents_sz);
98352af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, &mode, &op->mtime);
98430062bd1SDavid Howells 	yfs_check_req(call, bp);
98530062bd1SDavid Howells 
986abcbd3bfSDavid Howells 	call->fid = dvp->fid;
987e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
988e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
98930062bd1SDavid Howells }
99030062bd1SDavid Howells 
99130062bd1SDavid Howells /*
99230062bd1SDavid Howells  * Deliver reply data to a YFS.Rename operation.
99330062bd1SDavid Howells  */
yfs_deliver_fs_rename(struct afs_call * call)99430062bd1SDavid Howells static int yfs_deliver_fs_rename(struct afs_call *call)
99530062bd1SDavid Howells {
996e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
997e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
998e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
99930062bd1SDavid Howells 	const __be32 *bp;
100030062bd1SDavid Howells 	int ret;
100130062bd1SDavid Howells 
100230062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
100330062bd1SDavid Howells 
100430062bd1SDavid Howells 	ret = afs_transfer_reply(call);
100530062bd1SDavid Howells 	if (ret < 0)
100630062bd1SDavid Howells 		return ret;
100730062bd1SDavid Howells 
100830062bd1SDavid Howells 	bp = call->buffer;
100938355eecSDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
101038355eecSDavid Howells 	 * report, so we just decode it twice.
101138355eecSDavid Howells 	 */
1012e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &orig_dvp->scb);
1013e49c7b2fSDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &new_dvp->scb);
1014e49c7b2fSDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
101530062bd1SDavid Howells 	_leave(" = 0 [done]");
101630062bd1SDavid Howells 	return 0;
101730062bd1SDavid Howells }
101830062bd1SDavid Howells 
101930062bd1SDavid Howells /*
102030062bd1SDavid Howells  * YFS.Rename operation type
102130062bd1SDavid Howells  */
102230062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSRename = {
102330062bd1SDavid Howells 	.name		= "FS.Rename",
102430062bd1SDavid Howells 	.op		= yfs_FS_Rename,
102530062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_rename,
102630062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
102730062bd1SDavid Howells };
102830062bd1SDavid Howells 
102930062bd1SDavid Howells /*
103030062bd1SDavid Howells  * Rename a file or directory.
103130062bd1SDavid Howells  */
yfs_fs_rename(struct afs_operation * op)1032e49c7b2fSDavid Howells void yfs_fs_rename(struct afs_operation *op)
103330062bd1SDavid Howells {
1034e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
1035e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
1036e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
1037e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
103830062bd1SDavid Howells 	struct afs_call *call;
103930062bd1SDavid Howells 	__be32 *bp;
104030062bd1SDavid Howells 
104130062bd1SDavid Howells 	_enter("");
104230062bd1SDavid Howells 
1043e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSRename,
104430062bd1SDavid Howells 				   sizeof(__be32) +
104530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_RPCFlags) +
104630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1047e49c7b2fSDavid Howells 				   xdr_strlen(orig_name->len) +
104830062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1049e49c7b2fSDavid Howells 				   xdr_strlen(new_name->len),
105030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
105130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
105230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
105330062bd1SDavid Howells 	if (!call)
1054e49c7b2fSDavid Howells 		return afs_op_nomem(op);
105530062bd1SDavid Howells 
105630062bd1SDavid Howells 	/* marshall the parameters */
105730062bd1SDavid Howells 	bp = call->request;
105830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRENAME);
105930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1060e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &orig_dvp->fid);
1061e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, orig_name);
1062e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &new_dvp->fid);
1063e49c7b2fSDavid Howells 	bp = xdr_encode_name(bp, new_name);
106430062bd1SDavid Howells 	yfs_check_req(call, bp);
106530062bd1SDavid Howells 
1066abcbd3bfSDavid Howells 	call->fid = orig_dvp->fid;
1067e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1068e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
106930062bd1SDavid Howells }
107030062bd1SDavid Howells 
107130062bd1SDavid Howells /*
107230062bd1SDavid Howells  * YFS.StoreData64 operation type.
107330062bd1SDavid Howells  */
107430062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64 = {
107530062bd1SDavid Howells 	.name		= "YFS.StoreData64",
107630062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1077a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
107830062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
107930062bd1SDavid Howells };
108030062bd1SDavid Howells 
108130062bd1SDavid Howells /*
108230062bd1SDavid Howells  * Store a set of pages to a large file.
108330062bd1SDavid Howells  */
yfs_fs_store_data(struct afs_operation * op)1084e49c7b2fSDavid Howells void yfs_fs_store_data(struct afs_operation *op)
108530062bd1SDavid Howells {
1086e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
108730062bd1SDavid Howells 	struct afs_call *call;
108830062bd1SDavid Howells 	__be32 *bp;
108930062bd1SDavid Howells 
109030062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1091e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
109230062bd1SDavid Howells 
109330062bd1SDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
1094bd80d8a8SDavid Howells 	       (unsigned long long)op->store.size,
1095bd80d8a8SDavid Howells 	       (unsigned long long)op->store.pos,
1096bd80d8a8SDavid Howells 	       (unsigned long long)op->store.i_size);
109730062bd1SDavid Howells 
1098e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64,
109930062bd1SDavid Howells 				   sizeof(__be32) +
110030062bd1SDavid Howells 				   sizeof(__be32) +
110130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
110230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
110330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
110430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
110530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
110630062bd1SDavid Howells 	if (!call)
1107e49c7b2fSDavid Howells 		return afs_op_nomem(op);
110830062bd1SDavid Howells 
1109bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
111030062bd1SDavid Howells 
111130062bd1SDavid Howells 	/* marshall the parameters */
111230062bd1SDavid Howells 	bp = call->request;
111330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
111430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1115e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
111652af7105SMarc Dionne 	bp = xdr_encode_YFSStoreStatus(bp, NULL, &op->mtime);
1117bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.pos);
1118bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.size);
1119bd80d8a8SDavid Howells 	bp = xdr_encode_u64(bp, op->store.i_size);
112030062bd1SDavid Howells 	yfs_check_req(call, bp);
112130062bd1SDavid Howells 
1122abcbd3bfSDavid Howells 	call->fid = vp->fid;
1123e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1124e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
112530062bd1SDavid Howells }
112630062bd1SDavid Howells 
112730062bd1SDavid Howells /*
112830062bd1SDavid Howells  * YFS.StoreStatus operation type
112930062bd1SDavid Howells  */
113030062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreStatus = {
113130062bd1SDavid Howells 	.name		= "YFS.StoreStatus",
113230062bd1SDavid Howells 	.op		= yfs_FS_StoreStatus,
1133a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
113430062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
113530062bd1SDavid Howells };
113630062bd1SDavid Howells 
113730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSStoreData64_as_Status = {
113830062bd1SDavid Howells 	.name		= "YFS.StoreData64",
113930062bd1SDavid Howells 	.op		= yfs_FS_StoreData64,
1140a58823acSDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
114130062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
114230062bd1SDavid Howells };
114330062bd1SDavid Howells 
114430062bd1SDavid Howells /*
114530062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 rather than
114630062bd1SDavid Howells  * YFS.StoreStatus so as to alter the file size also.
114730062bd1SDavid Howells  */
yfs_fs_setattr_size(struct afs_operation * op)1148e49c7b2fSDavid Howells static void yfs_fs_setattr_size(struct afs_operation *op)
114930062bd1SDavid Howells {
1150e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
115130062bd1SDavid Howells 	struct afs_call *call;
1152e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
115330062bd1SDavid Howells 	__be32 *bp;
115430062bd1SDavid Howells 
115530062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1156e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
115730062bd1SDavid Howells 
1158e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreData64_as_Status,
115930062bd1SDavid Howells 				   sizeof(__be32) * 2 +
116030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
116130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus) +
116230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64) * 3,
116330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
116430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
116530062bd1SDavid Howells 	if (!call)
1166e49c7b2fSDavid Howells 		return afs_op_nomem(op);
116730062bd1SDavid Howells 
116830062bd1SDavid Howells 	/* marshall the parameters */
116930062bd1SDavid Howells 	bp = call->request;
117030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREDATA64);
117130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1172e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
117330062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
11748c7ae38dSDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* position of start of write */
117530062bd1SDavid Howells 	bp = xdr_encode_u64(bp, 0);		/* size of write */
117630062bd1SDavid Howells 	bp = xdr_encode_u64(bp, attr->ia_size);	/* new file length */
117730062bd1SDavid Howells 	yfs_check_req(call, bp);
117830062bd1SDavid Howells 
1179abcbd3bfSDavid Howells 	call->fid = vp->fid;
1180e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1181e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
118230062bd1SDavid Howells }
118330062bd1SDavid Howells 
118430062bd1SDavid Howells /*
118530062bd1SDavid Howells  * Set the attributes on a file, using YFS.StoreData64 if there's a change in
118630062bd1SDavid Howells  * file size, and YFS.StoreStatus otherwise.
118730062bd1SDavid Howells  */
yfs_fs_setattr(struct afs_operation * op)1188e49c7b2fSDavid Howells void yfs_fs_setattr(struct afs_operation *op)
118930062bd1SDavid Howells {
1190e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
119130062bd1SDavid Howells 	struct afs_call *call;
1192e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
119330062bd1SDavid Howells 	__be32 *bp;
119430062bd1SDavid Howells 
119530062bd1SDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1196e49c7b2fSDavid Howells 		return yfs_fs_setattr_size(op);
119730062bd1SDavid Howells 
119830062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1199e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
120030062bd1SDavid Howells 
1201e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreStatus,
120230062bd1SDavid Howells 				   sizeof(__be32) * 2 +
120330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
120430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSStoreStatus),
120530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
120630062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
120730062bd1SDavid Howells 	if (!call)
1208e49c7b2fSDavid Howells 		return afs_op_nomem(op);
120930062bd1SDavid Howells 
121030062bd1SDavid Howells 	/* marshall the parameters */
121130062bd1SDavid Howells 	bp = call->request;
121230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTORESTATUS);
121330062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1214e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
121530062bd1SDavid Howells 	bp = xdr_encode_YFS_StoreStatus(bp, attr);
121630062bd1SDavid Howells 	yfs_check_req(call, bp);
121730062bd1SDavid Howells 
1218abcbd3bfSDavid Howells 	call->fid = vp->fid;
1219e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1220e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
122130062bd1SDavid Howells }
122230062bd1SDavid Howells 
122330062bd1SDavid Howells /*
122430062bd1SDavid Howells  * Deliver reply data to a YFS.GetVolumeStatus operation.
122530062bd1SDavid Howells  */
yfs_deliver_fs_get_volume_status(struct afs_call * call)122630062bd1SDavid Howells static int yfs_deliver_fs_get_volume_status(struct afs_call *call)
122730062bd1SDavid Howells {
1228e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
122930062bd1SDavid Howells 	const __be32 *bp;
123030062bd1SDavid Howells 	char *p;
123130062bd1SDavid Howells 	u32 size;
123230062bd1SDavid Howells 	int ret;
123330062bd1SDavid Howells 
123430062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
123530062bd1SDavid Howells 
123630062bd1SDavid Howells 	switch (call->unmarshall) {
123730062bd1SDavid Howells 	case 0:
123830062bd1SDavid Howells 		call->unmarshall++;
123930062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchVolumeStatus));
1240df561f66SGustavo A. R. Silva 		fallthrough;
124130062bd1SDavid Howells 
124235a3a90cSGustavo A. R. Silva 		/* extract the returned status record */
124330062bd1SDavid Howells 	case 1:
124430062bd1SDavid Howells 		_debug("extract status");
124530062bd1SDavid Howells 		ret = afs_extract_data(call, true);
124630062bd1SDavid Howells 		if (ret < 0)
124730062bd1SDavid Howells 			return ret;
124830062bd1SDavid Howells 
124930062bd1SDavid Howells 		bp = call->buffer;
1250e49c7b2fSDavid Howells 		xdr_decode_YFSFetchVolumeStatus(&bp, &op->volstatus.vs);
125130062bd1SDavid Howells 		call->unmarshall++;
125230062bd1SDavid Howells 		afs_extract_to_tmp(call);
1253df561f66SGustavo A. R. Silva 		fallthrough;
125430062bd1SDavid Howells 
125535a3a90cSGustavo A. R. Silva 		/* extract the volume name length */
125630062bd1SDavid Howells 	case 2:
125730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
125830062bd1SDavid Howells 		if (ret < 0)
125930062bd1SDavid Howells 			return ret;
126030062bd1SDavid Howells 
126130062bd1SDavid Howells 		call->count = ntohl(call->tmp);
126230062bd1SDavid Howells 		_debug("volname length: %u", call->count);
126330062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
12647126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
126530062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1266ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
126730062bd1SDavid Howells 		call->unmarshall++;
1268df561f66SGustavo A. R. Silva 		fallthrough;
126930062bd1SDavid Howells 
127035a3a90cSGustavo A. R. Silva 		/* extract the volume name */
127130062bd1SDavid Howells 	case 3:
127230062bd1SDavid Howells 		_debug("extract volname");
127330062bd1SDavid Howells 		ret = afs_extract_data(call, true);
127430062bd1SDavid Howells 		if (ret < 0)
127530062bd1SDavid Howells 			return ret;
127630062bd1SDavid Howells 
1277ffba718eSDavid Howells 		p = call->buffer;
127830062bd1SDavid Howells 		p[call->count] = 0;
127930062bd1SDavid Howells 		_debug("volname '%s'", p);
128030062bd1SDavid Howells 		afs_extract_to_tmp(call);
128130062bd1SDavid Howells 		call->unmarshall++;
1282df561f66SGustavo A. R. Silva 		fallthrough;
128330062bd1SDavid Howells 
128435a3a90cSGustavo A. R. Silva 		/* extract the offline message length */
128530062bd1SDavid Howells 	case 4:
128630062bd1SDavid Howells 		ret = afs_extract_data(call, true);
128730062bd1SDavid Howells 		if (ret < 0)
128830062bd1SDavid Howells 			return ret;
128930062bd1SDavid Howells 
129030062bd1SDavid Howells 		call->count = ntohl(call->tmp);
129130062bd1SDavid Howells 		_debug("offline msg length: %u", call->count);
129230062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
12937126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
129430062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1295ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
129630062bd1SDavid Howells 		call->unmarshall++;
1297df561f66SGustavo A. R. Silva 		fallthrough;
129830062bd1SDavid Howells 
129935a3a90cSGustavo A. R. Silva 		/* extract the offline message */
130030062bd1SDavid Howells 	case 5:
130130062bd1SDavid Howells 		_debug("extract offline");
130230062bd1SDavid Howells 		ret = afs_extract_data(call, true);
130330062bd1SDavid Howells 		if (ret < 0)
130430062bd1SDavid Howells 			return ret;
130530062bd1SDavid Howells 
1306ffba718eSDavid Howells 		p = call->buffer;
130730062bd1SDavid Howells 		p[call->count] = 0;
130830062bd1SDavid Howells 		_debug("offline '%s'", p);
130930062bd1SDavid Howells 
131030062bd1SDavid Howells 		afs_extract_to_tmp(call);
131130062bd1SDavid Howells 		call->unmarshall++;
1312df561f66SGustavo A. R. Silva 		fallthrough;
131330062bd1SDavid Howells 
131435a3a90cSGustavo A. R. Silva 		/* extract the message of the day length */
131530062bd1SDavid Howells 	case 6:
131630062bd1SDavid Howells 		ret = afs_extract_data(call, true);
131730062bd1SDavid Howells 		if (ret < 0)
131830062bd1SDavid Howells 			return ret;
131930062bd1SDavid Howells 
132030062bd1SDavid Howells 		call->count = ntohl(call->tmp);
132130062bd1SDavid Howells 		_debug("motd length: %u", call->count);
132230062bd1SDavid Howells 		if (call->count >= AFSNAMEMAX)
13237126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
132430062bd1SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1325ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
132630062bd1SDavid Howells 		call->unmarshall++;
1327df561f66SGustavo A. R. Silva 		fallthrough;
132830062bd1SDavid Howells 
132935a3a90cSGustavo A. R. Silva 		/* extract the message of the day */
133030062bd1SDavid Howells 	case 7:
133130062bd1SDavid Howells 		_debug("extract motd");
133230062bd1SDavid Howells 		ret = afs_extract_data(call, false);
133330062bd1SDavid Howells 		if (ret < 0)
133430062bd1SDavid Howells 			return ret;
133530062bd1SDavid Howells 
1336ffba718eSDavid Howells 		p = call->buffer;
133730062bd1SDavid Howells 		p[call->count] = 0;
133830062bd1SDavid Howells 		_debug("motd '%s'", p);
133930062bd1SDavid Howells 
134030062bd1SDavid Howells 		call->unmarshall++;
1341df561f66SGustavo A. R. Silva 		fallthrough;
134235a3a90cSGustavo A. R. Silva 
134330062bd1SDavid Howells 	case 8:
134430062bd1SDavid Howells 		break;
134530062bd1SDavid Howells 	}
134630062bd1SDavid Howells 
134730062bd1SDavid Howells 	_leave(" = 0 [done]");
134830062bd1SDavid Howells 	return 0;
134930062bd1SDavid Howells }
135030062bd1SDavid Howells 
135130062bd1SDavid Howells /*
135230062bd1SDavid Howells  * YFS.GetVolumeStatus operation type
135330062bd1SDavid Howells  */
135430062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSGetVolumeStatus = {
135530062bd1SDavid Howells 	.name		= "YFS.GetVolumeStatus",
135630062bd1SDavid Howells 	.op		= yfs_FS_GetVolumeStatus,
135730062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_get_volume_status,
1358ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
135930062bd1SDavid Howells };
136030062bd1SDavid Howells 
136130062bd1SDavid Howells /*
136230062bd1SDavid Howells  * fetch the status of a volume
136330062bd1SDavid Howells  */
yfs_fs_get_volume_status(struct afs_operation * op)1364e49c7b2fSDavid Howells void yfs_fs_get_volume_status(struct afs_operation *op)
136530062bd1SDavid Howells {
1366e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
136730062bd1SDavid Howells 	struct afs_call *call;
136830062bd1SDavid Howells 	__be32 *bp;
136930062bd1SDavid Howells 
137030062bd1SDavid Howells 	_enter("");
137130062bd1SDavid Howells 
1372e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSGetVolumeStatus,
137330062bd1SDavid Howells 				   sizeof(__be32) * 2 +
137430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_u64),
1375ffba718eSDavid Howells 				   max_t(size_t,
137630062bd1SDavid Howells 					 sizeof(struct yfs_xdr_YFSFetchVolumeStatus) +
1377ffba718eSDavid Howells 					 sizeof(__be32),
1378ffba718eSDavid Howells 					 AFSOPAQUEMAX + 1));
1379ffba718eSDavid Howells 	if (!call)
1380e49c7b2fSDavid Howells 		return afs_op_nomem(op);
138130062bd1SDavid Howells 
138230062bd1SDavid Howells 	/* marshall the parameters */
138330062bd1SDavid Howells 	bp = call->request;
138430062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSGETVOLUMESTATUS);
138530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1386e49c7b2fSDavid Howells 	bp = xdr_encode_u64(bp, vp->fid.vid);
138730062bd1SDavid Howells 	yfs_check_req(call, bp);
138830062bd1SDavid Howells 
1389abcbd3bfSDavid Howells 	call->fid = vp->fid;
1390e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1391e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
139230062bd1SDavid Howells }
139330062bd1SDavid Howells 
139430062bd1SDavid Howells /*
139530062bd1SDavid Howells  * YFS.SetLock operation type
139630062bd1SDavid Howells  */
139730062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSSetLock = {
139830062bd1SDavid Howells 	.name		= "YFS.SetLock",
139930062bd1SDavid Howells 	.op		= yfs_FS_SetLock,
1400f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1401a690f60aSDavid Howells 	.done		= afs_lock_op_done,
140230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
140330062bd1SDavid Howells };
140430062bd1SDavid Howells 
140530062bd1SDavid Howells /*
140630062bd1SDavid Howells  * YFS.ExtendLock operation type
140730062bd1SDavid Howells  */
140830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSExtendLock = {
140930062bd1SDavid Howells 	.name		= "YFS.ExtendLock",
141030062bd1SDavid Howells 	.op		= yfs_FS_ExtendLock,
1411f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1412a690f60aSDavid Howells 	.done		= afs_lock_op_done,
141330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
141430062bd1SDavid Howells };
141530062bd1SDavid Howells 
141630062bd1SDavid Howells /*
141730062bd1SDavid Howells  * YFS.ReleaseLock operation type
141830062bd1SDavid Howells  */
141930062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSReleaseLock = {
142030062bd1SDavid Howells 	.name		= "YFS.ReleaseLock",
142130062bd1SDavid Howells 	.op		= yfs_FS_ReleaseLock,
1422f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
142330062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
142430062bd1SDavid Howells };
142530062bd1SDavid Howells 
142630062bd1SDavid Howells /*
142730062bd1SDavid Howells  * Set a lock on a file
142830062bd1SDavid Howells  */
yfs_fs_set_lock(struct afs_operation * op)1429e49c7b2fSDavid Howells void yfs_fs_set_lock(struct afs_operation *op)
143030062bd1SDavid Howells {
1431e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
143230062bd1SDavid Howells 	struct afs_call *call;
143330062bd1SDavid Howells 	__be32 *bp;
143430062bd1SDavid Howells 
143530062bd1SDavid Howells 	_enter("");
143630062bd1SDavid Howells 
1437e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSSetLock,
143830062bd1SDavid Howells 				   sizeof(__be32) * 2 +
143930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
144030062bd1SDavid Howells 				   sizeof(__be32),
144130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
144230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
144330062bd1SDavid Howells 	if (!call)
1444e49c7b2fSDavid Howells 		return afs_op_nomem(op);
144530062bd1SDavid Howells 
144630062bd1SDavid Howells 	/* marshall the parameters */
144730062bd1SDavid Howells 	bp = call->request;
144830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSSETLOCK);
144930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1450e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1451e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->lock.type);
145230062bd1SDavid Howells 	yfs_check_req(call, bp);
145330062bd1SDavid Howells 
1454abcbd3bfSDavid Howells 	call->fid = vp->fid;
1455e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1456e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
145730062bd1SDavid Howells }
145830062bd1SDavid Howells 
145930062bd1SDavid Howells /*
146030062bd1SDavid Howells  * extend a lock on a file
146130062bd1SDavid Howells  */
yfs_fs_extend_lock(struct afs_operation * op)1462e49c7b2fSDavid Howells void yfs_fs_extend_lock(struct afs_operation *op)
146330062bd1SDavid Howells {
1464e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
146530062bd1SDavid Howells 	struct afs_call *call;
146630062bd1SDavid Howells 	__be32 *bp;
146730062bd1SDavid Howells 
146830062bd1SDavid Howells 	_enter("");
146930062bd1SDavid Howells 
1470e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSExtendLock,
147130062bd1SDavid Howells 				   sizeof(__be32) * 2 +
147230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
147330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
147430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
147530062bd1SDavid Howells 	if (!call)
1476e49c7b2fSDavid Howells 		return afs_op_nomem(op);
147730062bd1SDavid Howells 
147830062bd1SDavid Howells 	/* marshall the parameters */
147930062bd1SDavid Howells 	bp = call->request;
148030062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSEXTENDLOCK);
148130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1482e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
148330062bd1SDavid Howells 	yfs_check_req(call, bp);
148430062bd1SDavid Howells 
1485abcbd3bfSDavid Howells 	call->fid = vp->fid;
1486e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1487e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
148830062bd1SDavid Howells }
148930062bd1SDavid Howells 
149030062bd1SDavid Howells /*
149130062bd1SDavid Howells  * release a lock on a file
149230062bd1SDavid Howells  */
yfs_fs_release_lock(struct afs_operation * op)1493e49c7b2fSDavid Howells void yfs_fs_release_lock(struct afs_operation *op)
149430062bd1SDavid Howells {
1495e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
149630062bd1SDavid Howells 	struct afs_call *call;
149730062bd1SDavid Howells 	__be32 *bp;
149830062bd1SDavid Howells 
149930062bd1SDavid Howells 	_enter("");
150030062bd1SDavid Howells 
1501e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSReleaseLock,
150230062bd1SDavid Howells 				   sizeof(__be32) * 2 +
150330062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
150430062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
150530062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
150630062bd1SDavid Howells 	if (!call)
1507e49c7b2fSDavid Howells 		return afs_op_nomem(op);
150830062bd1SDavid Howells 
150930062bd1SDavid Howells 	/* marshall the parameters */
151030062bd1SDavid Howells 	bp = call->request;
151130062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSRELEASELOCK);
151230062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1513e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
151430062bd1SDavid Howells 	yfs_check_req(call, bp);
151530062bd1SDavid Howells 
1516abcbd3bfSDavid Howells 	call->fid = vp->fid;
1517e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1518e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
151930062bd1SDavid Howells }
152030062bd1SDavid Howells 
152130062bd1SDavid Howells /*
15229bd87ec6SDavid Howells  * Deliver a reply to YFS.FetchStatus
15239bd87ec6SDavid Howells  */
yfs_deliver_fs_fetch_status(struct afs_call * call)15249bd87ec6SDavid Howells static int yfs_deliver_fs_fetch_status(struct afs_call *call)
15259bd87ec6SDavid Howells {
15269bd87ec6SDavid Howells 	struct afs_operation *op = call->op;
15279bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
15289bd87ec6SDavid Howells 	const __be32 *bp;
15299bd87ec6SDavid Howells 	int ret;
15309bd87ec6SDavid Howells 
15319bd87ec6SDavid Howells 	ret = afs_transfer_reply(call);
15329bd87ec6SDavid Howells 	if (ret < 0)
15339bd87ec6SDavid Howells 		return ret;
15349bd87ec6SDavid Howells 
15359bd87ec6SDavid Howells 	/* unmarshall the reply once we've received all of it */
15369bd87ec6SDavid Howells 	bp = call->buffer;
15379bd87ec6SDavid Howells 	xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
15389bd87ec6SDavid Howells 	xdr_decode_YFSCallBack(&bp, call, &vp->scb);
15399bd87ec6SDavid Howells 	xdr_decode_YFSVolSync(&bp, &op->volsync);
15409bd87ec6SDavid Howells 
15419bd87ec6SDavid Howells 	_leave(" = 0 [done]");
15429bd87ec6SDavid Howells 	return 0;
15439bd87ec6SDavid Howells }
15449bd87ec6SDavid Howells 
15459bd87ec6SDavid Howells /*
154630062bd1SDavid Howells  * YFS.FetchStatus operation type
154730062bd1SDavid Howells  */
154830062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSFetchStatus = {
154930062bd1SDavid Howells 	.name		= "YFS.FetchStatus",
155030062bd1SDavid Howells 	.op		= yfs_FS_FetchStatus,
15519bd87ec6SDavid Howells 	.deliver	= yfs_deliver_fs_fetch_status,
155230062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
155330062bd1SDavid Howells };
155430062bd1SDavid Howells 
155530062bd1SDavid Howells /*
155630062bd1SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
155730062bd1SDavid Howells  */
yfs_fs_fetch_status(struct afs_operation * op)1558e49c7b2fSDavid Howells void yfs_fs_fetch_status(struct afs_operation *op)
155930062bd1SDavid Howells {
15609bd87ec6SDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
156130062bd1SDavid Howells 	struct afs_call *call;
156230062bd1SDavid Howells 	__be32 *bp;
156330062bd1SDavid Howells 
156430062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1565e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
156630062bd1SDavid Howells 
1567e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchStatus,
156830062bd1SDavid Howells 				   sizeof(__be32) * 2 +
156930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
157030062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
157130062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSCallBack) +
157230062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1573e49c7b2fSDavid Howells 	if (!call)
1574e49c7b2fSDavid Howells 		return afs_op_nomem(op);
157530062bd1SDavid Howells 
157630062bd1SDavid Howells 	/* marshall the parameters */
157730062bd1SDavid Howells 	bp = call->request;
157830062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHSTATUS);
157930062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1580e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
158130062bd1SDavid Howells 	yfs_check_req(call, bp);
158230062bd1SDavid Howells 
1583abcbd3bfSDavid Howells 	call->fid = vp->fid;
1584e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1585e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
158630062bd1SDavid Howells }
158730062bd1SDavid Howells 
158830062bd1SDavid Howells /*
158930062bd1SDavid Howells  * Deliver reply data to an YFS.InlineBulkStatus call
159030062bd1SDavid Howells  */
yfs_deliver_fs_inline_bulk_status(struct afs_call * call)159130062bd1SDavid Howells static int yfs_deliver_fs_inline_bulk_status(struct afs_call *call)
159230062bd1SDavid Howells {
1593e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
159487182759SDavid Howells 	struct afs_status_cb *scb;
159530062bd1SDavid Howells 	const __be32 *bp;
159630062bd1SDavid Howells 	u32 tmp;
159730062bd1SDavid Howells 	int ret;
159830062bd1SDavid Howells 
159930062bd1SDavid Howells 	_enter("{%u}", call->unmarshall);
160030062bd1SDavid Howells 
160130062bd1SDavid Howells 	switch (call->unmarshall) {
160230062bd1SDavid Howells 	case 0:
160330062bd1SDavid Howells 		afs_extract_to_tmp(call);
160430062bd1SDavid Howells 		call->unmarshall++;
1605df561f66SGustavo A. R. Silva 		fallthrough;
160630062bd1SDavid Howells 
160730062bd1SDavid Howells 		/* Extract the file status count and array in two steps */
160830062bd1SDavid Howells 	case 1:
160930062bd1SDavid Howells 		_debug("extract status count");
161030062bd1SDavid Howells 		ret = afs_extract_data(call, true);
161130062bd1SDavid Howells 		if (ret < 0)
161230062bd1SDavid Howells 			return ret;
161330062bd1SDavid Howells 
161430062bd1SDavid Howells 		tmp = ntohl(call->tmp);
1615e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1616e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
16177126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
161830062bd1SDavid Howells 
161930062bd1SDavid Howells 		call->count = 0;
162030062bd1SDavid Howells 		call->unmarshall++;
162130062bd1SDavid Howells 	more_counts:
162230062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSFetchStatus));
1623df561f66SGustavo A. R. Silva 		fallthrough;
162435a3a90cSGustavo A. R. Silva 
162530062bd1SDavid Howells 	case 2:
162630062bd1SDavid Howells 		_debug("extract status array %u", call->count);
162730062bd1SDavid Howells 		ret = afs_extract_data(call, true);
162830062bd1SDavid Howells 		if (ret < 0)
162930062bd1SDavid Howells 			return ret;
163030062bd1SDavid Howells 
1631e49c7b2fSDavid Howells 		switch (call->count) {
1632e49c7b2fSDavid Howells 		case 0:
1633e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1634e49c7b2fSDavid Howells 			break;
1635e49c7b2fSDavid Howells 		case 1:
1636e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1637e49c7b2fSDavid Howells 			break;
1638e49c7b2fSDavid Howells 		default:
1639e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1640e49c7b2fSDavid Howells 			break;
1641e49c7b2fSDavid Howells 		}
1642e49c7b2fSDavid Howells 
164330062bd1SDavid Howells 		bp = call->buffer;
164438355eecSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, scb);
164530062bd1SDavid Howells 
164630062bd1SDavid Howells 		call->count++;
1647e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
164830062bd1SDavid Howells 			goto more_counts;
164930062bd1SDavid Howells 
165030062bd1SDavid Howells 		call->count = 0;
165130062bd1SDavid Howells 		call->unmarshall++;
165230062bd1SDavid Howells 		afs_extract_to_tmp(call);
1653df561f66SGustavo A. R. Silva 		fallthrough;
165430062bd1SDavid Howells 
165530062bd1SDavid Howells 		/* Extract the callback count and array in two steps */
165630062bd1SDavid Howells 	case 3:
165730062bd1SDavid Howells 		_debug("extract CB count");
165830062bd1SDavid Howells 		ret = afs_extract_data(call, true);
165930062bd1SDavid Howells 		if (ret < 0)
166030062bd1SDavid Howells 			return ret;
166130062bd1SDavid Howells 
166230062bd1SDavid Howells 		tmp = ntohl(call->tmp);
166330062bd1SDavid Howells 		_debug("CB count: %u", tmp);
1664e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
16657126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
166630062bd1SDavid Howells 		call->count = 0;
166730062bd1SDavid Howells 		call->unmarshall++;
166830062bd1SDavid Howells 	more_cbs:
166930062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSCallBack));
1670df561f66SGustavo A. R. Silva 		fallthrough;
167135a3a90cSGustavo A. R. Silva 
167230062bd1SDavid Howells 	case 4:
167330062bd1SDavid Howells 		_debug("extract CB array");
167430062bd1SDavid Howells 		ret = afs_extract_data(call, true);
167530062bd1SDavid Howells 		if (ret < 0)
167630062bd1SDavid Howells 			return ret;
167730062bd1SDavid Howells 
167830062bd1SDavid Howells 		_debug("unmarshall CB array");
1679e49c7b2fSDavid Howells 		switch (call->count) {
1680e49c7b2fSDavid Howells 		case 0:
1681e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1682e49c7b2fSDavid Howells 			break;
1683e49c7b2fSDavid Howells 		case 1:
1684e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1685e49c7b2fSDavid Howells 			break;
1686e49c7b2fSDavid Howells 		default:
1687e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1688e49c7b2fSDavid Howells 			break;
1689e49c7b2fSDavid Howells 		}
1690e49c7b2fSDavid Howells 
169130062bd1SDavid Howells 		bp = call->buffer;
1692a58823acSDavid Howells 		xdr_decode_YFSCallBack(&bp, call, scb);
169330062bd1SDavid Howells 		call->count++;
1694e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
169530062bd1SDavid Howells 			goto more_cbs;
169630062bd1SDavid Howells 
169730062bd1SDavid Howells 		afs_extract_to_buf(call, sizeof(struct yfs_xdr_YFSVolSync));
169830062bd1SDavid Howells 		call->unmarshall++;
1699df561f66SGustavo A. R. Silva 		fallthrough;
170035a3a90cSGustavo A. R. Silva 
170130062bd1SDavid Howells 	case 5:
170230062bd1SDavid Howells 		ret = afs_extract_data(call, false);
170330062bd1SDavid Howells 		if (ret < 0)
170430062bd1SDavid Howells 			return ret;
170530062bd1SDavid Howells 
170630062bd1SDavid Howells 		bp = call->buffer;
1707e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
170830062bd1SDavid Howells 
170930062bd1SDavid Howells 		call->unmarshall++;
1710df561f66SGustavo A. R. Silva 		fallthrough;
171135a3a90cSGustavo A. R. Silva 
171230062bd1SDavid Howells 	case 6:
171330062bd1SDavid Howells 		break;
171430062bd1SDavid Howells 	}
171530062bd1SDavid Howells 
171630062bd1SDavid Howells 	_leave(" = 0 [done]");
171730062bd1SDavid Howells 	return 0;
171830062bd1SDavid Howells }
171930062bd1SDavid Howells 
172030062bd1SDavid Howells /*
172130062bd1SDavid Howells  * FS.InlineBulkStatus operation type
172230062bd1SDavid Howells  */
172330062bd1SDavid Howells static const struct afs_call_type yfs_RXYFSInlineBulkStatus = {
172430062bd1SDavid Howells 	.name		= "YFS.InlineBulkStatus",
172530062bd1SDavid Howells 	.op		= yfs_FS_InlineBulkStatus,
172630062bd1SDavid Howells 	.deliver	= yfs_deliver_fs_inline_bulk_status,
172730062bd1SDavid Howells 	.destructor	= afs_flat_call_destructor,
172830062bd1SDavid Howells };
172930062bd1SDavid Howells 
173030062bd1SDavid Howells /*
173130062bd1SDavid Howells  * Fetch the status information for up to 1024 files
173230062bd1SDavid Howells  */
yfs_fs_inline_bulk_status(struct afs_operation * op)1733e49c7b2fSDavid Howells void yfs_fs_inline_bulk_status(struct afs_operation *op)
173430062bd1SDavid Howells {
1735e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1736e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
173730062bd1SDavid Howells 	struct afs_call *call;
173830062bd1SDavid Howells 	__be32 *bp;
173930062bd1SDavid Howells 	int i;
174030062bd1SDavid Howells 
174130062bd1SDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1742e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
174330062bd1SDavid Howells 
1744e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSInlineBulkStatus,
174530062bd1SDavid Howells 				   sizeof(__be32) +
174630062bd1SDavid Howells 				   sizeof(__be32) +
174730062bd1SDavid Howells 				   sizeof(__be32) +
1748e49c7b2fSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) * op->nr_files,
174930062bd1SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus));
1750e49c7b2fSDavid Howells 	if (!call)
1751e49c7b2fSDavid Howells 		return afs_op_nomem(op);
175230062bd1SDavid Howells 
175330062bd1SDavid Howells 	/* marshall the parameters */
175430062bd1SDavid Howells 	bp = call->request;
175530062bd1SDavid Howells 	bp = xdr_encode_u32(bp, YFSINLINEBULKSTATUS);
175630062bd1SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPCFlags */
1757e49c7b2fSDavid Howells 	bp = xdr_encode_u32(bp, op->nr_files);
1758e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &dvp->fid);
1759e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1760e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++)
1761e49c7b2fSDavid Howells 		bp = xdr_encode_YFSFid(bp, &op->more_files[i].fid);
176230062bd1SDavid Howells 	yfs_check_req(call, bp);
176330062bd1SDavid Howells 
1764abcbd3bfSDavid Howells 	call->fid = vp->fid;
1765e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1766e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
176730062bd1SDavid Howells }
1768ae46578bSDavid Howells 
1769ae46578bSDavid Howells /*
1770ae46578bSDavid Howells  * Deliver reply data to an YFS.FetchOpaqueACL.
1771ae46578bSDavid Howells  */
yfs_deliver_fs_fetch_opaque_acl(struct afs_call * call)1772ae46578bSDavid Howells static int yfs_deliver_fs_fetch_opaque_acl(struct afs_call *call)
1773ae46578bSDavid Howells {
1774e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1775e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1776e49c7b2fSDavid Howells 	struct yfs_acl *yacl = op->yacl;
1777ae46578bSDavid Howells 	struct afs_acl *acl;
1778ae46578bSDavid Howells 	const __be32 *bp;
1779ae46578bSDavid Howells 	unsigned int size;
1780ae46578bSDavid Howells 	int ret;
1781ae46578bSDavid Howells 
1782ae46578bSDavid Howells 	_enter("{%u}", call->unmarshall);
1783ae46578bSDavid Howells 
1784ae46578bSDavid Howells 	switch (call->unmarshall) {
1785ae46578bSDavid Howells 	case 0:
1786ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1787ae46578bSDavid Howells 		call->unmarshall++;
1788df561f66SGustavo A. R. Silva 		fallthrough;
1789ae46578bSDavid Howells 
1790ae46578bSDavid Howells 		/* Extract the file ACL length */
1791ae46578bSDavid Howells 	case 1:
1792ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1793ae46578bSDavid Howells 		if (ret < 0)
1794ae46578bSDavid Howells 			return ret;
1795ae46578bSDavid Howells 
1796ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1797ae46578bSDavid Howells 		size = round_up(size, 4);
1798ae46578bSDavid Howells 
1799ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_ACL) {
1800ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1801ae46578bSDavid Howells 			if (!acl)
1802ae46578bSDavid Howells 				return -ENOMEM;
1803ae46578bSDavid Howells 			yacl->acl = acl;
1804ae46578bSDavid Howells 			acl->size = call->count2;
1805ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1806ae46578bSDavid Howells 		} else {
180723a28913SDavid Howells 			afs_extract_discard(call, size);
1808ae46578bSDavid Howells 		}
1809ae46578bSDavid Howells 		call->unmarshall++;
1810df561f66SGustavo A. R. Silva 		fallthrough;
1811ae46578bSDavid Howells 
1812ae46578bSDavid Howells 		/* Extract the file ACL */
1813ae46578bSDavid Howells 	case 2:
1814ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1815ae46578bSDavid Howells 		if (ret < 0)
1816ae46578bSDavid Howells 			return ret;
1817ae46578bSDavid Howells 
1818ae46578bSDavid Howells 		afs_extract_to_tmp(call);
1819ae46578bSDavid Howells 		call->unmarshall++;
1820df561f66SGustavo A. R. Silva 		fallthrough;
1821ae46578bSDavid Howells 
1822ae46578bSDavid Howells 		/* Extract the volume ACL length */
1823ae46578bSDavid Howells 	case 3:
1824ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1825ae46578bSDavid Howells 		if (ret < 0)
1826ae46578bSDavid Howells 			return ret;
1827ae46578bSDavid Howells 
1828ae46578bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1829ae46578bSDavid Howells 		size = round_up(size, 4);
1830ae46578bSDavid Howells 
1831ae46578bSDavid Howells 		if (yacl->flags & YFS_ACL_WANT_VOL_ACL) {
1832ae46578bSDavid Howells 			acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1833ae46578bSDavid Howells 			if (!acl)
1834ae46578bSDavid Howells 				return -ENOMEM;
1835ae46578bSDavid Howells 			yacl->vol_acl = acl;
1836ae46578bSDavid Howells 			acl->size = call->count2;
1837ae46578bSDavid Howells 			afs_extract_begin(call, acl->data, size);
1838ae46578bSDavid Howells 		} else {
183923a28913SDavid Howells 			afs_extract_discard(call, size);
1840ae46578bSDavid Howells 		}
1841ae46578bSDavid Howells 		call->unmarshall++;
1842df561f66SGustavo A. R. Silva 		fallthrough;
1843ae46578bSDavid Howells 
1844ae46578bSDavid Howells 		/* Extract the volume ACL */
1845ae46578bSDavid Howells 	case 4:
1846ae46578bSDavid Howells 		ret = afs_extract_data(call, true);
1847ae46578bSDavid Howells 		if (ret < 0)
1848ae46578bSDavid Howells 			return ret;
1849ae46578bSDavid Howells 
1850ae46578bSDavid Howells 		afs_extract_to_buf(call,
1851ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1852ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1853ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1854ae46578bSDavid Howells 		call->unmarshall++;
1855df561f66SGustavo A. R. Silva 		fallthrough;
1856ae46578bSDavid Howells 
1857ae46578bSDavid Howells 		/* extract the metadata */
1858ae46578bSDavid Howells 	case 5:
1859ae46578bSDavid Howells 		ret = afs_extract_data(call, false);
1860ae46578bSDavid Howells 		if (ret < 0)
1861ae46578bSDavid Howells 			return ret;
1862ae46578bSDavid Howells 
1863ae46578bSDavid Howells 		bp = call->buffer;
1864ae46578bSDavid Howells 		yacl->inherit_flag = ntohl(*bp++);
1865ae46578bSDavid Howells 		yacl->num_cleaned = ntohl(*bp++);
1866e49c7b2fSDavid Howells 		xdr_decode_YFSFetchStatus(&bp, call, &vp->scb);
1867e49c7b2fSDavid Howells 		xdr_decode_YFSVolSync(&bp, &op->volsync);
1868ae46578bSDavid Howells 
1869ae46578bSDavid Howells 		call->unmarshall++;
1870df561f66SGustavo A. R. Silva 		fallthrough;
1871ae46578bSDavid Howells 
1872ae46578bSDavid Howells 	case 6:
1873ae46578bSDavid Howells 		break;
1874ae46578bSDavid Howells 	}
1875ae46578bSDavid Howells 
1876ae46578bSDavid Howells 	_leave(" = 0 [done]");
1877ae46578bSDavid Howells 	return 0;
1878ae46578bSDavid Howells }
1879ae46578bSDavid Howells 
yfs_free_opaque_acl(struct yfs_acl * yacl)1880ae46578bSDavid Howells void yfs_free_opaque_acl(struct yfs_acl *yacl)
1881ae46578bSDavid Howells {
1882ae46578bSDavid Howells 	if (yacl) {
1883ae46578bSDavid Howells 		kfree(yacl->acl);
1884ae46578bSDavid Howells 		kfree(yacl->vol_acl);
1885ae46578bSDavid Howells 		kfree(yacl);
1886ae46578bSDavid Howells 	}
1887ae46578bSDavid Howells }
1888ae46578bSDavid Howells 
1889ae46578bSDavid Howells /*
1890ae46578bSDavid Howells  * YFS.FetchOpaqueACL operation type
1891ae46578bSDavid Howells  */
1892ae46578bSDavid Howells static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = {
1893ae46578bSDavid Howells 	.name		= "YFS.FetchOpaqueACL",
1894ae46578bSDavid Howells 	.op		= yfs_FS_FetchOpaqueACL,
1895ae46578bSDavid Howells 	.deliver	= yfs_deliver_fs_fetch_opaque_acl,
1896773e0c40SDavid Howells 	.destructor	= afs_flat_call_destructor,
1897ae46578bSDavid Howells };
1898ae46578bSDavid Howells 
1899ae46578bSDavid Howells /*
1900ae46578bSDavid Howells  * Fetch the YFS advanced ACLs for a file.
1901ae46578bSDavid Howells  */
yfs_fs_fetch_opaque_acl(struct afs_operation * op)1902e49c7b2fSDavid Howells void yfs_fs_fetch_opaque_acl(struct afs_operation *op)
1903ae46578bSDavid Howells {
1904e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1905ae46578bSDavid Howells 	struct afs_call *call;
1906ae46578bSDavid Howells 	__be32 *bp;
1907ae46578bSDavid Howells 
1908ae46578bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1909e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1910ae46578bSDavid Howells 
1911e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSFetchOpaqueACL,
1912ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1913ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFid),
1914ae46578bSDavid Howells 				   sizeof(__be32) * 2 +
1915ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1916ae46578bSDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1917e49c7b2fSDavid Howells 	if (!call)
1918e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1919ae46578bSDavid Howells 
1920ae46578bSDavid Howells 	/* marshall the parameters */
1921ae46578bSDavid Howells 	bp = call->request;
1922ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, YFSFETCHOPAQUEACL);
1923ae46578bSDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1924e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1925ae46578bSDavid Howells 	yfs_check_req(call, bp);
1926ae46578bSDavid Howells 
1927abcbd3bfSDavid Howells 	call->fid = vp->fid;
1928e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1929e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
1930ae46578bSDavid Howells }
1931f5e45463SDavid Howells 
1932f5e45463SDavid Howells /*
1933f5e45463SDavid Howells  * YFS.StoreOpaqueACL2 operation type
1934f5e45463SDavid Howells  */
1935f5e45463SDavid Howells static const struct afs_call_type yfs_RXYFSStoreOpaqueACL2 = {
1936f5e45463SDavid Howells 	.name		= "YFS.StoreOpaqueACL2",
1937f5e45463SDavid Howells 	.op		= yfs_FS_StoreOpaqueACL2,
1938f5e45463SDavid Howells 	.deliver	= yfs_deliver_status_and_volsync,
1939f5e45463SDavid Howells 	.destructor	= afs_flat_call_destructor,
1940f5e45463SDavid Howells };
1941f5e45463SDavid Howells 
1942f5e45463SDavid Howells /*
1943f5e45463SDavid Howells  * Fetch the YFS ACL for a file.
1944f5e45463SDavid Howells  */
yfs_fs_store_opaque_acl2(struct afs_operation * op)1945e49c7b2fSDavid Howells void yfs_fs_store_opaque_acl2(struct afs_operation *op)
1946f5e45463SDavid Howells {
1947e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1948f5e45463SDavid Howells 	struct afs_call *call;
1949e49c7b2fSDavid Howells 	struct afs_acl *acl = op->acl;
1950f5e45463SDavid Howells 	size_t size;
1951f5e45463SDavid Howells 	__be32 *bp;
1952f5e45463SDavid Howells 
1953f5e45463SDavid Howells 	_enter(",%x,{%llx:%llu},,",
1954e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1955f5e45463SDavid Howells 
1956f5e45463SDavid Howells 	size = round_up(acl->size, 4);
1957e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &yfs_RXYFSStoreOpaqueACL2,
1958f5e45463SDavid Howells 				   sizeof(__be32) * 2 +
1959f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFid) +
1960f5e45463SDavid Howells 				   sizeof(__be32) + size,
1961f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSFetchStatus) +
1962f5e45463SDavid Howells 				   sizeof(struct yfs_xdr_YFSVolSync));
1963e49c7b2fSDavid Howells 	if (!call)
1964e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1965f5e45463SDavid Howells 
1966f5e45463SDavid Howells 	/* marshall the parameters */
1967f5e45463SDavid Howells 	bp = call->request;
1968f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, YFSSTOREOPAQUEACL2);
1969f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, 0); /* RPC flags */
1970e49c7b2fSDavid Howells 	bp = xdr_encode_YFSFid(bp, &vp->fid);
1971f5e45463SDavid Howells 	bp = xdr_encode_u32(bp, acl->size);
1972f5e45463SDavid Howells 	memcpy(bp, acl->data, acl->size);
1973f5e45463SDavid Howells 	if (acl->size != size)
1974f5e45463SDavid Howells 		memset((void *)bp + acl->size, 0, size - acl->size);
1975c80afa1dSDavid Howells 	bp += size / sizeof(__be32);
1976f5e45463SDavid Howells 	yfs_check_req(call, bp);
1977f5e45463SDavid Howells 
1978abcbd3bfSDavid Howells 	call->fid = vp->fid;
1979e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1980e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
198130062bd1SDavid Howells }
1982