xref: /kernel/linux/linux-5.10/fs/afs/fsclient.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* AFS File Server client stubs
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include <linux/circ_buf.h>
128c2ecf20Sopenharmony_ci#include <linux/iversion.h>
138c2ecf20Sopenharmony_ci#include "internal.h"
148c2ecf20Sopenharmony_ci#include "afs_fs.h"
158c2ecf20Sopenharmony_ci#include "xdr_fs.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/*
188c2ecf20Sopenharmony_ci * decode an AFSFid block
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_cistatic void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	const __be32 *bp = *_bp;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	fid->vid		= ntohl(*bp++);
258c2ecf20Sopenharmony_ci	fid->vnode		= ntohl(*bp++);
268c2ecf20Sopenharmony_ci	fid->unique		= ntohl(*bp++);
278c2ecf20Sopenharmony_ci	*_bp = bp;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * Dump a bad file status record.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_cistatic void xdr_dump_bad(const __be32 *bp)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	__be32 x[4];
368c2ecf20Sopenharmony_ci	int i;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	pr_notice("AFS XDR: Bad status record\n");
398c2ecf20Sopenharmony_ci	for (i = 0; i < 5 * 4 * 4; i += 16) {
408c2ecf20Sopenharmony_ci		memcpy(x, bp, 16);
418c2ecf20Sopenharmony_ci		bp += 4;
428c2ecf20Sopenharmony_ci		pr_notice("%03x: %08x %08x %08x %08x\n",
438c2ecf20Sopenharmony_ci			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	memcpy(x, bp, 4);
478c2ecf20Sopenharmony_ci	pr_notice("0x50: %08x\n", ntohl(x[0]));
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * decode an AFSFetchStatus block
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistatic void xdr_decode_AFSFetchStatus(const __be32 **_bp,
548c2ecf20Sopenharmony_ci				      struct afs_call *call,
558c2ecf20Sopenharmony_ci				      struct afs_status_cb *scb)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
588c2ecf20Sopenharmony_ci	struct afs_file_status *status = &scb->status;
598c2ecf20Sopenharmony_ci	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
608c2ecf20Sopenharmony_ci	u64 data_version, size;
618c2ecf20Sopenharmony_ci	u32 type, abort_code;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	abort_code = ntohl(xdr->abort_code);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
668c2ecf20Sopenharmony_ci		if (xdr->if_version == htonl(0) &&
678c2ecf20Sopenharmony_ci		    abort_code != 0 &&
688c2ecf20Sopenharmony_ci		    inline_error) {
698c2ecf20Sopenharmony_ci			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
708c2ecf20Sopenharmony_ci			 * whereby it doesn't set the interface version in the error
718c2ecf20Sopenharmony_ci			 * case.
728c2ecf20Sopenharmony_ci			 */
738c2ecf20Sopenharmony_ci			status->abort_code = abort_code;
748c2ecf20Sopenharmony_ci			scb->have_error = true;
758c2ecf20Sopenharmony_ci			goto advance;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
798c2ecf20Sopenharmony_ci		goto bad;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (abort_code != 0 && inline_error) {
838c2ecf20Sopenharmony_ci		status->abort_code = abort_code;
848c2ecf20Sopenharmony_ci		scb->have_error = true;
858c2ecf20Sopenharmony_ci		goto advance;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	type = ntohl(xdr->type);
898c2ecf20Sopenharmony_ci	switch (type) {
908c2ecf20Sopenharmony_ci	case AFS_FTYPE_FILE:
918c2ecf20Sopenharmony_ci	case AFS_FTYPE_DIR:
928c2ecf20Sopenharmony_ci	case AFS_FTYPE_SYMLINK:
938c2ecf20Sopenharmony_ci		status->type = type;
948c2ecf20Sopenharmony_ci		break;
958c2ecf20Sopenharmony_ci	default:
968c2ecf20Sopenharmony_ci		goto bad;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	status->nlink		= ntohl(xdr->nlink);
1008c2ecf20Sopenharmony_ci	status->author		= ntohl(xdr->author);
1018c2ecf20Sopenharmony_ci	status->owner		= ntohl(xdr->owner);
1028c2ecf20Sopenharmony_ci	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
1038c2ecf20Sopenharmony_ci	status->anon_access	= ntohl(xdr->anon_access);
1048c2ecf20Sopenharmony_ci	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
1058c2ecf20Sopenharmony_ci	status->group		= ntohl(xdr->group);
1068c2ecf20Sopenharmony_ci	status->lock_count	= ntohl(xdr->lock_count);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
1098c2ecf20Sopenharmony_ci	status->mtime_client.tv_nsec = 0;
1108c2ecf20Sopenharmony_ci	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
1118c2ecf20Sopenharmony_ci	status->mtime_server.tv_nsec = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	size  = (u64)ntohl(xdr->size_lo);
1148c2ecf20Sopenharmony_ci	size |= (u64)ntohl(xdr->size_hi) << 32;
1158c2ecf20Sopenharmony_ci	status->size = size;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	data_version  = (u64)ntohl(xdr->data_version_lo);
1188c2ecf20Sopenharmony_ci	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
1198c2ecf20Sopenharmony_ci	status->data_version = data_version;
1208c2ecf20Sopenharmony_ci	scb->have_status = true;
1218c2ecf20Sopenharmony_ciadvance:
1228c2ecf20Sopenharmony_ci	*_bp = (const void *)*_bp + sizeof(*xdr);
1238c2ecf20Sopenharmony_ci	return;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cibad:
1268c2ecf20Sopenharmony_ci	xdr_dump_bad(*_bp);
1278c2ecf20Sopenharmony_ci	afs_protocol_error(call, afs_eproto_bad_status);
1288c2ecf20Sopenharmony_ci	goto advance;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return ktime_divns(call->issue_time, NSEC_PER_SEC) + expiry;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic void xdr_decode_AFSCallBack(const __be32 **_bp,
1378c2ecf20Sopenharmony_ci				   struct afs_call *call,
1388c2ecf20Sopenharmony_ci				   struct afs_status_cb *scb)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct afs_callback *cb = &scb->callback;
1418c2ecf20Sopenharmony_ci	const __be32 *bp = *_bp;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	bp++; /* version */
1448c2ecf20Sopenharmony_ci	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1458c2ecf20Sopenharmony_ci	bp++; /* type */
1468c2ecf20Sopenharmony_ci	scb->have_cb	= true;
1478c2ecf20Sopenharmony_ci	*_bp = bp;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/*
1518c2ecf20Sopenharmony_ci * decode an AFSVolSync block
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_cistatic void xdr_decode_AFSVolSync(const __be32 **_bp,
1548c2ecf20Sopenharmony_ci				  struct afs_volsync *volsync)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	const __be32 *bp = *_bp;
1578c2ecf20Sopenharmony_ci	u32 creation;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	creation = ntohl(*bp++);
1608c2ecf20Sopenharmony_ci	bp++; /* spare2 */
1618c2ecf20Sopenharmony_ci	bp++; /* spare3 */
1628c2ecf20Sopenharmony_ci	bp++; /* spare4 */
1638c2ecf20Sopenharmony_ci	bp++; /* spare5 */
1648c2ecf20Sopenharmony_ci	bp++; /* spare6 */
1658c2ecf20Sopenharmony_ci	*_bp = bp;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (volsync)
1688c2ecf20Sopenharmony_ci		volsync->creation = creation;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/*
1728c2ecf20Sopenharmony_ci * encode the requested attributes into an AFSStoreStatus block
1738c2ecf20Sopenharmony_ci */
1748c2ecf20Sopenharmony_cistatic void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	__be32 *bp = *_bp;
1778c2ecf20Sopenharmony_ci	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	mask = 0;
1808c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_MTIME) {
1818c2ecf20Sopenharmony_ci		mask |= AFS_SET_MTIME;
1828c2ecf20Sopenharmony_ci		mtime = attr->ia_mtime.tv_sec;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_UID) {
1868c2ecf20Sopenharmony_ci		mask |= AFS_SET_OWNER;
1878c2ecf20Sopenharmony_ci		owner = from_kuid(&init_user_ns, attr->ia_uid);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_GID) {
1918c2ecf20Sopenharmony_ci		mask |= AFS_SET_GROUP;
1928c2ecf20Sopenharmony_ci		group = from_kgid(&init_user_ns, attr->ia_gid);
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE) {
1968c2ecf20Sopenharmony_ci		mask |= AFS_SET_MODE;
1978c2ecf20Sopenharmony_ci		mode = attr->ia_mode & S_IALLUGO;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	*bp++ = htonl(mask);
2018c2ecf20Sopenharmony_ci	*bp++ = htonl(mtime);
2028c2ecf20Sopenharmony_ci	*bp++ = htonl(owner);
2038c2ecf20Sopenharmony_ci	*bp++ = htonl(group);
2048c2ecf20Sopenharmony_ci	*bp++ = htonl(mode);
2058c2ecf20Sopenharmony_ci	*bp++ = 0;		/* segment size */
2068c2ecf20Sopenharmony_ci	*_bp = bp;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/*
2108c2ecf20Sopenharmony_ci * decode an AFSFetchVolumeStatus block
2118c2ecf20Sopenharmony_ci */
2128c2ecf20Sopenharmony_cistatic void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
2138c2ecf20Sopenharmony_ci					    struct afs_volume_status *vs)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	const __be32 *bp = *_bp;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	vs->vid			= ntohl(*bp++);
2188c2ecf20Sopenharmony_ci	vs->parent_id		= ntohl(*bp++);
2198c2ecf20Sopenharmony_ci	vs->online		= ntohl(*bp++);
2208c2ecf20Sopenharmony_ci	vs->in_service		= ntohl(*bp++);
2218c2ecf20Sopenharmony_ci	vs->blessed		= ntohl(*bp++);
2228c2ecf20Sopenharmony_ci	vs->needs_salvage	= ntohl(*bp++);
2238c2ecf20Sopenharmony_ci	vs->type		= ntohl(*bp++);
2248c2ecf20Sopenharmony_ci	vs->min_quota		= ntohl(*bp++);
2258c2ecf20Sopenharmony_ci	vs->max_quota		= ntohl(*bp++);
2268c2ecf20Sopenharmony_ci	vs->blocks_in_use	= ntohl(*bp++);
2278c2ecf20Sopenharmony_ci	vs->part_blocks_avail	= ntohl(*bp++);
2288c2ecf20Sopenharmony_ci	vs->part_max_blocks	= ntohl(*bp++);
2298c2ecf20Sopenharmony_ci	vs->vol_copy_date	= 0;
2308c2ecf20Sopenharmony_ci	vs->vol_backup_date	= 0;
2318c2ecf20Sopenharmony_ci	*_bp = bp;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/*
2358c2ecf20Sopenharmony_ci * deliver reply data to an FS.FetchStatus
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_cistatic int afs_deliver_fs_fetch_status(struct afs_call *call)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
2408c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
2418c2ecf20Sopenharmony_ci	const __be32 *bp;
2428c2ecf20Sopenharmony_ci	int ret;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
2458c2ecf20Sopenharmony_ci	if (ret < 0)
2468c2ecf20Sopenharmony_ci		return ret;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
2498c2ecf20Sopenharmony_ci	bp = call->buffer;
2508c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
2518c2ecf20Sopenharmony_ci	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
2528c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/*
2598c2ecf20Sopenharmony_ci * FS.FetchStatus operation type
2608c2ecf20Sopenharmony_ci */
2618c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSFetchStatus = {
2628c2ecf20Sopenharmony_ci	.name		= "FS.FetchStatus",
2638c2ecf20Sopenharmony_ci	.op		= afs_FS_FetchStatus,
2648c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_fetch_status,
2658c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
2668c2ecf20Sopenharmony_ci};
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/*
2698c2ecf20Sopenharmony_ci * fetch the status information for a file
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_civoid afs_fs_fetch_status(struct afs_operation *op)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
2748c2ecf20Sopenharmony_ci	struct afs_call *call;
2758c2ecf20Sopenharmony_ci	__be32 *bp;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
2788c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchStatus,
2818c2ecf20Sopenharmony_ci				   16, (21 + 3 + 6) * 4);
2828c2ecf20Sopenharmony_ci	if (!call)
2838c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	/* marshall the parameters */
2868c2ecf20Sopenharmony_ci	bp = call->request;
2878c2ecf20Sopenharmony_ci	bp[0] = htonl(FSFETCHSTATUS);
2888c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
2898c2ecf20Sopenharmony_ci	bp[2] = htonl(vp->fid.vnode);
2908c2ecf20Sopenharmony_ci	bp[3] = htonl(vp->fid.unique);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
2938c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/*
2978c2ecf20Sopenharmony_ci * deliver reply data to an FS.FetchData
2988c2ecf20Sopenharmony_ci */
2998c2ecf20Sopenharmony_cistatic int afs_deliver_fs_fetch_data(struct afs_call *call)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
3028c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
3038c2ecf20Sopenharmony_ci	struct afs_read *req = op->fetch.req;
3048c2ecf20Sopenharmony_ci	const __be32 *bp;
3058c2ecf20Sopenharmony_ci	unsigned int size;
3068c2ecf20Sopenharmony_ci	int ret;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	_enter("{%u,%zu/%llu}",
3098c2ecf20Sopenharmony_ci	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
3128c2ecf20Sopenharmony_ci	case 0:
3138c2ecf20Sopenharmony_ci		req->actual_len = 0;
3148c2ecf20Sopenharmony_ci		req->index = 0;
3158c2ecf20Sopenharmony_ci		req->offset = req->pos & (PAGE_SIZE - 1);
3168c2ecf20Sopenharmony_ci		call->unmarshall++;
3178c2ecf20Sopenharmony_ci		if (call->operation_ID == FSFETCHDATA64) {
3188c2ecf20Sopenharmony_ci			afs_extract_to_tmp64(call);
3198c2ecf20Sopenharmony_ci		} else {
3208c2ecf20Sopenharmony_ci			call->tmp_u = htonl(0);
3218c2ecf20Sopenharmony_ci			afs_extract_to_tmp(call);
3228c2ecf20Sopenharmony_ci		}
3238c2ecf20Sopenharmony_ci		fallthrough;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		/* extract the returned data length */
3268c2ecf20Sopenharmony_ci	case 1:
3278c2ecf20Sopenharmony_ci		_debug("extract data length");
3288c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
3298c2ecf20Sopenharmony_ci		if (ret < 0)
3308c2ecf20Sopenharmony_ci			return ret;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		req->actual_len = be64_to_cpu(call->tmp64);
3338c2ecf20Sopenharmony_ci		_debug("DATA length: %llu", req->actual_len);
3348c2ecf20Sopenharmony_ci		req->remain = min(req->len, req->actual_len);
3358c2ecf20Sopenharmony_ci		if (req->remain == 0)
3368c2ecf20Sopenharmony_ci			goto no_more_data;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		call->unmarshall++;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	begin_page:
3418c2ecf20Sopenharmony_ci		ASSERTCMP(req->index, <, req->nr_pages);
3428c2ecf20Sopenharmony_ci		if (req->remain > PAGE_SIZE - req->offset)
3438c2ecf20Sopenharmony_ci			size = PAGE_SIZE - req->offset;
3448c2ecf20Sopenharmony_ci		else
3458c2ecf20Sopenharmony_ci			size = req->remain;
3468c2ecf20Sopenharmony_ci		call->bvec[0].bv_len = size;
3478c2ecf20Sopenharmony_ci		call->bvec[0].bv_offset = req->offset;
3488c2ecf20Sopenharmony_ci		call->bvec[0].bv_page = req->pages[req->index];
3498c2ecf20Sopenharmony_ci		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
3508c2ecf20Sopenharmony_ci		ASSERTCMP(size, <=, PAGE_SIZE);
3518c2ecf20Sopenharmony_ci		fallthrough;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		/* extract the returned data */
3548c2ecf20Sopenharmony_ci	case 2:
3558c2ecf20Sopenharmony_ci		_debug("extract data %zu/%llu",
3568c2ecf20Sopenharmony_ci		       iov_iter_count(call->iter), req->remain);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
3598c2ecf20Sopenharmony_ci		if (ret < 0)
3608c2ecf20Sopenharmony_ci			return ret;
3618c2ecf20Sopenharmony_ci		req->remain -= call->bvec[0].bv_len;
3628c2ecf20Sopenharmony_ci		req->offset += call->bvec[0].bv_len;
3638c2ecf20Sopenharmony_ci		ASSERTCMP(req->offset, <=, PAGE_SIZE);
3648c2ecf20Sopenharmony_ci		if (req->offset == PAGE_SIZE) {
3658c2ecf20Sopenharmony_ci			req->offset = 0;
3668c2ecf20Sopenharmony_ci			req->index++;
3678c2ecf20Sopenharmony_ci			if (req->remain > 0)
3688c2ecf20Sopenharmony_ci				goto begin_page;
3698c2ecf20Sopenharmony_ci		}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		ASSERTCMP(req->remain, ==, 0);
3728c2ecf20Sopenharmony_ci		if (req->actual_len <= req->len)
3738c2ecf20Sopenharmony_ci			goto no_more_data;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci		/* Discard any excess data the server gave us */
3768c2ecf20Sopenharmony_ci		afs_extract_discard(call, req->actual_len - req->len);
3778c2ecf20Sopenharmony_ci		call->unmarshall = 3;
3788c2ecf20Sopenharmony_ci		fallthrough;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	case 3:
3818c2ecf20Sopenharmony_ci		_debug("extract discard %zu/%llu",
3828c2ecf20Sopenharmony_ci		       iov_iter_count(call->iter), req->actual_len - req->len);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
3858c2ecf20Sopenharmony_ci		if (ret < 0)
3868c2ecf20Sopenharmony_ci			return ret;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	no_more_data:
3898c2ecf20Sopenharmony_ci		call->unmarshall = 4;
3908c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
3918c2ecf20Sopenharmony_ci		fallthrough;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		/* extract the metadata */
3948c2ecf20Sopenharmony_ci	case 4:
3958c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
3968c2ecf20Sopenharmony_ci		if (ret < 0)
3978c2ecf20Sopenharmony_ci			return ret;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		bp = call->buffer;
4008c2ecf20Sopenharmony_ci		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
4018c2ecf20Sopenharmony_ci		xdr_decode_AFSCallBack(&bp, call, &vp->scb);
4028c2ecf20Sopenharmony_ci		xdr_decode_AFSVolSync(&bp, &op->volsync);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		req->data_version = vp->scb.status.data_version;
4058c2ecf20Sopenharmony_ci		req->file_size = vp->scb.status.size;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci		call->unmarshall++;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	case 5:
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	for (; req->index < req->nr_pages; req->index++) {
4148c2ecf20Sopenharmony_ci		if (req->offset < PAGE_SIZE)
4158c2ecf20Sopenharmony_ci			zero_user_segment(req->pages[req->index],
4168c2ecf20Sopenharmony_ci					  req->offset, PAGE_SIZE);
4178c2ecf20Sopenharmony_ci		req->offset = 0;
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (req->page_done)
4218c2ecf20Sopenharmony_ci		for (req->index = 0; req->index < req->nr_pages; req->index++)
4228c2ecf20Sopenharmony_ci			req->page_done(req);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/*
4298c2ecf20Sopenharmony_ci * FS.FetchData operation type
4308c2ecf20Sopenharmony_ci */
4318c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSFetchData = {
4328c2ecf20Sopenharmony_ci	.name		= "FS.FetchData",
4338c2ecf20Sopenharmony_ci	.op		= afs_FS_FetchData,
4348c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_fetch_data,
4358c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
4368c2ecf20Sopenharmony_ci};
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSFetchData64 = {
4398c2ecf20Sopenharmony_ci	.name		= "FS.FetchData64",
4408c2ecf20Sopenharmony_ci	.op		= afs_FS_FetchData64,
4418c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_fetch_data,
4428c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
4438c2ecf20Sopenharmony_ci};
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci/*
4468c2ecf20Sopenharmony_ci * fetch data from a very large file
4478c2ecf20Sopenharmony_ci */
4488c2ecf20Sopenharmony_cistatic void afs_fs_fetch_data64(struct afs_operation *op)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
4518c2ecf20Sopenharmony_ci	struct afs_read *req = op->fetch.req;
4528c2ecf20Sopenharmony_ci	struct afs_call *call;
4538c2ecf20Sopenharmony_ci	__be32 *bp;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	_enter("");
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
4588c2ecf20Sopenharmony_ci	if (!call)
4598c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* marshall the parameters */
4628c2ecf20Sopenharmony_ci	bp = call->request;
4638c2ecf20Sopenharmony_ci	bp[0] = htonl(FSFETCHDATA64);
4648c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
4658c2ecf20Sopenharmony_ci	bp[2] = htonl(vp->fid.vnode);
4668c2ecf20Sopenharmony_ci	bp[3] = htonl(vp->fid.unique);
4678c2ecf20Sopenharmony_ci	bp[4] = htonl(upper_32_bits(req->pos));
4688c2ecf20Sopenharmony_ci	bp[5] = htonl(lower_32_bits(req->pos));
4698c2ecf20Sopenharmony_ci	bp[6] = 0;
4708c2ecf20Sopenharmony_ci	bp[7] = htonl(lower_32_bits(req->len));
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
4738c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci/*
4778c2ecf20Sopenharmony_ci * fetch data from a file
4788c2ecf20Sopenharmony_ci */
4798c2ecf20Sopenharmony_civoid afs_fs_fetch_data(struct afs_operation *op)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
4828c2ecf20Sopenharmony_ci	struct afs_call *call;
4838c2ecf20Sopenharmony_ci	struct afs_read *req = op->fetch.req;
4848c2ecf20Sopenharmony_ci	__be32 *bp;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (upper_32_bits(req->pos) ||
4878c2ecf20Sopenharmony_ci	    upper_32_bits(req->len) ||
4888c2ecf20Sopenharmony_ci	    upper_32_bits(req->pos + req->len))
4898c2ecf20Sopenharmony_ci		return afs_fs_fetch_data64(op);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	_enter("");
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
4948c2ecf20Sopenharmony_ci	if (!call)
4958c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* marshall the parameters */
4988c2ecf20Sopenharmony_ci	bp = call->request;
4998c2ecf20Sopenharmony_ci	bp[0] = htonl(FSFETCHDATA);
5008c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
5018c2ecf20Sopenharmony_ci	bp[2] = htonl(vp->fid.vnode);
5028c2ecf20Sopenharmony_ci	bp[3] = htonl(vp->fid.unique);
5038c2ecf20Sopenharmony_ci	bp[4] = htonl(lower_32_bits(req->pos));
5048c2ecf20Sopenharmony_ci	bp[5] = htonl(lower_32_bits(req->len));
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
5078c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/*
5118c2ecf20Sopenharmony_ci * deliver reply data to an FS.CreateFile or an FS.MakeDir
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_cistatic int afs_deliver_fs_create_vnode(struct afs_call *call)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
5168c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
5178c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[1];
5188c2ecf20Sopenharmony_ci	const __be32 *bp;
5198c2ecf20Sopenharmony_ci	int ret;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
5228c2ecf20Sopenharmony_ci	if (ret < 0)
5238c2ecf20Sopenharmony_ci		return ret;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
5268c2ecf20Sopenharmony_ci	bp = call->buffer;
5278c2ecf20Sopenharmony_ci	xdr_decode_AFSFid(&bp, &op->file[1].fid);
5288c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
5298c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
5308c2ecf20Sopenharmony_ci	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
5318c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
5348c2ecf20Sopenharmony_ci	return 0;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci/*
5388c2ecf20Sopenharmony_ci * FS.CreateFile and FS.MakeDir operation type
5398c2ecf20Sopenharmony_ci */
5408c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSCreateFile = {
5418c2ecf20Sopenharmony_ci	.name		= "FS.CreateFile",
5428c2ecf20Sopenharmony_ci	.op		= afs_FS_CreateFile,
5438c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_create_vnode,
5448c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
5458c2ecf20Sopenharmony_ci};
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/*
5488c2ecf20Sopenharmony_ci * Create a file.
5498c2ecf20Sopenharmony_ci */
5508c2ecf20Sopenharmony_civoid afs_fs_create_file(struct afs_operation *op)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
5538c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
5548c2ecf20Sopenharmony_ci	struct afs_call *call;
5558c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz;
5568c2ecf20Sopenharmony_ci	__be32 *bp;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	_enter("");
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	namesz = name->len;
5618c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
5628c2ecf20Sopenharmony_ci	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile,
5658c2ecf20Sopenharmony_ci				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
5668c2ecf20Sopenharmony_ci	if (!call)
5678c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* marshall the parameters */
5708c2ecf20Sopenharmony_ci	bp = call->request;
5718c2ecf20Sopenharmony_ci	*bp++ = htonl(FSCREATEFILE);
5728c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
5738c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
5748c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
5758c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
5768c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
5778c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
5788c2ecf20Sopenharmony_ci	if (padsz > 0) {
5798c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
5808c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
5838c2ecf20Sopenharmony_ci	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
5848c2ecf20Sopenharmony_ci	*bp++ = 0; /* owner */
5858c2ecf20Sopenharmony_ci	*bp++ = 0; /* group */
5868c2ecf20Sopenharmony_ci	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
5878c2ecf20Sopenharmony_ci	*bp++ = 0; /* segment size */
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &dvp->fid, name);
5908c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSMakeDir = {
5948c2ecf20Sopenharmony_ci	.name		= "FS.MakeDir",
5958c2ecf20Sopenharmony_ci	.op		= afs_FS_MakeDir,
5968c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_create_vnode,
5978c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
5988c2ecf20Sopenharmony_ci};
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci/*
6018c2ecf20Sopenharmony_ci * Create a new directory
6028c2ecf20Sopenharmony_ci */
6038c2ecf20Sopenharmony_civoid afs_fs_make_dir(struct afs_operation *op)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
6068c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
6078c2ecf20Sopenharmony_ci	struct afs_call *call;
6088c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz;
6098c2ecf20Sopenharmony_ci	__be32 *bp;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	_enter("");
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	namesz = name->len;
6148c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
6158c2ecf20Sopenharmony_ci	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir,
6188c2ecf20Sopenharmony_ci				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
6198c2ecf20Sopenharmony_ci	if (!call)
6208c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* marshall the parameters */
6238c2ecf20Sopenharmony_ci	bp = call->request;
6248c2ecf20Sopenharmony_ci	*bp++ = htonl(FSMAKEDIR);
6258c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
6268c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
6278c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
6288c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
6298c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
6308c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
6318c2ecf20Sopenharmony_ci	if (padsz > 0) {
6328c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
6338c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
6368c2ecf20Sopenharmony_ci	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
6378c2ecf20Sopenharmony_ci	*bp++ = 0; /* owner */
6388c2ecf20Sopenharmony_ci	*bp++ = 0; /* group */
6398c2ecf20Sopenharmony_ci	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
6408c2ecf20Sopenharmony_ci	*bp++ = 0; /* segment size */
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &dvp->fid, name);
6438c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/*
6478c2ecf20Sopenharmony_ci * Deliver reply data to any operation that returns status and volume sync.
6488c2ecf20Sopenharmony_ci */
6498c2ecf20Sopenharmony_cistatic int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
6528c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
6538c2ecf20Sopenharmony_ci	const __be32 *bp;
6548c2ecf20Sopenharmony_ci	int ret;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
6578c2ecf20Sopenharmony_ci	if (ret < 0)
6588c2ecf20Sopenharmony_ci		return ret;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
6618c2ecf20Sopenharmony_ci	bp = call->buffer;
6628c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
6638c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
6668c2ecf20Sopenharmony_ci	return 0;
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci/*
6708c2ecf20Sopenharmony_ci * FS.RemoveFile operation type
6718c2ecf20Sopenharmony_ci */
6728c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSRemoveFile = {
6738c2ecf20Sopenharmony_ci	.name		= "FS.RemoveFile",
6748c2ecf20Sopenharmony_ci	.op		= afs_FS_RemoveFile,
6758c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_file_status_and_vol,
6768c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
6778c2ecf20Sopenharmony_ci};
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci/*
6808c2ecf20Sopenharmony_ci * Remove a file.
6818c2ecf20Sopenharmony_ci */
6828c2ecf20Sopenharmony_civoid afs_fs_remove_file(struct afs_operation *op)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
6858c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
6868c2ecf20Sopenharmony_ci	struct afs_call *call;
6878c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz;
6888c2ecf20Sopenharmony_ci	__be32 *bp;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	_enter("");
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	namesz = name->len;
6938c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
6948c2ecf20Sopenharmony_ci	reqsz = (5 * 4) + namesz + padsz;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile,
6978c2ecf20Sopenharmony_ci				   reqsz, (21 + 6) * 4);
6988c2ecf20Sopenharmony_ci	if (!call)
6998c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	/* marshall the parameters */
7028c2ecf20Sopenharmony_ci	bp = call->request;
7038c2ecf20Sopenharmony_ci	*bp++ = htonl(FSREMOVEFILE);
7048c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
7058c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
7068c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
7078c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
7088c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
7098c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
7108c2ecf20Sopenharmony_ci	if (padsz > 0) {
7118c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
7128c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &dvp->fid, name);
7168c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSRemoveDir = {
7208c2ecf20Sopenharmony_ci	.name		= "FS.RemoveDir",
7218c2ecf20Sopenharmony_ci	.op		= afs_FS_RemoveDir,
7228c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_file_status_and_vol,
7238c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
7248c2ecf20Sopenharmony_ci};
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci/*
7278c2ecf20Sopenharmony_ci * Remove a directory.
7288c2ecf20Sopenharmony_ci */
7298c2ecf20Sopenharmony_civoid afs_fs_remove_dir(struct afs_operation *op)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
7328c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
7338c2ecf20Sopenharmony_ci	struct afs_call *call;
7348c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz;
7358c2ecf20Sopenharmony_ci	__be32 *bp;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	_enter("");
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	namesz = name->len;
7408c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
7418c2ecf20Sopenharmony_ci	reqsz = (5 * 4) + namesz + padsz;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir,
7448c2ecf20Sopenharmony_ci				   reqsz, (21 + 6) * 4);
7458c2ecf20Sopenharmony_ci	if (!call)
7468c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* marshall the parameters */
7498c2ecf20Sopenharmony_ci	bp = call->request;
7508c2ecf20Sopenharmony_ci	*bp++ = htonl(FSREMOVEDIR);
7518c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
7528c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
7538c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
7548c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
7558c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
7568c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
7578c2ecf20Sopenharmony_ci	if (padsz > 0) {
7588c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
7598c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &dvp->fid, name);
7638c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/*
7678c2ecf20Sopenharmony_ci * deliver reply data to an FS.Link
7688c2ecf20Sopenharmony_ci */
7698c2ecf20Sopenharmony_cistatic int afs_deliver_fs_link(struct afs_call *call)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
7728c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
7738c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[1];
7748c2ecf20Sopenharmony_ci	const __be32 *bp;
7758c2ecf20Sopenharmony_ci	int ret;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
7808c2ecf20Sopenharmony_ci	if (ret < 0)
7818c2ecf20Sopenharmony_ci		return ret;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
7848c2ecf20Sopenharmony_ci	bp = call->buffer;
7858c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
7868c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
7878c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
7908c2ecf20Sopenharmony_ci	return 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/*
7948c2ecf20Sopenharmony_ci * FS.Link operation type
7958c2ecf20Sopenharmony_ci */
7968c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSLink = {
7978c2ecf20Sopenharmony_ci	.name		= "FS.Link",
7988c2ecf20Sopenharmony_ci	.op		= afs_FS_Link,
7998c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_link,
8008c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
8018c2ecf20Sopenharmony_ci};
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci/*
8048c2ecf20Sopenharmony_ci * make a hard link
8058c2ecf20Sopenharmony_ci */
8068c2ecf20Sopenharmony_civoid afs_fs_link(struct afs_operation *op)
8078c2ecf20Sopenharmony_ci{
8088c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
8098c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
8108c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[1];
8118c2ecf20Sopenharmony_ci	struct afs_call *call;
8128c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz;
8138c2ecf20Sopenharmony_ci	__be32 *bp;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	_enter("");
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	namesz = name->len;
8188c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
8198c2ecf20Sopenharmony_ci	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
8228c2ecf20Sopenharmony_ci	if (!call)
8238c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	/* marshall the parameters */
8268c2ecf20Sopenharmony_ci	bp = call->request;
8278c2ecf20Sopenharmony_ci	*bp++ = htonl(FSLINK);
8288c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
8298c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
8308c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
8318c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
8328c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
8338c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
8348c2ecf20Sopenharmony_ci	if (padsz > 0) {
8358c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
8368c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
8398c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
8408c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &vp->fid, name);
8438c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci/*
8478c2ecf20Sopenharmony_ci * deliver reply data to an FS.Symlink
8488c2ecf20Sopenharmony_ci */
8498c2ecf20Sopenharmony_cistatic int afs_deliver_fs_symlink(struct afs_call *call)
8508c2ecf20Sopenharmony_ci{
8518c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
8528c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
8538c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[1];
8548c2ecf20Sopenharmony_ci	const __be32 *bp;
8558c2ecf20Sopenharmony_ci	int ret;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
8608c2ecf20Sopenharmony_ci	if (ret < 0)
8618c2ecf20Sopenharmony_ci		return ret;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
8648c2ecf20Sopenharmony_ci	bp = call->buffer;
8658c2ecf20Sopenharmony_ci	xdr_decode_AFSFid(&bp, &vp->fid);
8668c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
8678c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
8688c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
8718c2ecf20Sopenharmony_ci	return 0;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/*
8758c2ecf20Sopenharmony_ci * FS.Symlink operation type
8768c2ecf20Sopenharmony_ci */
8778c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSSymlink = {
8788c2ecf20Sopenharmony_ci	.name		= "FS.Symlink",
8798c2ecf20Sopenharmony_ci	.op		= afs_FS_Symlink,
8808c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_symlink,
8818c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
8828c2ecf20Sopenharmony_ci};
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci/*
8858c2ecf20Sopenharmony_ci * create a symbolic link
8868c2ecf20Sopenharmony_ci */
8878c2ecf20Sopenharmony_civoid afs_fs_symlink(struct afs_operation *op)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	const struct qstr *name = &op->dentry->d_name;
8908c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
8918c2ecf20Sopenharmony_ci	struct afs_call *call;
8928c2ecf20Sopenharmony_ci	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
8938c2ecf20Sopenharmony_ci	__be32 *bp;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	_enter("");
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	namesz = name->len;
8988c2ecf20Sopenharmony_ci	padsz = (4 - (namesz & 3)) & 3;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	c_namesz = strlen(op->create.symlink);
9018c2ecf20Sopenharmony_ci	c_padsz = (4 - (c_namesz & 3)) & 3;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz,
9068c2ecf20Sopenharmony_ci				   (3 + 21 + 21 + 6) * 4);
9078c2ecf20Sopenharmony_ci	if (!call)
9088c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	/* marshall the parameters */
9118c2ecf20Sopenharmony_ci	bp = call->request;
9128c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSYMLINK);
9138c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
9148c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
9158c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
9168c2ecf20Sopenharmony_ci	*bp++ = htonl(namesz);
9178c2ecf20Sopenharmony_ci	memcpy(bp, name->name, namesz);
9188c2ecf20Sopenharmony_ci	bp = (void *) bp + namesz;
9198c2ecf20Sopenharmony_ci	if (padsz > 0) {
9208c2ecf20Sopenharmony_ci		memset(bp, 0, padsz);
9218c2ecf20Sopenharmony_ci		bp = (void *) bp + padsz;
9228c2ecf20Sopenharmony_ci	}
9238c2ecf20Sopenharmony_ci	*bp++ = htonl(c_namesz);
9248c2ecf20Sopenharmony_ci	memcpy(bp, op->create.symlink, c_namesz);
9258c2ecf20Sopenharmony_ci	bp = (void *) bp + c_namesz;
9268c2ecf20Sopenharmony_ci	if (c_padsz > 0) {
9278c2ecf20Sopenharmony_ci		memset(bp, 0, c_padsz);
9288c2ecf20Sopenharmony_ci		bp = (void *) bp + c_padsz;
9298c2ecf20Sopenharmony_ci	}
9308c2ecf20Sopenharmony_ci	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
9318c2ecf20Sopenharmony_ci	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
9328c2ecf20Sopenharmony_ci	*bp++ = 0; /* owner */
9338c2ecf20Sopenharmony_ci	*bp++ = 0; /* group */
9348c2ecf20Sopenharmony_ci	*bp++ = htonl(S_IRWXUGO); /* unix mode */
9358c2ecf20Sopenharmony_ci	*bp++ = 0; /* segment size */
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	trace_afs_make_fs_call1(call, &dvp->fid, name);
9388c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci/*
9428c2ecf20Sopenharmony_ci * deliver reply data to an FS.Rename
9438c2ecf20Sopenharmony_ci */
9448c2ecf20Sopenharmony_cistatic int afs_deliver_fs_rename(struct afs_call *call)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
9478c2ecf20Sopenharmony_ci	struct afs_vnode_param *orig_dvp = &op->file[0];
9488c2ecf20Sopenharmony_ci	struct afs_vnode_param *new_dvp = &op->file[1];
9498c2ecf20Sopenharmony_ci	const __be32 *bp;
9508c2ecf20Sopenharmony_ci	int ret;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
9538c2ecf20Sopenharmony_ci	if (ret < 0)
9548c2ecf20Sopenharmony_ci		return ret;
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	bp = call->buffer;
9578c2ecf20Sopenharmony_ci	/* If the two dirs are the same, we have two copies of the same status
9588c2ecf20Sopenharmony_ci	 * report, so we just decode it twice.
9598c2ecf20Sopenharmony_ci	 */
9608c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb);
9618c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb);
9628c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
9658c2ecf20Sopenharmony_ci	return 0;
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci/*
9698c2ecf20Sopenharmony_ci * FS.Rename operation type
9708c2ecf20Sopenharmony_ci */
9718c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSRename = {
9728c2ecf20Sopenharmony_ci	.name		= "FS.Rename",
9738c2ecf20Sopenharmony_ci	.op		= afs_FS_Rename,
9748c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_rename,
9758c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
9768c2ecf20Sopenharmony_ci};
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/*
9798c2ecf20Sopenharmony_ci * Rename/move a file or directory.
9808c2ecf20Sopenharmony_ci */
9818c2ecf20Sopenharmony_civoid afs_fs_rename(struct afs_operation *op)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	struct afs_vnode_param *orig_dvp = &op->file[0];
9848c2ecf20Sopenharmony_ci	struct afs_vnode_param *new_dvp = &op->file[1];
9858c2ecf20Sopenharmony_ci	const struct qstr *orig_name = &op->dentry->d_name;
9868c2ecf20Sopenharmony_ci	const struct qstr *new_name = &op->dentry_2->d_name;
9878c2ecf20Sopenharmony_ci	struct afs_call *call;
9888c2ecf20Sopenharmony_ci	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
9898c2ecf20Sopenharmony_ci	__be32 *bp;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	_enter("");
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	o_namesz = orig_name->len;
9948c2ecf20Sopenharmony_ci	o_padsz = (4 - (o_namesz & 3)) & 3;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	n_namesz = new_name->len;
9978c2ecf20Sopenharmony_ci	n_padsz = (4 - (n_namesz & 3)) & 3;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	reqsz = (4 * 4) +
10008c2ecf20Sopenharmony_ci		4 + o_namesz + o_padsz +
10018c2ecf20Sopenharmony_ci		(3 * 4) +
10028c2ecf20Sopenharmony_ci		4 + n_namesz + n_padsz;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
10058c2ecf20Sopenharmony_ci	if (!call)
10068c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* marshall the parameters */
10098c2ecf20Sopenharmony_ci	bp = call->request;
10108c2ecf20Sopenharmony_ci	*bp++ = htonl(FSRENAME);
10118c2ecf20Sopenharmony_ci	*bp++ = htonl(orig_dvp->fid.vid);
10128c2ecf20Sopenharmony_ci	*bp++ = htonl(orig_dvp->fid.vnode);
10138c2ecf20Sopenharmony_ci	*bp++ = htonl(orig_dvp->fid.unique);
10148c2ecf20Sopenharmony_ci	*bp++ = htonl(o_namesz);
10158c2ecf20Sopenharmony_ci	memcpy(bp, orig_name->name, o_namesz);
10168c2ecf20Sopenharmony_ci	bp = (void *) bp + o_namesz;
10178c2ecf20Sopenharmony_ci	if (o_padsz > 0) {
10188c2ecf20Sopenharmony_ci		memset(bp, 0, o_padsz);
10198c2ecf20Sopenharmony_ci		bp = (void *) bp + o_padsz;
10208c2ecf20Sopenharmony_ci	}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	*bp++ = htonl(new_dvp->fid.vid);
10238c2ecf20Sopenharmony_ci	*bp++ = htonl(new_dvp->fid.vnode);
10248c2ecf20Sopenharmony_ci	*bp++ = htonl(new_dvp->fid.unique);
10258c2ecf20Sopenharmony_ci	*bp++ = htonl(n_namesz);
10268c2ecf20Sopenharmony_ci	memcpy(bp, new_name->name, n_namesz);
10278c2ecf20Sopenharmony_ci	bp = (void *) bp + n_namesz;
10288c2ecf20Sopenharmony_ci	if (n_padsz > 0) {
10298c2ecf20Sopenharmony_ci		memset(bp, 0, n_padsz);
10308c2ecf20Sopenharmony_ci		bp = (void *) bp + n_padsz;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
10348c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci/*
10388c2ecf20Sopenharmony_ci * Deliver reply data to FS.StoreData or FS.StoreStatus
10398c2ecf20Sopenharmony_ci */
10408c2ecf20Sopenharmony_cistatic int afs_deliver_fs_store_data(struct afs_call *call)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
10438c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
10448c2ecf20Sopenharmony_ci	const __be32 *bp;
10458c2ecf20Sopenharmony_ci	int ret;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	_enter("");
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
10508c2ecf20Sopenharmony_ci	if (ret < 0)
10518c2ecf20Sopenharmony_ci		return ret;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
10548c2ecf20Sopenharmony_ci	bp = call->buffer;
10558c2ecf20Sopenharmony_ci	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
10568c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci/*
10638c2ecf20Sopenharmony_ci * FS.StoreData operation type
10648c2ecf20Sopenharmony_ci */
10658c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreData = {
10668c2ecf20Sopenharmony_ci	.name		= "FS.StoreData",
10678c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreData,
10688c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_store_data,
10698c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
10708c2ecf20Sopenharmony_ci};
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreData64 = {
10738c2ecf20Sopenharmony_ci	.name		= "FS.StoreData64",
10748c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreData64,
10758c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_store_data,
10768c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
10778c2ecf20Sopenharmony_ci};
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci/*
10808c2ecf20Sopenharmony_ci * store a set of pages to a very large file
10818c2ecf20Sopenharmony_ci */
10828c2ecf20Sopenharmony_cistatic void afs_fs_store_data64(struct afs_operation *op,
10838c2ecf20Sopenharmony_ci				loff_t pos, loff_t size, loff_t i_size)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
10868c2ecf20Sopenharmony_ci	struct afs_call *call;
10878c2ecf20Sopenharmony_ci	__be32 *bp;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
10908c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64,
10938c2ecf20Sopenharmony_ci				   (4 + 6 + 3 * 2) * 4,
10948c2ecf20Sopenharmony_ci				   (21 + 6) * 4);
10958c2ecf20Sopenharmony_ci	if (!call)
10968c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	call->send_pages = true;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	/* marshall the parameters */
11018c2ecf20Sopenharmony_ci	bp = call->request;
11028c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSTOREDATA64);
11038c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
11048c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
11058c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	*bp++ = htonl(AFS_SET_MTIME); /* mask */
11088c2ecf20Sopenharmony_ci	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
11098c2ecf20Sopenharmony_ci	*bp++ = 0; /* owner */
11108c2ecf20Sopenharmony_ci	*bp++ = 0; /* group */
11118c2ecf20Sopenharmony_ci	*bp++ = 0; /* unix mode */
11128c2ecf20Sopenharmony_ci	*bp++ = 0; /* segment size */
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	*bp++ = htonl(upper_32_bits(pos));
11158c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(pos));
11168c2ecf20Sopenharmony_ci	*bp++ = htonl(upper_32_bits(size));
11178c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(size));
11188c2ecf20Sopenharmony_ci	*bp++ = htonl(upper_32_bits(i_size));
11198c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(i_size));
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
11228c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci/*
11268c2ecf20Sopenharmony_ci * store a set of pages
11278c2ecf20Sopenharmony_ci */
11288c2ecf20Sopenharmony_civoid afs_fs_store_data(struct afs_operation *op)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
11318c2ecf20Sopenharmony_ci	struct afs_call *call;
11328c2ecf20Sopenharmony_ci	loff_t size, pos, i_size;
11338c2ecf20Sopenharmony_ci	__be32 *bp;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
11368c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset;
11398c2ecf20Sopenharmony_ci	if (op->store.first != op->store.last)
11408c2ecf20Sopenharmony_ci		size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT;
11418c2ecf20Sopenharmony_ci	pos = (loff_t)op->store.first << PAGE_SHIFT;
11428c2ecf20Sopenharmony_ci	pos += op->store.first_offset;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	i_size = i_size_read(&vp->vnode->vfs_inode);
11458c2ecf20Sopenharmony_ci	if (pos + size > i_size)
11468c2ecf20Sopenharmony_ci		i_size = size + pos;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	_debug("size %llx, at %llx, i_size %llx",
11498c2ecf20Sopenharmony_ci	       (unsigned long long) size, (unsigned long long) pos,
11508c2ecf20Sopenharmony_ci	       (unsigned long long) i_size);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (upper_32_bits(pos) || upper_32_bits(i_size) || upper_32_bits(size) ||
11538c2ecf20Sopenharmony_ci	    upper_32_bits(pos + size))
11548c2ecf20Sopenharmony_ci		return afs_fs_store_data64(op, pos, size, i_size);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData,
11578c2ecf20Sopenharmony_ci				   (4 + 6 + 3) * 4,
11588c2ecf20Sopenharmony_ci				   (21 + 6) * 4);
11598c2ecf20Sopenharmony_ci	if (!call)
11608c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	call->send_pages = true;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	/* marshall the parameters */
11658c2ecf20Sopenharmony_ci	bp = call->request;
11668c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSTOREDATA);
11678c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
11688c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
11698c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	*bp++ = htonl(AFS_SET_MTIME); /* mask */
11728c2ecf20Sopenharmony_ci	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
11738c2ecf20Sopenharmony_ci	*bp++ = 0; /* owner */
11748c2ecf20Sopenharmony_ci	*bp++ = 0; /* group */
11758c2ecf20Sopenharmony_ci	*bp++ = 0; /* unix mode */
11768c2ecf20Sopenharmony_ci	*bp++ = 0; /* segment size */
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(pos));
11798c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(size));
11808c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(i_size));
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
11838c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci/*
11878c2ecf20Sopenharmony_ci * FS.StoreStatus operation type
11888c2ecf20Sopenharmony_ci */
11898c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreStatus = {
11908c2ecf20Sopenharmony_ci	.name		= "FS.StoreStatus",
11918c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreStatus,
11928c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_store_data,
11938c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
11948c2ecf20Sopenharmony_ci};
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreData_as_Status = {
11978c2ecf20Sopenharmony_ci	.name		= "FS.StoreData",
11988c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreData,
11998c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_store_data,
12008c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
12018c2ecf20Sopenharmony_ci};
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreData64_as_Status = {
12048c2ecf20Sopenharmony_ci	.name		= "FS.StoreData64",
12058c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreData64,
12068c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_store_data,
12078c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
12088c2ecf20Sopenharmony_ci};
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci/*
12118c2ecf20Sopenharmony_ci * set the attributes on a very large file, using FS.StoreData rather than
12128c2ecf20Sopenharmony_ci * FS.StoreStatus so as to alter the file size also
12138c2ecf20Sopenharmony_ci */
12148c2ecf20Sopenharmony_cistatic void afs_fs_setattr_size64(struct afs_operation *op)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
12178c2ecf20Sopenharmony_ci	struct afs_call *call;
12188c2ecf20Sopenharmony_ci	struct iattr *attr = op->setattr.attr;
12198c2ecf20Sopenharmony_ci	__be32 *bp;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
12228c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	ASSERT(attr->ia_valid & ATTR_SIZE);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status,
12278c2ecf20Sopenharmony_ci				   (4 + 6 + 3 * 2) * 4,
12288c2ecf20Sopenharmony_ci				   (21 + 6) * 4);
12298c2ecf20Sopenharmony_ci	if (!call)
12308c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	/* marshall the parameters */
12338c2ecf20Sopenharmony_ci	bp = call->request;
12348c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSTOREDATA64);
12358c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
12368c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
12378c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	xdr_encode_AFS_StoreStatus(&bp, attr);
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* position of start of write */
12428c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(attr->ia_size));
12438c2ecf20Sopenharmony_ci	*bp++ = 0;					/* size of write */
12448c2ecf20Sopenharmony_ci	*bp++ = 0;
12458c2ecf20Sopenharmony_ci	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* new file length */
12468c2ecf20Sopenharmony_ci	*bp++ = htonl(lower_32_bits(attr->ia_size));
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
12498c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
12508c2ecf20Sopenharmony_ci}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci/*
12538c2ecf20Sopenharmony_ci * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
12548c2ecf20Sopenharmony_ci * so as to alter the file size also
12558c2ecf20Sopenharmony_ci */
12568c2ecf20Sopenharmony_cistatic void afs_fs_setattr_size(struct afs_operation *op)
12578c2ecf20Sopenharmony_ci{
12588c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
12598c2ecf20Sopenharmony_ci	struct afs_call *call;
12608c2ecf20Sopenharmony_ci	struct iattr *attr = op->setattr.attr;
12618c2ecf20Sopenharmony_ci	__be32 *bp;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
12648c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	ASSERT(attr->ia_valid & ATTR_SIZE);
12678c2ecf20Sopenharmony_ci	if (upper_32_bits(attr->ia_size))
12688c2ecf20Sopenharmony_ci		return afs_fs_setattr_size64(op);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status,
12718c2ecf20Sopenharmony_ci				   (4 + 6 + 3) * 4,
12728c2ecf20Sopenharmony_ci				   (21 + 6) * 4);
12738c2ecf20Sopenharmony_ci	if (!call)
12748c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	/* marshall the parameters */
12778c2ecf20Sopenharmony_ci	bp = call->request;
12788c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSTOREDATA);
12798c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
12808c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
12818c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	xdr_encode_AFS_StoreStatus(&bp, attr);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	*bp++ = htonl(attr->ia_size);		/* position of start of write */
12868c2ecf20Sopenharmony_ci	*bp++ = 0;				/* size of write */
12878c2ecf20Sopenharmony_ci	*bp++ = htonl(attr->ia_size);		/* new file length */
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
12908c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci/*
12948c2ecf20Sopenharmony_ci * set the attributes on a file, using FS.StoreData if there's a change in file
12958c2ecf20Sopenharmony_ci * size, and FS.StoreStatus otherwise
12968c2ecf20Sopenharmony_ci */
12978c2ecf20Sopenharmony_civoid afs_fs_setattr(struct afs_operation *op)
12988c2ecf20Sopenharmony_ci{
12998c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
13008c2ecf20Sopenharmony_ci	struct afs_call *call;
13018c2ecf20Sopenharmony_ci	struct iattr *attr = op->setattr.attr;
13028c2ecf20Sopenharmony_ci	__be32 *bp;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (attr->ia_valid & ATTR_SIZE)
13058c2ecf20Sopenharmony_ci		return afs_fs_setattr_size(op);
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
13088c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus,
13118c2ecf20Sopenharmony_ci				   (4 + 6) * 4,
13128c2ecf20Sopenharmony_ci				   (21 + 6) * 4);
13138c2ecf20Sopenharmony_ci	if (!call)
13148c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	/* marshall the parameters */
13178c2ecf20Sopenharmony_ci	bp = call->request;
13188c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSTORESTATUS);
13198c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
13208c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
13218c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
13268c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
13278c2ecf20Sopenharmony_ci}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci/*
13308c2ecf20Sopenharmony_ci * deliver reply data to an FS.GetVolumeStatus
13318c2ecf20Sopenharmony_ci */
13328c2ecf20Sopenharmony_cistatic int afs_deliver_fs_get_volume_status(struct afs_call *call)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
13358c2ecf20Sopenharmony_ci	const __be32 *bp;
13368c2ecf20Sopenharmony_ci	char *p;
13378c2ecf20Sopenharmony_ci	u32 size;
13388c2ecf20Sopenharmony_ci	int ret;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
13438c2ecf20Sopenharmony_ci	case 0:
13448c2ecf20Sopenharmony_ci		call->unmarshall++;
13458c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, 12 * 4);
13468c2ecf20Sopenharmony_ci		fallthrough;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		/* extract the returned status record */
13498c2ecf20Sopenharmony_ci	case 1:
13508c2ecf20Sopenharmony_ci		_debug("extract status");
13518c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
13528c2ecf20Sopenharmony_ci		if (ret < 0)
13538c2ecf20Sopenharmony_ci			return ret;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci		bp = call->buffer;
13568c2ecf20Sopenharmony_ci		xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs);
13578c2ecf20Sopenharmony_ci		call->unmarshall++;
13588c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
13598c2ecf20Sopenharmony_ci		fallthrough;
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci		/* extract the volume name length */
13628c2ecf20Sopenharmony_ci	case 2:
13638c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
13648c2ecf20Sopenharmony_ci		if (ret < 0)
13658c2ecf20Sopenharmony_ci			return ret;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci		call->count = ntohl(call->tmp);
13688c2ecf20Sopenharmony_ci		_debug("volname length: %u", call->count);
13698c2ecf20Sopenharmony_ci		if (call->count >= AFSNAMEMAX)
13708c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_volname_len);
13718c2ecf20Sopenharmony_ci		size = (call->count + 3) & ~3; /* It's padded */
13728c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, size);
13738c2ecf20Sopenharmony_ci		call->unmarshall++;
13748c2ecf20Sopenharmony_ci		fallthrough;
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci		/* extract the volume name */
13778c2ecf20Sopenharmony_ci	case 3:
13788c2ecf20Sopenharmony_ci		_debug("extract volname");
13798c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
13808c2ecf20Sopenharmony_ci		if (ret < 0)
13818c2ecf20Sopenharmony_ci			return ret;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		p = call->buffer;
13848c2ecf20Sopenharmony_ci		p[call->count] = 0;
13858c2ecf20Sopenharmony_ci		_debug("volname '%s'", p);
13868c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
13878c2ecf20Sopenharmony_ci		call->unmarshall++;
13888c2ecf20Sopenharmony_ci		fallthrough;
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci		/* extract the offline message length */
13918c2ecf20Sopenharmony_ci	case 4:
13928c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
13938c2ecf20Sopenharmony_ci		if (ret < 0)
13948c2ecf20Sopenharmony_ci			return ret;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci		call->count = ntohl(call->tmp);
13978c2ecf20Sopenharmony_ci		_debug("offline msg length: %u", call->count);
13988c2ecf20Sopenharmony_ci		if (call->count >= AFSNAMEMAX)
13998c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_offline_msg_len);
14008c2ecf20Sopenharmony_ci		size = (call->count + 3) & ~3; /* It's padded */
14018c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, size);
14028c2ecf20Sopenharmony_ci		call->unmarshall++;
14038c2ecf20Sopenharmony_ci		fallthrough;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci		/* extract the offline message */
14068c2ecf20Sopenharmony_ci	case 5:
14078c2ecf20Sopenharmony_ci		_debug("extract offline");
14088c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
14098c2ecf20Sopenharmony_ci		if (ret < 0)
14108c2ecf20Sopenharmony_ci			return ret;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci		p = call->buffer;
14138c2ecf20Sopenharmony_ci		p[call->count] = 0;
14148c2ecf20Sopenharmony_ci		_debug("offline '%s'", p);
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
14178c2ecf20Sopenharmony_ci		call->unmarshall++;
14188c2ecf20Sopenharmony_ci		fallthrough;
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci		/* extract the message of the day length */
14218c2ecf20Sopenharmony_ci	case 6:
14228c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
14238c2ecf20Sopenharmony_ci		if (ret < 0)
14248c2ecf20Sopenharmony_ci			return ret;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		call->count = ntohl(call->tmp);
14278c2ecf20Sopenharmony_ci		_debug("motd length: %u", call->count);
14288c2ecf20Sopenharmony_ci		if (call->count >= AFSNAMEMAX)
14298c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_motd_len);
14308c2ecf20Sopenharmony_ci		size = (call->count + 3) & ~3; /* It's padded */
14318c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, size);
14328c2ecf20Sopenharmony_ci		call->unmarshall++;
14338c2ecf20Sopenharmony_ci		fallthrough;
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci		/* extract the message of the day */
14368c2ecf20Sopenharmony_ci	case 7:
14378c2ecf20Sopenharmony_ci		_debug("extract motd");
14388c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
14398c2ecf20Sopenharmony_ci		if (ret < 0)
14408c2ecf20Sopenharmony_ci			return ret;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		p = call->buffer;
14438c2ecf20Sopenharmony_ci		p[call->count] = 0;
14448c2ecf20Sopenharmony_ci		_debug("motd '%s'", p);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci		call->unmarshall++;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	case 8:
14498c2ecf20Sopenharmony_ci		break;
14508c2ecf20Sopenharmony_ci	}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
14538c2ecf20Sopenharmony_ci	return 0;
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci/*
14578c2ecf20Sopenharmony_ci * FS.GetVolumeStatus operation type
14588c2ecf20Sopenharmony_ci */
14598c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSGetVolumeStatus = {
14608c2ecf20Sopenharmony_ci	.name		= "FS.GetVolumeStatus",
14618c2ecf20Sopenharmony_ci	.op		= afs_FS_GetVolumeStatus,
14628c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_get_volume_status,
14638c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
14648c2ecf20Sopenharmony_ci};
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci/*
14678c2ecf20Sopenharmony_ci * fetch the status of a volume
14688c2ecf20Sopenharmony_ci */
14698c2ecf20Sopenharmony_civoid afs_fs_get_volume_status(struct afs_operation *op)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
14728c2ecf20Sopenharmony_ci	struct afs_call *call;
14738c2ecf20Sopenharmony_ci	__be32 *bp;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	_enter("");
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4,
14788c2ecf20Sopenharmony_ci				   max(12 * 4, AFSOPAQUEMAX + 1));
14798c2ecf20Sopenharmony_ci	if (!call)
14808c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	/* marshall the parameters */
14838c2ecf20Sopenharmony_ci	bp = call->request;
14848c2ecf20Sopenharmony_ci	bp[0] = htonl(FSGETVOLUMESTATUS);
14858c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
14888c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci/*
14928c2ecf20Sopenharmony_ci * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
14938c2ecf20Sopenharmony_ci */
14948c2ecf20Sopenharmony_cistatic int afs_deliver_fs_xxxx_lock(struct afs_call *call)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
14978c2ecf20Sopenharmony_ci	const __be32 *bp;
14988c2ecf20Sopenharmony_ci	int ret;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	ret = afs_transfer_reply(call);
15038c2ecf20Sopenharmony_ci	if (ret < 0)
15048c2ecf20Sopenharmony_ci		return ret;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	/* unmarshall the reply once we've received all of it */
15078c2ecf20Sopenharmony_ci	bp = call->buffer;
15088c2ecf20Sopenharmony_ci	xdr_decode_AFSVolSync(&bp, &op->volsync);
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
15118c2ecf20Sopenharmony_ci	return 0;
15128c2ecf20Sopenharmony_ci}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci/*
15158c2ecf20Sopenharmony_ci * FS.SetLock operation type
15168c2ecf20Sopenharmony_ci */
15178c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSSetLock = {
15188c2ecf20Sopenharmony_ci	.name		= "FS.SetLock",
15198c2ecf20Sopenharmony_ci	.op		= afs_FS_SetLock,
15208c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_xxxx_lock,
15218c2ecf20Sopenharmony_ci	.done		= afs_lock_op_done,
15228c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
15238c2ecf20Sopenharmony_ci};
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_ci/*
15268c2ecf20Sopenharmony_ci * FS.ExtendLock operation type
15278c2ecf20Sopenharmony_ci */
15288c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSExtendLock = {
15298c2ecf20Sopenharmony_ci	.name		= "FS.ExtendLock",
15308c2ecf20Sopenharmony_ci	.op		= afs_FS_ExtendLock,
15318c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_xxxx_lock,
15328c2ecf20Sopenharmony_ci	.done		= afs_lock_op_done,
15338c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
15348c2ecf20Sopenharmony_ci};
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci/*
15378c2ecf20Sopenharmony_ci * FS.ReleaseLock operation type
15388c2ecf20Sopenharmony_ci */
15398c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSReleaseLock = {
15408c2ecf20Sopenharmony_ci	.name		= "FS.ReleaseLock",
15418c2ecf20Sopenharmony_ci	.op		= afs_FS_ReleaseLock,
15428c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_xxxx_lock,
15438c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
15448c2ecf20Sopenharmony_ci};
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci/*
15478c2ecf20Sopenharmony_ci * Set a lock on a file
15488c2ecf20Sopenharmony_ci */
15498c2ecf20Sopenharmony_civoid afs_fs_set_lock(struct afs_operation *op)
15508c2ecf20Sopenharmony_ci{
15518c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
15528c2ecf20Sopenharmony_ci	struct afs_call *call;
15538c2ecf20Sopenharmony_ci	__be32 *bp;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	_enter("");
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
15588c2ecf20Sopenharmony_ci	if (!call)
15598c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	/* marshall the parameters */
15628c2ecf20Sopenharmony_ci	bp = call->request;
15638c2ecf20Sopenharmony_ci	*bp++ = htonl(FSSETLOCK);
15648c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
15658c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
15668c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
15678c2ecf20Sopenharmony_ci	*bp++ = htonl(op->lock.type);
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
15708c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
15718c2ecf20Sopenharmony_ci}
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci/*
15748c2ecf20Sopenharmony_ci * extend a lock on a file
15758c2ecf20Sopenharmony_ci */
15768c2ecf20Sopenharmony_civoid afs_fs_extend_lock(struct afs_operation *op)
15778c2ecf20Sopenharmony_ci{
15788c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
15798c2ecf20Sopenharmony_ci	struct afs_call *call;
15808c2ecf20Sopenharmony_ci	__be32 *bp;
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	_enter("");
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
15858c2ecf20Sopenharmony_ci	if (!call)
15868c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci	/* marshall the parameters */
15898c2ecf20Sopenharmony_ci	bp = call->request;
15908c2ecf20Sopenharmony_ci	*bp++ = htonl(FSEXTENDLOCK);
15918c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
15928c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
15938c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
15968c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci/*
16008c2ecf20Sopenharmony_ci * release a lock on a file
16018c2ecf20Sopenharmony_ci */
16028c2ecf20Sopenharmony_civoid afs_fs_release_lock(struct afs_operation *op)
16038c2ecf20Sopenharmony_ci{
16048c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
16058c2ecf20Sopenharmony_ci	struct afs_call *call;
16068c2ecf20Sopenharmony_ci	__be32 *bp;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	_enter("");
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
16118c2ecf20Sopenharmony_ci	if (!call)
16128c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	/* marshall the parameters */
16158c2ecf20Sopenharmony_ci	bp = call->request;
16168c2ecf20Sopenharmony_ci	*bp++ = htonl(FSRELEASELOCK);
16178c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
16188c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
16198c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
16228c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
16238c2ecf20Sopenharmony_ci}
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci/*
16268c2ecf20Sopenharmony_ci * Deliver reply data to an FS.GiveUpAllCallBacks operation.
16278c2ecf20Sopenharmony_ci */
16288c2ecf20Sopenharmony_cistatic int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
16298c2ecf20Sopenharmony_ci{
16308c2ecf20Sopenharmony_ci	return afs_transfer_reply(call);
16318c2ecf20Sopenharmony_ci}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci/*
16348c2ecf20Sopenharmony_ci * FS.GiveUpAllCallBacks operation type
16358c2ecf20Sopenharmony_ci */
16368c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
16378c2ecf20Sopenharmony_ci	.name		= "FS.GiveUpAllCallBacks",
16388c2ecf20Sopenharmony_ci	.op		= afs_FS_GiveUpAllCallBacks,
16398c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_give_up_all_callbacks,
16408c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
16418c2ecf20Sopenharmony_ci};
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci/*
16448c2ecf20Sopenharmony_ci * Flush all the callbacks we have on a server.
16458c2ecf20Sopenharmony_ci */
16468c2ecf20Sopenharmony_ciint afs_fs_give_up_all_callbacks(struct afs_net *net,
16478c2ecf20Sopenharmony_ci				 struct afs_server *server,
16488c2ecf20Sopenharmony_ci				 struct afs_addr_cursor *ac,
16498c2ecf20Sopenharmony_ci				 struct key *key)
16508c2ecf20Sopenharmony_ci{
16518c2ecf20Sopenharmony_ci	struct afs_call *call;
16528c2ecf20Sopenharmony_ci	__be32 *bp;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	_enter("");
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
16578c2ecf20Sopenharmony_ci	if (!call)
16588c2ecf20Sopenharmony_ci		return -ENOMEM;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	call->key = key;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	/* marshall the parameters */
16638c2ecf20Sopenharmony_ci	bp = call->request;
16648c2ecf20Sopenharmony_ci	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	call->server = afs_use_server(server, afs_server_trace_give_up_cb);
16678c2ecf20Sopenharmony_ci	afs_make_call(ac, call, GFP_NOFS);
16688c2ecf20Sopenharmony_ci	return afs_wait_for_call_to_complete(call, ac);
16698c2ecf20Sopenharmony_ci}
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci/*
16728c2ecf20Sopenharmony_ci * Deliver reply data to an FS.GetCapabilities operation.
16738c2ecf20Sopenharmony_ci */
16748c2ecf20Sopenharmony_cistatic int afs_deliver_fs_get_capabilities(struct afs_call *call)
16758c2ecf20Sopenharmony_ci{
16768c2ecf20Sopenharmony_ci	u32 count;
16778c2ecf20Sopenharmony_ci	int ret;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
16828c2ecf20Sopenharmony_ci	case 0:
16838c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
16848c2ecf20Sopenharmony_ci		call->unmarshall++;
16858c2ecf20Sopenharmony_ci		fallthrough;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci		/* Extract the capabilities word count */
16888c2ecf20Sopenharmony_ci	case 1:
16898c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
16908c2ecf20Sopenharmony_ci		if (ret < 0)
16918c2ecf20Sopenharmony_ci			return ret;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci		count = ntohl(call->tmp);
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci		call->count = count;
16968c2ecf20Sopenharmony_ci		call->count2 = count;
16978c2ecf20Sopenharmony_ci		afs_extract_discard(call, count * sizeof(__be32));
16988c2ecf20Sopenharmony_ci		call->unmarshall++;
16998c2ecf20Sopenharmony_ci		fallthrough;
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci		/* Extract capabilities words */
17028c2ecf20Sopenharmony_ci	case 2:
17038c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
17048c2ecf20Sopenharmony_ci		if (ret < 0)
17058c2ecf20Sopenharmony_ci			return ret;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci		/* TODO: Examine capabilities */
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci		call->unmarshall++;
17108c2ecf20Sopenharmony_ci		break;
17118c2ecf20Sopenharmony_ci	}
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
17148c2ecf20Sopenharmony_ci	return 0;
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci/*
17188c2ecf20Sopenharmony_ci * FS.GetCapabilities operation type
17198c2ecf20Sopenharmony_ci */
17208c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSGetCapabilities = {
17218c2ecf20Sopenharmony_ci	.name		= "FS.GetCapabilities",
17228c2ecf20Sopenharmony_ci	.op		= afs_FS_GetCapabilities,
17238c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_get_capabilities,
17248c2ecf20Sopenharmony_ci	.done		= afs_fileserver_probe_result,
17258c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
17268c2ecf20Sopenharmony_ci};
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci/*
17298c2ecf20Sopenharmony_ci * Probe a fileserver for the capabilities that it supports.  This RPC can
17308c2ecf20Sopenharmony_ci * reply with up to 196 words.  The operation is asynchronous and if we managed
17318c2ecf20Sopenharmony_ci * to allocate a call, true is returned the result is delivered through the
17328c2ecf20Sopenharmony_ci * ->done() - otherwise we return false to indicate we didn't even try.
17338c2ecf20Sopenharmony_ci */
17348c2ecf20Sopenharmony_cibool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
17358c2ecf20Sopenharmony_ci			     struct afs_addr_cursor *ac, struct key *key)
17368c2ecf20Sopenharmony_ci{
17378c2ecf20Sopenharmony_ci	struct afs_call *call;
17388c2ecf20Sopenharmony_ci	__be32 *bp;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	_enter("");
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
17438c2ecf20Sopenharmony_ci	if (!call)
17448c2ecf20Sopenharmony_ci		return false;
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	call->key = key;
17478c2ecf20Sopenharmony_ci	call->server = afs_use_server(server, afs_server_trace_get_caps);
17488c2ecf20Sopenharmony_ci	call->upgrade = true;
17498c2ecf20Sopenharmony_ci	call->async = true;
17508c2ecf20Sopenharmony_ci	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	/* marshall the parameters */
17538c2ecf20Sopenharmony_ci	bp = call->request;
17548c2ecf20Sopenharmony_ci	*bp++ = htonl(FSGETCAPABILITIES);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, NULL);
17578c2ecf20Sopenharmony_ci	afs_make_call(ac, call, GFP_NOFS);
17588c2ecf20Sopenharmony_ci	afs_put_call(call);
17598c2ecf20Sopenharmony_ci	return true;
17608c2ecf20Sopenharmony_ci}
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci/*
17638c2ecf20Sopenharmony_ci * Deliver reply data to an FS.InlineBulkStatus call
17648c2ecf20Sopenharmony_ci */
17658c2ecf20Sopenharmony_cistatic int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
17668c2ecf20Sopenharmony_ci{
17678c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
17688c2ecf20Sopenharmony_ci	struct afs_status_cb *scb;
17698c2ecf20Sopenharmony_ci	const __be32 *bp;
17708c2ecf20Sopenharmony_ci	u32 tmp;
17718c2ecf20Sopenharmony_ci	int ret;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
17768c2ecf20Sopenharmony_ci	case 0:
17778c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
17788c2ecf20Sopenharmony_ci		call->unmarshall++;
17798c2ecf20Sopenharmony_ci		fallthrough;
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci		/* Extract the file status count and array in two steps */
17828c2ecf20Sopenharmony_ci	case 1:
17838c2ecf20Sopenharmony_ci		_debug("extract status count");
17848c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
17858c2ecf20Sopenharmony_ci		if (ret < 0)
17868c2ecf20Sopenharmony_ci			return ret;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci		tmp = ntohl(call->tmp);
17898c2ecf20Sopenharmony_ci		_debug("status count: %u/%u", tmp, op->nr_files);
17908c2ecf20Sopenharmony_ci		if (tmp != op->nr_files)
17918c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_ibulkst_count);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci		call->count = 0;
17948c2ecf20Sopenharmony_ci		call->unmarshall++;
17958c2ecf20Sopenharmony_ci	more_counts:
17968c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, 21 * sizeof(__be32));
17978c2ecf20Sopenharmony_ci		fallthrough;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	case 2:
18008c2ecf20Sopenharmony_ci		_debug("extract status array %u", call->count);
18018c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
18028c2ecf20Sopenharmony_ci		if (ret < 0)
18038c2ecf20Sopenharmony_ci			return ret;
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci		switch (call->count) {
18068c2ecf20Sopenharmony_ci		case 0:
18078c2ecf20Sopenharmony_ci			scb = &op->file[0].scb;
18088c2ecf20Sopenharmony_ci			break;
18098c2ecf20Sopenharmony_ci		case 1:
18108c2ecf20Sopenharmony_ci			scb = &op->file[1].scb;
18118c2ecf20Sopenharmony_ci			break;
18128c2ecf20Sopenharmony_ci		default:
18138c2ecf20Sopenharmony_ci			scb = &op->more_files[call->count - 2].scb;
18148c2ecf20Sopenharmony_ci			break;
18158c2ecf20Sopenharmony_ci		}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		bp = call->buffer;
18188c2ecf20Sopenharmony_ci		xdr_decode_AFSFetchStatus(&bp, call, scb);
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci		call->count++;
18218c2ecf20Sopenharmony_ci		if (call->count < op->nr_files)
18228c2ecf20Sopenharmony_ci			goto more_counts;
18238c2ecf20Sopenharmony_ci
18248c2ecf20Sopenharmony_ci		call->count = 0;
18258c2ecf20Sopenharmony_ci		call->unmarshall++;
18268c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
18278c2ecf20Sopenharmony_ci		fallthrough;
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci		/* Extract the callback count and array in two steps */
18308c2ecf20Sopenharmony_ci	case 3:
18318c2ecf20Sopenharmony_ci		_debug("extract CB count");
18328c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
18338c2ecf20Sopenharmony_ci		if (ret < 0)
18348c2ecf20Sopenharmony_ci			return ret;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci		tmp = ntohl(call->tmp);
18378c2ecf20Sopenharmony_ci		_debug("CB count: %u", tmp);
18388c2ecf20Sopenharmony_ci		if (tmp != op->nr_files)
18398c2ecf20Sopenharmony_ci			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
18408c2ecf20Sopenharmony_ci		call->count = 0;
18418c2ecf20Sopenharmony_ci		call->unmarshall++;
18428c2ecf20Sopenharmony_ci	more_cbs:
18438c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, 3 * sizeof(__be32));
18448c2ecf20Sopenharmony_ci		fallthrough;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	case 4:
18478c2ecf20Sopenharmony_ci		_debug("extract CB array");
18488c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
18498c2ecf20Sopenharmony_ci		if (ret < 0)
18508c2ecf20Sopenharmony_ci			return ret;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		_debug("unmarshall CB array");
18538c2ecf20Sopenharmony_ci		switch (call->count) {
18548c2ecf20Sopenharmony_ci		case 0:
18558c2ecf20Sopenharmony_ci			scb = &op->file[0].scb;
18568c2ecf20Sopenharmony_ci			break;
18578c2ecf20Sopenharmony_ci		case 1:
18588c2ecf20Sopenharmony_ci			scb = &op->file[1].scb;
18598c2ecf20Sopenharmony_ci			break;
18608c2ecf20Sopenharmony_ci		default:
18618c2ecf20Sopenharmony_ci			scb = &op->more_files[call->count - 2].scb;
18628c2ecf20Sopenharmony_ci			break;
18638c2ecf20Sopenharmony_ci		}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci		bp = call->buffer;
18668c2ecf20Sopenharmony_ci		xdr_decode_AFSCallBack(&bp, call, scb);
18678c2ecf20Sopenharmony_ci		call->count++;
18688c2ecf20Sopenharmony_ci		if (call->count < op->nr_files)
18698c2ecf20Sopenharmony_ci			goto more_cbs;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, 6 * sizeof(__be32));
18728c2ecf20Sopenharmony_ci		call->unmarshall++;
18738c2ecf20Sopenharmony_ci		fallthrough;
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	case 5:
18768c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
18778c2ecf20Sopenharmony_ci		if (ret < 0)
18788c2ecf20Sopenharmony_ci			return ret;
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci		bp = call->buffer;
18818c2ecf20Sopenharmony_ci		xdr_decode_AFSVolSync(&bp, &op->volsync);
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci		call->unmarshall++;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	case 6:
18868c2ecf20Sopenharmony_ci		break;
18878c2ecf20Sopenharmony_ci	}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
18908c2ecf20Sopenharmony_ci	return 0;
18918c2ecf20Sopenharmony_ci}
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_cistatic void afs_done_fs_inline_bulk_status(struct afs_call *call)
18948c2ecf20Sopenharmony_ci{
18958c2ecf20Sopenharmony_ci	if (call->error == -ECONNABORTED &&
18968c2ecf20Sopenharmony_ci	    call->abort_code == RX_INVALID_OPERATION) {
18978c2ecf20Sopenharmony_ci		set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags);
18988c2ecf20Sopenharmony_ci		if (call->op)
18998c2ecf20Sopenharmony_ci			set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags);
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci/*
19048c2ecf20Sopenharmony_ci * FS.InlineBulkStatus operation type
19058c2ecf20Sopenharmony_ci */
19068c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSInlineBulkStatus = {
19078c2ecf20Sopenharmony_ci	.name		= "FS.InlineBulkStatus",
19088c2ecf20Sopenharmony_ci	.op		= afs_FS_InlineBulkStatus,
19098c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_inline_bulk_status,
19108c2ecf20Sopenharmony_ci	.done		= afs_done_fs_inline_bulk_status,
19118c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
19128c2ecf20Sopenharmony_ci};
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci/*
19158c2ecf20Sopenharmony_ci * Fetch the status information for up to 50 files
19168c2ecf20Sopenharmony_ci */
19178c2ecf20Sopenharmony_civoid afs_fs_inline_bulk_status(struct afs_operation *op)
19188c2ecf20Sopenharmony_ci{
19198c2ecf20Sopenharmony_ci	struct afs_vnode_param *dvp = &op->file[0];
19208c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[1];
19218c2ecf20Sopenharmony_ci	struct afs_call *call;
19228c2ecf20Sopenharmony_ci	__be32 *bp;
19238c2ecf20Sopenharmony_ci	int i;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) {
19268c2ecf20Sopenharmony_ci		op->error = -ENOTSUPP;
19278c2ecf20Sopenharmony_ci		return;
19288c2ecf20Sopenharmony_ci	}
19298c2ecf20Sopenharmony_ci
19308c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},%u",
19318c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus,
19348c2ecf20Sopenharmony_ci				   (2 + op->nr_files * 3) * 4,
19358c2ecf20Sopenharmony_ci				   21 * 4);
19368c2ecf20Sopenharmony_ci	if (!call)
19378c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	/* marshall the parameters */
19408c2ecf20Sopenharmony_ci	bp = call->request;
19418c2ecf20Sopenharmony_ci	*bp++ = htonl(FSINLINEBULKSTATUS);
19428c2ecf20Sopenharmony_ci	*bp++ = htonl(op->nr_files);
19438c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vid);
19448c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.vnode);
19458c2ecf20Sopenharmony_ci	*bp++ = htonl(dvp->fid.unique);
19468c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vid);
19478c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.vnode);
19488c2ecf20Sopenharmony_ci	*bp++ = htonl(vp->fid.unique);
19498c2ecf20Sopenharmony_ci	for (i = 0; i < op->nr_files - 2; i++) {
19508c2ecf20Sopenharmony_ci		*bp++ = htonl(op->more_files[i].fid.vid);
19518c2ecf20Sopenharmony_ci		*bp++ = htonl(op->more_files[i].fid.vnode);
19528c2ecf20Sopenharmony_ci		*bp++ = htonl(op->more_files[i].fid.unique);
19538c2ecf20Sopenharmony_ci	}
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
19568c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_NOFS);
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci/*
19608c2ecf20Sopenharmony_ci * deliver reply data to an FS.FetchACL
19618c2ecf20Sopenharmony_ci */
19628c2ecf20Sopenharmony_cistatic int afs_deliver_fs_fetch_acl(struct afs_call *call)
19638c2ecf20Sopenharmony_ci{
19648c2ecf20Sopenharmony_ci	struct afs_operation *op = call->op;
19658c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
19668c2ecf20Sopenharmony_ci	struct afs_acl *acl;
19678c2ecf20Sopenharmony_ci	const __be32 *bp;
19688c2ecf20Sopenharmony_ci	unsigned int size;
19698c2ecf20Sopenharmony_ci	int ret;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	_enter("{%u}", call->unmarshall);
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	switch (call->unmarshall) {
19748c2ecf20Sopenharmony_ci	case 0:
19758c2ecf20Sopenharmony_ci		afs_extract_to_tmp(call);
19768c2ecf20Sopenharmony_ci		call->unmarshall++;
19778c2ecf20Sopenharmony_ci		fallthrough;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci		/* extract the returned data length */
19808c2ecf20Sopenharmony_ci	case 1:
19818c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
19828c2ecf20Sopenharmony_ci		if (ret < 0)
19838c2ecf20Sopenharmony_ci			return ret;
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci		size = call->count2 = ntohl(call->tmp);
19868c2ecf20Sopenharmony_ci		size = round_up(size, 4);
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
19898c2ecf20Sopenharmony_ci		if (!acl)
19908c2ecf20Sopenharmony_ci			return -ENOMEM;
19918c2ecf20Sopenharmony_ci		op->acl = acl;
19928c2ecf20Sopenharmony_ci		acl->size = call->count2;
19938c2ecf20Sopenharmony_ci		afs_extract_begin(call, acl->data, size);
19948c2ecf20Sopenharmony_ci		call->unmarshall++;
19958c2ecf20Sopenharmony_ci		fallthrough;
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_ci		/* extract the returned data */
19988c2ecf20Sopenharmony_ci	case 2:
19998c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, true);
20008c2ecf20Sopenharmony_ci		if (ret < 0)
20018c2ecf20Sopenharmony_ci			return ret;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		afs_extract_to_buf(call, (21 + 6) * 4);
20048c2ecf20Sopenharmony_ci		call->unmarshall++;
20058c2ecf20Sopenharmony_ci		fallthrough;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci		/* extract the metadata */
20088c2ecf20Sopenharmony_ci	case 3:
20098c2ecf20Sopenharmony_ci		ret = afs_extract_data(call, false);
20108c2ecf20Sopenharmony_ci		if (ret < 0)
20118c2ecf20Sopenharmony_ci			return ret;
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci		bp = call->buffer;
20148c2ecf20Sopenharmony_ci		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
20158c2ecf20Sopenharmony_ci		xdr_decode_AFSVolSync(&bp, &op->volsync);
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci		call->unmarshall++;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	case 4:
20208c2ecf20Sopenharmony_ci		break;
20218c2ecf20Sopenharmony_ci	}
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	_leave(" = 0 [done]");
20248c2ecf20Sopenharmony_ci	return 0;
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci/*
20288c2ecf20Sopenharmony_ci * FS.FetchACL operation type
20298c2ecf20Sopenharmony_ci */
20308c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSFetchACL = {
20318c2ecf20Sopenharmony_ci	.name		= "FS.FetchACL",
20328c2ecf20Sopenharmony_ci	.op		= afs_FS_FetchACL,
20338c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_fetch_acl,
20348c2ecf20Sopenharmony_ci};
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci/*
20378c2ecf20Sopenharmony_ci * Fetch the ACL for a file.
20388c2ecf20Sopenharmony_ci */
20398c2ecf20Sopenharmony_civoid afs_fs_fetch_acl(struct afs_operation *op)
20408c2ecf20Sopenharmony_ci{
20418c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
20428c2ecf20Sopenharmony_ci	struct afs_call *call;
20438c2ecf20Sopenharmony_ci	__be32 *bp;
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
20468c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
20498c2ecf20Sopenharmony_ci	if (!call)
20508c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	/* marshall the parameters */
20538c2ecf20Sopenharmony_ci	bp = call->request;
20548c2ecf20Sopenharmony_ci	bp[0] = htonl(FSFETCHACL);
20558c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
20568c2ecf20Sopenharmony_ci	bp[2] = htonl(vp->fid.vnode);
20578c2ecf20Sopenharmony_ci	bp[3] = htonl(vp->fid.unique);
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
20608c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_KERNEL);
20618c2ecf20Sopenharmony_ci}
20628c2ecf20Sopenharmony_ci
20638c2ecf20Sopenharmony_ci/*
20648c2ecf20Sopenharmony_ci * FS.StoreACL operation type
20658c2ecf20Sopenharmony_ci */
20668c2ecf20Sopenharmony_cistatic const struct afs_call_type afs_RXFSStoreACL = {
20678c2ecf20Sopenharmony_ci	.name		= "FS.StoreACL",
20688c2ecf20Sopenharmony_ci	.op		= afs_FS_StoreACL,
20698c2ecf20Sopenharmony_ci	.deliver	= afs_deliver_fs_file_status_and_vol,
20708c2ecf20Sopenharmony_ci	.destructor	= afs_flat_call_destructor,
20718c2ecf20Sopenharmony_ci};
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci/*
20748c2ecf20Sopenharmony_ci * Fetch the ACL for a file.
20758c2ecf20Sopenharmony_ci */
20768c2ecf20Sopenharmony_civoid afs_fs_store_acl(struct afs_operation *op)
20778c2ecf20Sopenharmony_ci{
20788c2ecf20Sopenharmony_ci	struct afs_vnode_param *vp = &op->file[0];
20798c2ecf20Sopenharmony_ci	struct afs_call *call;
20808c2ecf20Sopenharmony_ci	const struct afs_acl *acl = op->acl;
20818c2ecf20Sopenharmony_ci	size_t size;
20828c2ecf20Sopenharmony_ci	__be32 *bp;
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	_enter(",%x,{%llx:%llu},,",
20858c2ecf20Sopenharmony_ci	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci	size = round_up(acl->size, 4);
20888c2ecf20Sopenharmony_ci	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL,
20898c2ecf20Sopenharmony_ci				   5 * 4 + size, (21 + 6) * 4);
20908c2ecf20Sopenharmony_ci	if (!call)
20918c2ecf20Sopenharmony_ci		return afs_op_nomem(op);
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	/* marshall the parameters */
20948c2ecf20Sopenharmony_ci	bp = call->request;
20958c2ecf20Sopenharmony_ci	bp[0] = htonl(FSSTOREACL);
20968c2ecf20Sopenharmony_ci	bp[1] = htonl(vp->fid.vid);
20978c2ecf20Sopenharmony_ci	bp[2] = htonl(vp->fid.vnode);
20988c2ecf20Sopenharmony_ci	bp[3] = htonl(vp->fid.unique);
20998c2ecf20Sopenharmony_ci	bp[4] = htonl(acl->size);
21008c2ecf20Sopenharmony_ci	memcpy(&bp[5], acl->data, acl->size);
21018c2ecf20Sopenharmony_ci	if (acl->size != size)
21028c2ecf20Sopenharmony_ci		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	trace_afs_make_fs_call(call, &vp->fid);
21058c2ecf20Sopenharmony_ci	afs_make_op_call(op, call, GFP_KERNEL);
21068c2ecf20Sopenharmony_ci}
2107