xref: /openbmc/linux/fs/afs/fsclient.c (revision 2f6640b1)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
208e0e7c8SDavid Howells /* AFS File Server client stubs
31da177e4SLinus Torvalds  *
408e0e7c8SDavid Howells  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/init.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
101da177e4SLinus Torvalds #include <linux/sched.h>
1108e0e7c8SDavid Howells #include <linux/circ_buf.h>
12a01179e6SJeff Layton #include <linux/iversion.h>
135cbf0398SDavid Howells #include <linux/netfs.h>
141da177e4SLinus Torvalds #include "internal.h"
1508e0e7c8SDavid Howells #include "afs_fs.h"
16dd9fbcb8SDavid Howells #include "xdr_fs.h"
17c435ee34SDavid Howells 
186db3ac3cSDavid Howells /*
19260a9803SDavid Howells  * decode an AFSFid block
20260a9803SDavid Howells  */
xdr_decode_AFSFid(const __be32 ** _bp,struct afs_fid * fid)21260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
22260a9803SDavid Howells {
23260a9803SDavid Howells 	const __be32 *bp = *_bp;
24260a9803SDavid Howells 
25260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
26260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
27260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
28260a9803SDavid Howells 	*_bp = bp;
29260a9803SDavid Howells }
30260a9803SDavid Howells 
31260a9803SDavid Howells /*
32888b3384SDavid Howells  * Dump a bad file status record.
33888b3384SDavid Howells  */
xdr_dump_bad(const __be32 * bp)34888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
35888b3384SDavid Howells {
36888b3384SDavid Howells 	__be32 x[4];
37888b3384SDavid Howells 	int i;
38888b3384SDavid Howells 
39888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
40888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
41888b3384SDavid Howells 		memcpy(x, bp, 16);
42888b3384SDavid Howells 		bp += 4;
43888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
44888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
45888b3384SDavid Howells 	}
46888b3384SDavid Howells 
47888b3384SDavid Howells 	memcpy(x, bp, 4);
48888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
49888b3384SDavid Howells }
50888b3384SDavid Howells 
51888b3384SDavid Howells /*
52dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
53dd9fbcb8SDavid Howells  */
xdr_decode_AFSFetchStatus(const __be32 ** _bp,struct afs_call * call,struct afs_status_cb * scb)5438355eecSDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
55a58823acSDavid Howells 				      struct afs_call *call,
56a58823acSDavid Howells 				      struct afs_status_cb *scb)
57dd9fbcb8SDavid Howells {
58dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
59a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
60684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
61dd9fbcb8SDavid Howells 	u64 data_version, size;
62dd9fbcb8SDavid Howells 	u32 type, abort_code;
63dd9fbcb8SDavid Howells 
64684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
65684b0f68SDavid Howells 
66dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
67684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
68684b0f68SDavid Howells 		    abort_code != 0 &&
69684b0f68SDavid Howells 		    inline_error) {
70684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
71684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
72684b0f68SDavid Howells 			 * case.
73684b0f68SDavid Howells 			 */
74684b0f68SDavid Howells 			status->abort_code = abort_code;
75a38a7558SDavid Howells 			scb->have_error = true;
7638355eecSDavid Howells 			goto advance;
77684b0f68SDavid Howells 		}
78684b0f68SDavid Howells 
79dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
80dd9fbcb8SDavid Howells 		goto bad;
81dd9fbcb8SDavid Howells 	}
82dd9fbcb8SDavid Howells 
83684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
84684b0f68SDavid Howells 		status->abort_code = abort_code;
853e0d9892SDavid Howells 		scb->have_error = true;
8638355eecSDavid Howells 		goto advance;
87684b0f68SDavid Howells 	}
88684b0f68SDavid Howells 
89dd9fbcb8SDavid Howells 	type = ntohl(xdr->type);
90dd9fbcb8SDavid Howells 	switch (type) {
91dd9fbcb8SDavid Howells 	case AFS_FTYPE_FILE:
92dd9fbcb8SDavid Howells 	case AFS_FTYPE_DIR:
93dd9fbcb8SDavid Howells 	case AFS_FTYPE_SYMLINK:
94dd9fbcb8SDavid Howells 		status->type = type;
95dd9fbcb8SDavid Howells 		break;
96dd9fbcb8SDavid Howells 	default:
97dd9fbcb8SDavid Howells 		goto bad;
98dd9fbcb8SDavid Howells 	}
99dd9fbcb8SDavid Howells 
100a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
101a58823acSDavid Howells 	status->author		= ntohl(xdr->author);
102a58823acSDavid Howells 	status->owner		= ntohl(xdr->owner);
103a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
104a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
105a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
106a58823acSDavid Howells 	status->group		= ntohl(xdr->group);
107a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
108dd9fbcb8SDavid Howells 
109d4936803SDavid Howells 	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
110d4936803SDavid Howells 	status->mtime_client.tv_nsec = 0;
111d4936803SDavid Howells 	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
112d4936803SDavid Howells 	status->mtime_server.tv_nsec = 0;
113dd9fbcb8SDavid Howells 
114dd9fbcb8SDavid Howells 	size  = (u64)ntohl(xdr->size_lo);
115dd9fbcb8SDavid Howells 	size |= (u64)ntohl(xdr->size_hi) << 32;
116dd9fbcb8SDavid Howells 	status->size = size;
117dd9fbcb8SDavid Howells 
118dd9fbcb8SDavid Howells 	data_version  = (u64)ntohl(xdr->data_version_lo);
119dd9fbcb8SDavid Howells 	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
120dd9fbcb8SDavid Howells 	status->data_version = data_version;
121a38a7558SDavid Howells 	scb->have_status = true;
122c72057b5SDavid Howells advance:
123dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
12438355eecSDavid Howells 	return;
125dd9fbcb8SDavid Howells 
126dd9fbcb8SDavid Howells bad:
127dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
1287126ead9SDavid Howells 	afs_protocol_error(call, afs_eproto_bad_status);
129c72057b5SDavid Howells 	goto advance;
130c875c76aSDavid Howells }
131c875c76aSDavid Howells 
xdr_decode_expiry(struct afs_call * call,u32 expiry)13278107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
13378107055SDavid Howells {
134*2f6640b1SDavid Howells 	return ktime_divns(call->issue_time, NSEC_PER_SEC) + expiry;
13578107055SDavid Howells }
13678107055SDavid Howells 
xdr_decode_AFSCallBack(const __be32 ** _bp,struct afs_call * call,struct afs_status_cb * scb)137a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
138a58823acSDavid Howells 				   struct afs_call *call,
139a58823acSDavid Howells 				   struct afs_status_cb *scb)
14078107055SDavid Howells {
141a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
14278107055SDavid Howells 	const __be32 *bp = *_bp;
14378107055SDavid Howells 
1447c712458SDavid Howells 	bp++; /* version */
14578107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1467c712458SDavid Howells 	bp++; /* type */
147a58823acSDavid Howells 	scb->have_cb	= true;
14878107055SDavid Howells 	*_bp = bp;
14978107055SDavid Howells }
15078107055SDavid Howells 
1511da177e4SLinus Torvalds /*
15208e0e7c8SDavid Howells  * decode an AFSVolSync block
1531da177e4SLinus Torvalds  */
xdr_decode_AFSVolSync(const __be32 ** _bp,struct afs_volsync * volsync)15408e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
15508e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1561da177e4SLinus Torvalds {
15708e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
15830062bd1SDavid Howells 	u32 creation;
1591da177e4SLinus Torvalds 
16030062bd1SDavid Howells 	creation = ntohl(*bp++);
16108e0e7c8SDavid Howells 	bp++; /* spare2 */
16208e0e7c8SDavid Howells 	bp++; /* spare3 */
16308e0e7c8SDavid Howells 	bp++; /* spare4 */
16408e0e7c8SDavid Howells 	bp++; /* spare5 */
16508e0e7c8SDavid Howells 	bp++; /* spare6 */
16608e0e7c8SDavid Howells 	*_bp = bp;
16730062bd1SDavid Howells 
16830062bd1SDavid Howells 	if (volsync)
16930062bd1SDavid Howells 		volsync->creation = creation;
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds 
17208e0e7c8SDavid Howells /*
17331143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
17431143d5dSDavid Howells  */
xdr_encode_AFS_StoreStatus(__be32 ** _bp,struct iattr * attr)17531143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
17631143d5dSDavid Howells {
17731143d5dSDavid Howells 	__be32 *bp = *_bp;
17831143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
17931143d5dSDavid Howells 
18031143d5dSDavid Howells 	mask = 0;
18131143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18231143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
18331143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
18431143d5dSDavid Howells 	}
18531143d5dSDavid Howells 
18631143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
18731143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
188a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
18931143d5dSDavid Howells 	}
19031143d5dSDavid Howells 
19131143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19231143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
193a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
19431143d5dSDavid Howells 	}
19531143d5dSDavid Howells 
19631143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
19731143d5dSDavid Howells 		mask |= AFS_SET_MODE;
19831143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
19931143d5dSDavid Howells 	}
20031143d5dSDavid Howells 
20131143d5dSDavid Howells 	*bp++ = htonl(mask);
20231143d5dSDavid Howells 	*bp++ = htonl(mtime);
20331143d5dSDavid Howells 	*bp++ = htonl(owner);
20431143d5dSDavid Howells 	*bp++ = htonl(group);
20531143d5dSDavid Howells 	*bp++ = htonl(mode);
20631143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
20731143d5dSDavid Howells 	*_bp = bp;
20831143d5dSDavid Howells }
20931143d5dSDavid Howells 
21031143d5dSDavid Howells /*
21145222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21245222b9eSDavid Howells  */
xdr_decode_AFSFetchVolumeStatus(const __be32 ** _bp,struct afs_volume_status * vs)21345222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
21445222b9eSDavid Howells 					    struct afs_volume_status *vs)
21545222b9eSDavid Howells {
21645222b9eSDavid Howells 	const __be32 *bp = *_bp;
21745222b9eSDavid Howells 
21845222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
21945222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22045222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22145222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22245222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
22345222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
22445222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
22545222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23030062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23130062bd1SDavid Howells 	vs->vol_backup_date	= 0;
23245222b9eSDavid Howells 	*_bp = bp;
23345222b9eSDavid Howells }
23445222b9eSDavid Howells 
23545222b9eSDavid Howells /*
23608e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
23708e0e7c8SDavid Howells  */
afs_deliver_fs_fetch_status(struct afs_call * call)238e49c7b2fSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
23908e0e7c8SDavid Howells {
240e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
241e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
24208e0e7c8SDavid Howells 	const __be32 *bp;
243372ee163SDavid Howells 	int ret;
2441da177e4SLinus Torvalds 
245d001648eSDavid Howells 	ret = afs_transfer_reply(call);
246372ee163SDavid Howells 	if (ret < 0)
247372ee163SDavid Howells 		return ret;
2481da177e4SLinus Torvalds 
24908e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25008e0e7c8SDavid Howells 	bp = call->buffer;
251e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
252e49c7b2fSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
253e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
2541da177e4SLinus Torvalds 
25508e0e7c8SDavid Howells 	_leave(" = 0 [done]");
25608e0e7c8SDavid Howells 	return 0;
257ec26815aSDavid Howells }
25808e0e7c8SDavid Howells 
25908e0e7c8SDavid Howells /*
26008e0e7c8SDavid Howells  * FS.FetchStatus operation type
26108e0e7c8SDavid Howells  */
262e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
263e49c7b2fSDavid Howells 	.name		= "FS.FetchStatus",
264025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
265e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
26608e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
26708e0e7c8SDavid Howells };
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds /*
2701da177e4SLinus Torvalds  * fetch the status information for a file
2711da177e4SLinus Torvalds  */
afs_fs_fetch_status(struct afs_operation * op)272e49c7b2fSDavid Howells void afs_fs_fetch_status(struct afs_operation *op)
2731da177e4SLinus Torvalds {
274e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
27508e0e7c8SDavid Howells 	struct afs_call *call;
2761da177e4SLinus Torvalds 	__be32 *bp;
2771da177e4SLinus Torvalds 
2783b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
279e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2801da177e4SLinus Torvalds 
281e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchStatus,
2825cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
283e49c7b2fSDavid Howells 	if (!call)
284e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 	/* marshall the parameters */
28708e0e7c8SDavid Howells 	bp = call->request;
2881da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
289e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
290e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
291e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2921da177e4SLinus Torvalds 
293e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
294e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
295ec26815aSDavid Howells }
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds /*
29808e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
2991da177e4SLinus Torvalds  */
afs_deliver_fs_fetch_data(struct afs_call * call)300d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3011da177e4SLinus Torvalds {
302e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
303e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
304e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
30508e0e7c8SDavid Howells 	const __be32 *bp;
3061da177e4SLinus Torvalds 	int ret;
3071da177e4SLinus Torvalds 
308f105da1aSDavid Howells 	_enter("{%u,%zu,%zu/%llu}",
309f105da1aSDavid Howells 	       call->unmarshall, call->iov_len, iov_iter_count(call->iter),
310f105da1aSDavid Howells 	       req->actual_len);
3111da177e4SLinus Torvalds 
31208e0e7c8SDavid Howells 	switch (call->unmarshall) {
31308e0e7c8SDavid Howells 	case 0:
314196ee9cdSDavid Howells 		req->actual_len = 0;
31508e0e7c8SDavid Howells 		call->unmarshall++;
31612bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
31712bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
31812bdcf33SDavid Howells 		} else {
31912bdcf33SDavid Howells 			call->tmp_u = htonl(0);
32012bdcf33SDavid Howells 			afs_extract_to_tmp(call);
321b9b1f8d5SDavid Howells 		}
322df561f66SGustavo A. R. Silva 		fallthrough;
3231da177e4SLinus Torvalds 
324c4508464SDavid Howells 		/* Extract the returned data length into
325c4508464SDavid Howells 		 * ->actual_len.  This may indicate more or less data than was
326c4508464SDavid Howells 		 * requested will be returned.
327c4508464SDavid Howells 		 */
32812bdcf33SDavid Howells 	case 1:
32908e0e7c8SDavid Howells 		_debug("extract data length");
33012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
331372ee163SDavid Howells 		if (ret < 0)
332372ee163SDavid Howells 			return ret;
3331da177e4SLinus Torvalds 
33412bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
335196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
336c4508464SDavid Howells 
337c4508464SDavid Howells 		if (req->actual_len == 0)
338196ee9cdSDavid Howells 			goto no_more_data;
33912bdcf33SDavid Howells 
340c4508464SDavid Howells 		call->iter = req->iter;
341c4508464SDavid Howells 		call->iov_len = min(req->actual_len, req->len);
34208e0e7c8SDavid Howells 		call->unmarshall++;
343df561f66SGustavo A. R. Silva 		fallthrough;
344196ee9cdSDavid Howells 
34529881608SGustavo A. R. Silva 		/* extract the returned data */
34612bdcf33SDavid Howells 	case 2:
34712bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
348c4508464SDavid Howells 		       iov_iter_count(call->iter), req->actual_len);
349196ee9cdSDavid Howells 
35012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
351372ee163SDavid Howells 		if (ret < 0)
352372ee163SDavid Howells 			return ret;
35312bdcf33SDavid Howells 
354c4508464SDavid Howells 		call->iter = &call->def_iter;
35512bdcf33SDavid Howells 		if (req->actual_len <= req->len)
3566db3ac3cSDavid Howells 			goto no_more_data;
3576db3ac3cSDavid Howells 
3586db3ac3cSDavid Howells 		/* Discard any excess data the server gave us */
35923a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
36012bdcf33SDavid Howells 		call->unmarshall = 3;
361df561f66SGustavo A. R. Silva 		fallthrough;
36229881608SGustavo A. R. Silva 
36312bdcf33SDavid Howells 	case 3:
36412bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
365fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
3666db3ac3cSDavid Howells 
36712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
3686db3ac3cSDavid Howells 		if (ret < 0)
3696db3ac3cSDavid Howells 			return ret;
3701da177e4SLinus Torvalds 
371196ee9cdSDavid Howells 	no_more_data:
37212bdcf33SDavid Howells 		call->unmarshall = 4;
37312bdcf33SDavid Howells 		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
374df561f66SGustavo A. R. Silva 		fallthrough;
37508e0e7c8SDavid Howells 
37629881608SGustavo A. R. Silva 		/* extract the metadata */
37712bdcf33SDavid Howells 	case 4:
37812bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
379372ee163SDavid Howells 		if (ret < 0)
380372ee163SDavid Howells 			return ret;
3811da177e4SLinus Torvalds 
38208e0e7c8SDavid Howells 		bp = call->buffer;
383e49c7b2fSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
384e49c7b2fSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, &vp->scb);
385e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
3861da177e4SLinus Torvalds 
387e49c7b2fSDavid Howells 		req->data_version = vp->scb.status.data_version;
388e49c7b2fSDavid Howells 		req->file_size = vp->scb.status.size;
389a58823acSDavid Howells 
39008e0e7c8SDavid Howells 		call->unmarshall++;
391b2db6c35SGustavo A. R. Silva 		fallthrough;
3921da177e4SLinus Torvalds 
39312bdcf33SDavid Howells 	case 5:
3941da177e4SLinus Torvalds 		break;
3951da177e4SLinus Torvalds 	}
3961da177e4SLinus Torvalds 
39708e0e7c8SDavid Howells 	_leave(" = 0 [done]");
39808e0e7c8SDavid Howells 	return 0;
399ec26815aSDavid Howells }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds /*
40208e0e7c8SDavid Howells  * FS.FetchData operation type
4031da177e4SLinus Torvalds  */
40408e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
40500d3b7a4SDavid Howells 	.name		= "FS.FetchData",
406025db80cSDavid Howells 	.op		= afs_FS_FetchData,
40708e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
408e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
40908e0e7c8SDavid Howells };
41008e0e7c8SDavid Howells 
411b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
412b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
413025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
414b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
415e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
416b9b1f8d5SDavid Howells };
417b9b1f8d5SDavid Howells 
418b9b1f8d5SDavid Howells /*
419b9b1f8d5SDavid Howells  * fetch data from a very large file
420b9b1f8d5SDavid Howells  */
afs_fs_fetch_data64(struct afs_operation * op)421e49c7b2fSDavid Howells static void afs_fs_fetch_data64(struct afs_operation *op)
422b9b1f8d5SDavid Howells {
423e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
424e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
425b9b1f8d5SDavid Howells 	struct afs_call *call;
426b9b1f8d5SDavid Howells 	__be32 *bp;
427b9b1f8d5SDavid Howells 
428b9b1f8d5SDavid Howells 	_enter("");
429b9b1f8d5SDavid Howells 
430e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
431b9b1f8d5SDavid Howells 	if (!call)
432e49c7b2fSDavid Howells 		return afs_op_nomem(op);
433b9b1f8d5SDavid Howells 
434b9b1f8d5SDavid Howells 	/* marshall the parameters */
435b9b1f8d5SDavid Howells 	bp = call->request;
436b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
437e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
438e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
439e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
440196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
441196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
442b9b1f8d5SDavid Howells 	bp[6] = 0;
443196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
444b9b1f8d5SDavid Howells 
445e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
446e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
447b9b1f8d5SDavid Howells }
448b9b1f8d5SDavid Howells 
44908e0e7c8SDavid Howells /*
45008e0e7c8SDavid Howells  * fetch data from a file
45108e0e7c8SDavid Howells  */
afs_fs_fetch_data(struct afs_operation * op)452e49c7b2fSDavid Howells void afs_fs_fetch_data(struct afs_operation *op)
4531da177e4SLinus Torvalds {
454e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
45508e0e7c8SDavid Howells 	struct afs_call *call;
456e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
45708e0e7c8SDavid Howells 	__be32 *bp;
4581da177e4SLinus Torvalds 
459b537a3c2SDavid Howells 	if (test_bit(AFS_SERVER_FL_HAS_FS64, &op->server->flags))
460e49c7b2fSDavid Howells 		return afs_fs_fetch_data64(op);
461b9b1f8d5SDavid Howells 
46208e0e7c8SDavid Howells 	_enter("");
4631da177e4SLinus Torvalds 
464e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
46508e0e7c8SDavid Howells 	if (!call)
466e49c7b2fSDavid Howells 		return afs_op_nomem(op);
4671da177e4SLinus Torvalds 
468c4508464SDavid Howells 	req->call_debug_id = call->debug_id;
469c4508464SDavid Howells 
4701da177e4SLinus Torvalds 	/* marshall the parameters */
47108e0e7c8SDavid Howells 	bp = call->request;
47208e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
473e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
474e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
475e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
476196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
477196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
4781da177e4SLinus Torvalds 
479e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
480e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
48108e0e7c8SDavid Howells }
482260a9803SDavid Howells 
483260a9803SDavid Howells /*
484260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
485260a9803SDavid Howells  */
afs_deliver_fs_create_vnode(struct afs_call * call)486d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
487260a9803SDavid Howells {
488e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
489e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
490e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
491260a9803SDavid Howells 	const __be32 *bp;
492372ee163SDavid Howells 	int ret;
493260a9803SDavid Howells 
494d001648eSDavid Howells 	ret = afs_transfer_reply(call);
495372ee163SDavid Howells 	if (ret < 0)
496372ee163SDavid Howells 		return ret;
497260a9803SDavid Howells 
498260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
499260a9803SDavid Howells 	bp = call->buffer;
500e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &op->file[1].fid);
501e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
502e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
503e49c7b2fSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
504e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
505260a9803SDavid Howells 
506260a9803SDavid Howells 	_leave(" = 0 [done]");
507260a9803SDavid Howells 	return 0;
508260a9803SDavid Howells }
509260a9803SDavid Howells 
510260a9803SDavid Howells /*
511260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
512260a9803SDavid Howells  */
513025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
514025db80cSDavid Howells 	.name		= "FS.CreateFile",
515025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
516025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
517025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
518025db80cSDavid Howells };
519025db80cSDavid Howells 
520e49c7b2fSDavid Howells /*
521e49c7b2fSDavid Howells  * Create a file.
522e49c7b2fSDavid Howells  */
afs_fs_create_file(struct afs_operation * op)523e49c7b2fSDavid Howells void afs_fs_create_file(struct afs_operation *op)
524e49c7b2fSDavid Howells {
525e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
526e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
527e49c7b2fSDavid Howells 	struct afs_call *call;
528e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
529e49c7b2fSDavid Howells 	__be32 *bp;
530e49c7b2fSDavid Howells 
531e49c7b2fSDavid Howells 	_enter("");
532e49c7b2fSDavid Howells 
533e49c7b2fSDavid Howells 	namesz = name->len;
534e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
535e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
536e49c7b2fSDavid Howells 
537e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile,
538e49c7b2fSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
539e49c7b2fSDavid Howells 	if (!call)
540e49c7b2fSDavid Howells 		return afs_op_nomem(op);
541e49c7b2fSDavid Howells 
542e49c7b2fSDavid Howells 	/* marshall the parameters */
543e49c7b2fSDavid Howells 	bp = call->request;
544e49c7b2fSDavid Howells 	*bp++ = htonl(FSCREATEFILE);
545e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
546e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
547e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
548e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
549e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
550e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
551e49c7b2fSDavid Howells 	if (padsz > 0) {
552e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
553e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
554e49c7b2fSDavid Howells 	}
555e49c7b2fSDavid Howells 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
556e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
557e49c7b2fSDavid Howells 	*bp++ = 0; /* owner */
558e49c7b2fSDavid Howells 	*bp++ = 0; /* group */
559e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
560e49c7b2fSDavid Howells 	*bp++ = 0; /* segment size */
561e49c7b2fSDavid Howells 
562e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
563e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
564e49c7b2fSDavid Howells }
565e49c7b2fSDavid Howells 
566025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
567025db80cSDavid Howells 	.name		= "FS.MakeDir",
568025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
569260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
570260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
571260a9803SDavid Howells };
572260a9803SDavid Howells 
573260a9803SDavid Howells /*
574e49c7b2fSDavid Howells  * Create a new directory
575260a9803SDavid Howells  */
afs_fs_make_dir(struct afs_operation * op)576e49c7b2fSDavid Howells void afs_fs_make_dir(struct afs_operation *op)
577260a9803SDavid Howells {
578e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
579e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
580260a9803SDavid Howells 	struct afs_call *call;
581260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
582260a9803SDavid Howells 	__be32 *bp;
583260a9803SDavid Howells 
584260a9803SDavid Howells 	_enter("");
585260a9803SDavid Howells 
586e49c7b2fSDavid Howells 	namesz = name->len;
587260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
588260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
589260a9803SDavid Howells 
590e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir,
591025db80cSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
592260a9803SDavid Howells 	if (!call)
593e49c7b2fSDavid Howells 		return afs_op_nomem(op);
594260a9803SDavid Howells 
595260a9803SDavid Howells 	/* marshall the parameters */
596260a9803SDavid Howells 	bp = call->request;
597e49c7b2fSDavid Howells 	*bp++ = htonl(FSMAKEDIR);
598e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
599e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
600e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
601260a9803SDavid Howells 	*bp++ = htonl(namesz);
602e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
603260a9803SDavid Howells 	bp = (void *) bp + namesz;
604260a9803SDavid Howells 	if (padsz > 0) {
605260a9803SDavid Howells 		memset(bp, 0, padsz);
606260a9803SDavid Howells 		bp = (void *) bp + padsz;
607260a9803SDavid Howells 	}
608ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
609e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
610260a9803SDavid Howells 	*bp++ = 0; /* owner */
611260a9803SDavid Howells 	*bp++ = 0; /* group */
612e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
613260a9803SDavid Howells 	*bp++ = 0; /* segment size */
614260a9803SDavid Howells 
615e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
616e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
617260a9803SDavid Howells }
618260a9803SDavid Howells 
619260a9803SDavid Howells /*
620e49c7b2fSDavid Howells  * Deliver reply data to any operation that returns status and volume sync.
621260a9803SDavid Howells  */
afs_deliver_fs_file_status_and_vol(struct afs_call * call)622e49c7b2fSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
623260a9803SDavid Howells {
624e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
625e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
626260a9803SDavid Howells 	const __be32 *bp;
627372ee163SDavid Howells 	int ret;
628260a9803SDavid Howells 
629d001648eSDavid Howells 	ret = afs_transfer_reply(call);
630372ee163SDavid Howells 	if (ret < 0)
631372ee163SDavid Howells 		return ret;
632260a9803SDavid Howells 
633260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
634260a9803SDavid Howells 	bp = call->buffer;
635e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
636e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
637260a9803SDavid Howells 
638260a9803SDavid Howells 	_leave(" = 0 [done]");
639260a9803SDavid Howells 	return 0;
640260a9803SDavid Howells }
641260a9803SDavid Howells 
642260a9803SDavid Howells /*
643e49c7b2fSDavid Howells  * FS.RemoveFile operation type
644260a9803SDavid Howells  */
645025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
646025db80cSDavid Howells 	.name		= "FS.RemoveFile",
647025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
648e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
649260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
650260a9803SDavid Howells };
651260a9803SDavid Howells 
652260a9803SDavid Howells /*
653e49c7b2fSDavid Howells  * Remove a file.
654260a9803SDavid Howells  */
afs_fs_remove_file(struct afs_operation * op)655e49c7b2fSDavid Howells void afs_fs_remove_file(struct afs_operation *op)
656260a9803SDavid Howells {
657e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
658e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
659260a9803SDavid Howells 	struct afs_call *call;
660260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
661260a9803SDavid Howells 	__be32 *bp;
662260a9803SDavid Howells 
663260a9803SDavid Howells 	_enter("");
664260a9803SDavid Howells 
665e49c7b2fSDavid Howells 	namesz = name->len;
666260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
667260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
668260a9803SDavid Howells 
669e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile,
670025db80cSDavid Howells 				   reqsz, (21 + 6) * 4);
671260a9803SDavid Howells 	if (!call)
672e49c7b2fSDavid Howells 		return afs_op_nomem(op);
673260a9803SDavid Howells 
674260a9803SDavid Howells 	/* marshall the parameters */
675260a9803SDavid Howells 	bp = call->request;
676e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEFILE);
677e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
678e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
679e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
680260a9803SDavid Howells 	*bp++ = htonl(namesz);
681e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
682260a9803SDavid Howells 	bp = (void *) bp + namesz;
683260a9803SDavid Howells 	if (padsz > 0) {
684260a9803SDavid Howells 		memset(bp, 0, padsz);
685260a9803SDavid Howells 		bp = (void *) bp + padsz;
686260a9803SDavid Howells 	}
687260a9803SDavid Howells 
688e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
689e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
690e49c7b2fSDavid Howells }
691e49c7b2fSDavid Howells 
692e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
693e49c7b2fSDavid Howells 	.name		= "FS.RemoveDir",
694e49c7b2fSDavid Howells 	.op		= afs_FS_RemoveDir,
695e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
696e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
697e49c7b2fSDavid Howells };
698e49c7b2fSDavid Howells 
699e49c7b2fSDavid Howells /*
700e49c7b2fSDavid Howells  * Remove a directory.
701e49c7b2fSDavid Howells  */
afs_fs_remove_dir(struct afs_operation * op)702e49c7b2fSDavid Howells void afs_fs_remove_dir(struct afs_operation *op)
703e49c7b2fSDavid Howells {
704e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
705e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
706e49c7b2fSDavid Howells 	struct afs_call *call;
707e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
708e49c7b2fSDavid Howells 	__be32 *bp;
709e49c7b2fSDavid Howells 
710e49c7b2fSDavid Howells 	_enter("");
711e49c7b2fSDavid Howells 
712e49c7b2fSDavid Howells 	namesz = name->len;
713e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
714e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
715e49c7b2fSDavid Howells 
716e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir,
717e49c7b2fSDavid Howells 				   reqsz, (21 + 6) * 4);
718e49c7b2fSDavid Howells 	if (!call)
719e49c7b2fSDavid Howells 		return afs_op_nomem(op);
720e49c7b2fSDavid Howells 
721e49c7b2fSDavid Howells 	/* marshall the parameters */
722e49c7b2fSDavid Howells 	bp = call->request;
723e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEDIR);
724e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
725e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
726e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
727e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
728e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
729e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
730e49c7b2fSDavid Howells 	if (padsz > 0) {
731e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
732e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
733e49c7b2fSDavid Howells 	}
734e49c7b2fSDavid Howells 
735e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
736e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
737260a9803SDavid Howells }
738260a9803SDavid Howells 
739260a9803SDavid Howells /*
740260a9803SDavid Howells  * deliver reply data to an FS.Link
741260a9803SDavid Howells  */
afs_deliver_fs_link(struct afs_call * call)742d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
743260a9803SDavid Howells {
744e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
745e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
746e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
747260a9803SDavid Howells 	const __be32 *bp;
748372ee163SDavid Howells 	int ret;
749260a9803SDavid Howells 
750d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
751260a9803SDavid Howells 
752d001648eSDavid Howells 	ret = afs_transfer_reply(call);
753372ee163SDavid Howells 	if (ret < 0)
754372ee163SDavid Howells 		return ret;
755260a9803SDavid Howells 
756260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
757260a9803SDavid Howells 	bp = call->buffer;
758e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
759e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
760e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
761260a9803SDavid Howells 
762260a9803SDavid Howells 	_leave(" = 0 [done]");
763260a9803SDavid Howells 	return 0;
764260a9803SDavid Howells }
765260a9803SDavid Howells 
766260a9803SDavid Howells /*
767260a9803SDavid Howells  * FS.Link operation type
768260a9803SDavid Howells  */
769260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
770260a9803SDavid Howells 	.name		= "FS.Link",
771025db80cSDavid Howells 	.op		= afs_FS_Link,
772260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
773260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
774260a9803SDavid Howells };
775260a9803SDavid Howells 
776260a9803SDavid Howells /*
777260a9803SDavid Howells  * make a hard link
778260a9803SDavid Howells  */
afs_fs_link(struct afs_operation * op)779e49c7b2fSDavid Howells void afs_fs_link(struct afs_operation *op)
780260a9803SDavid Howells {
781e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
782e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
783e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
784260a9803SDavid Howells 	struct afs_call *call;
785260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
786260a9803SDavid Howells 	__be32 *bp;
787260a9803SDavid Howells 
788260a9803SDavid Howells 	_enter("");
789260a9803SDavid Howells 
790e49c7b2fSDavid Howells 	namesz = name->len;
791260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
792260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
793260a9803SDavid Howells 
794e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
795260a9803SDavid Howells 	if (!call)
796e49c7b2fSDavid Howells 		return afs_op_nomem(op);
797260a9803SDavid Howells 
798260a9803SDavid Howells 	/* marshall the parameters */
799260a9803SDavid Howells 	bp = call->request;
800260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
801e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
802e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
803e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
804260a9803SDavid Howells 	*bp++ = htonl(namesz);
805e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
806260a9803SDavid Howells 	bp = (void *) bp + namesz;
807260a9803SDavid Howells 	if (padsz > 0) {
808260a9803SDavid Howells 		memset(bp, 0, padsz);
809260a9803SDavid Howells 		bp = (void *) bp + padsz;
810260a9803SDavid Howells 	}
811e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
812e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
813e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
814260a9803SDavid Howells 
815e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
816e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
817260a9803SDavid Howells }
818260a9803SDavid Howells 
819260a9803SDavid Howells /*
820260a9803SDavid Howells  * deliver reply data to an FS.Symlink
821260a9803SDavid Howells  */
afs_deliver_fs_symlink(struct afs_call * call)822d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
823260a9803SDavid Howells {
824e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
825e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
826e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
827260a9803SDavid Howells 	const __be32 *bp;
828372ee163SDavid Howells 	int ret;
829260a9803SDavid Howells 
830d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
831260a9803SDavid Howells 
832d001648eSDavid Howells 	ret = afs_transfer_reply(call);
833372ee163SDavid Howells 	if (ret < 0)
834372ee163SDavid Howells 		return ret;
835260a9803SDavid Howells 
836260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
837260a9803SDavid Howells 	bp = call->buffer;
838e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &vp->fid);
839e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
840e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
841e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
842260a9803SDavid Howells 
843260a9803SDavid Howells 	_leave(" = 0 [done]");
844260a9803SDavid Howells 	return 0;
845260a9803SDavid Howells }
846260a9803SDavid Howells 
847260a9803SDavid Howells /*
848260a9803SDavid Howells  * FS.Symlink operation type
849260a9803SDavid Howells  */
850260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
851260a9803SDavid Howells 	.name		= "FS.Symlink",
852025db80cSDavid Howells 	.op		= afs_FS_Symlink,
853260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
854260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
855260a9803SDavid Howells };
856260a9803SDavid Howells 
857260a9803SDavid Howells /*
858260a9803SDavid Howells  * create a symbolic link
859260a9803SDavid Howells  */
afs_fs_symlink(struct afs_operation * op)860e49c7b2fSDavid Howells void afs_fs_symlink(struct afs_operation *op)
861260a9803SDavid Howells {
862e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
863e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
864260a9803SDavid Howells 	struct afs_call *call;
865260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
866260a9803SDavid Howells 	__be32 *bp;
867260a9803SDavid Howells 
868260a9803SDavid Howells 	_enter("");
869260a9803SDavid Howells 
870e49c7b2fSDavid Howells 	namesz = name->len;
871260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
872260a9803SDavid Howells 
873e49c7b2fSDavid Howells 	c_namesz = strlen(op->create.symlink);
874260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
875260a9803SDavid Howells 
876260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
877260a9803SDavid Howells 
878e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz,
879260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
880260a9803SDavid Howells 	if (!call)
881e49c7b2fSDavid Howells 		return afs_op_nomem(op);
882260a9803SDavid Howells 
883260a9803SDavid Howells 	/* marshall the parameters */
884260a9803SDavid Howells 	bp = call->request;
885260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
886e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
887e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
888e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
889260a9803SDavid Howells 	*bp++ = htonl(namesz);
890e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
891260a9803SDavid Howells 	bp = (void *) bp + namesz;
892260a9803SDavid Howells 	if (padsz > 0) {
893260a9803SDavid Howells 		memset(bp, 0, padsz);
894260a9803SDavid Howells 		bp = (void *) bp + padsz;
895260a9803SDavid Howells 	}
896260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
897e49c7b2fSDavid Howells 	memcpy(bp, op->create.symlink, c_namesz);
898260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
899260a9803SDavid Howells 	if (c_padsz > 0) {
900260a9803SDavid Howells 		memset(bp, 0, c_padsz);
901260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
902260a9803SDavid Howells 	}
903ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
904e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
905260a9803SDavid Howells 	*bp++ = 0; /* owner */
906260a9803SDavid Howells 	*bp++ = 0; /* group */
907260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
908260a9803SDavid Howells 	*bp++ = 0; /* segment size */
909260a9803SDavid Howells 
910e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
911e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
912260a9803SDavid Howells }
913260a9803SDavid Howells 
914260a9803SDavid Howells /*
915260a9803SDavid Howells  * deliver reply data to an FS.Rename
916260a9803SDavid Howells  */
afs_deliver_fs_rename(struct afs_call * call)917d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
918260a9803SDavid Howells {
919e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
920e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
921e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
922260a9803SDavid Howells 	const __be32 *bp;
923372ee163SDavid Howells 	int ret;
924260a9803SDavid Howells 
925d001648eSDavid Howells 	ret = afs_transfer_reply(call);
926372ee163SDavid Howells 	if (ret < 0)
927372ee163SDavid Howells 		return ret;
928260a9803SDavid Howells 
92938355eecSDavid Howells 	bp = call->buffer;
930b98f0ec9SDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
931b98f0ec9SDavid Howells 	 * report, so we just decode it twice.
932b98f0ec9SDavid Howells 	 */
933e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb);
934e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb);
935e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
936260a9803SDavid Howells 
937260a9803SDavid Howells 	_leave(" = 0 [done]");
938260a9803SDavid Howells 	return 0;
939260a9803SDavid Howells }
940260a9803SDavid Howells 
941260a9803SDavid Howells /*
942260a9803SDavid Howells  * FS.Rename operation type
943260a9803SDavid Howells  */
944260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
945260a9803SDavid Howells 	.name		= "FS.Rename",
946025db80cSDavid Howells 	.op		= afs_FS_Rename,
947260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
948260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
949260a9803SDavid Howells };
950260a9803SDavid Howells 
951260a9803SDavid Howells /*
952a58823acSDavid Howells  * Rename/move a file or directory.
953260a9803SDavid Howells  */
afs_fs_rename(struct afs_operation * op)954e49c7b2fSDavid Howells void afs_fs_rename(struct afs_operation *op)
955260a9803SDavid Howells {
956e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
957e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
958e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
959e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
960260a9803SDavid Howells 	struct afs_call *call;
961260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
962260a9803SDavid Howells 	__be32 *bp;
963260a9803SDavid Howells 
964260a9803SDavid Howells 	_enter("");
965260a9803SDavid Howells 
966e49c7b2fSDavid Howells 	o_namesz = orig_name->len;
967260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
968260a9803SDavid Howells 
969e49c7b2fSDavid Howells 	n_namesz = new_name->len;
970260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
971260a9803SDavid Howells 
972260a9803SDavid Howells 	reqsz = (4 * 4) +
973260a9803SDavid Howells 		4 + o_namesz + o_padsz +
974260a9803SDavid Howells 		(3 * 4) +
975260a9803SDavid Howells 		4 + n_namesz + n_padsz;
976260a9803SDavid Howells 
977e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
978260a9803SDavid Howells 	if (!call)
979e49c7b2fSDavid Howells 		return afs_op_nomem(op);
980260a9803SDavid Howells 
981260a9803SDavid Howells 	/* marshall the parameters */
982260a9803SDavid Howells 	bp = call->request;
983260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
984e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vid);
985e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vnode);
986e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.unique);
987260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
988e49c7b2fSDavid Howells 	memcpy(bp, orig_name->name, o_namesz);
989260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
990260a9803SDavid Howells 	if (o_padsz > 0) {
991260a9803SDavid Howells 		memset(bp, 0, o_padsz);
992260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
993260a9803SDavid Howells 	}
994260a9803SDavid Howells 
995e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vid);
996e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vnode);
997e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.unique);
998260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
999e49c7b2fSDavid Howells 	memcpy(bp, new_name->name, n_namesz);
1000260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1001260a9803SDavid Howells 	if (n_padsz > 0) {
1002260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1003260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1004260a9803SDavid Howells 	}
1005260a9803SDavid Howells 
1006e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1007e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1008260a9803SDavid Howells }
100931143d5dSDavid Howells 
101031143d5dSDavid Howells /*
1011e49c7b2fSDavid Howells  * Deliver reply data to FS.StoreData or FS.StoreStatus
101231143d5dSDavid Howells  */
afs_deliver_fs_store_data(struct afs_call * call)1013d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
101431143d5dSDavid Howells {
1015e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1016e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
101731143d5dSDavid Howells 	const __be32 *bp;
1018372ee163SDavid Howells 	int ret;
101931143d5dSDavid Howells 
1020d001648eSDavid Howells 	_enter("");
102131143d5dSDavid Howells 
1022d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1023372ee163SDavid Howells 	if (ret < 0)
1024372ee163SDavid Howells 		return ret;
102531143d5dSDavid Howells 
102631143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
102731143d5dSDavid Howells 	bp = call->buffer;
1028e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
1029e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
103031143d5dSDavid Howells 
103131143d5dSDavid Howells 	_leave(" = 0 [done]");
103231143d5dSDavid Howells 	return 0;
103331143d5dSDavid Howells }
103431143d5dSDavid Howells 
103531143d5dSDavid Howells /*
103631143d5dSDavid Howells  * FS.StoreData operation type
103731143d5dSDavid Howells  */
103831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
103931143d5dSDavid Howells 	.name		= "FS.StoreData",
1040025db80cSDavid Howells 	.op		= afs_FS_StoreData,
104131143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
104231143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
104331143d5dSDavid Howells };
104431143d5dSDavid Howells 
1045b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1046b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1047025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1048b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1049b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1050b9b1f8d5SDavid Howells };
1051b9b1f8d5SDavid Howells 
1052b9b1f8d5SDavid Howells /*
1053b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1054b9b1f8d5SDavid Howells  */
afs_fs_store_data64(struct afs_operation * op)1055bd80d8a8SDavid Howells static void afs_fs_store_data64(struct afs_operation *op)
1056b9b1f8d5SDavid Howells {
1057e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1058b9b1f8d5SDavid Howells 	struct afs_call *call;
1059b9b1f8d5SDavid Howells 	__be32 *bp;
1060b9b1f8d5SDavid Howells 
10613b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1062e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1063b9b1f8d5SDavid Howells 
1064e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64,
1065b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1066b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1067b9b1f8d5SDavid Howells 	if (!call)
1068e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1069b9b1f8d5SDavid Howells 
1070bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
1071b9b1f8d5SDavid Howells 
1072b9b1f8d5SDavid Howells 	/* marshall the parameters */
1073b9b1f8d5SDavid Howells 	bp = call->request;
1074b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1075e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1076e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1077e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1078b9b1f8d5SDavid Howells 
1079ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1080e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
1081b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1082b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1083b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1084b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1085b9b1f8d5SDavid Howells 
1086bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.pos));
1087bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.pos));
1088bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.size));
1089bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.size));
1090bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.i_size));
1091bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.i_size));
1092b9b1f8d5SDavid Howells 
1093e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1094e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1095b9b1f8d5SDavid Howells }
1096b9b1f8d5SDavid Howells 
109731143d5dSDavid Howells /*
1098bd80d8a8SDavid Howells  * Write data to a file on the server.
109931143d5dSDavid Howells  */
afs_fs_store_data(struct afs_operation * op)1100e49c7b2fSDavid Howells void afs_fs_store_data(struct afs_operation *op)
110131143d5dSDavid Howells {
1102e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
110331143d5dSDavid Howells 	struct afs_call *call;
110431143d5dSDavid Howells 	__be32 *bp;
110531143d5dSDavid Howells 
11063b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1107e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
110831143d5dSDavid Howells 
110931143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
1110bd80d8a8SDavid Howells 	       (unsigned long long)op->store.size,
1111bd80d8a8SDavid Howells 	       (unsigned long long)op->store.pos,
1112bd80d8a8SDavid Howells 	       (unsigned long long)op->store.i_size);
111331143d5dSDavid Howells 
1114b537a3c2SDavid Howells 	if (test_bit(AFS_SERVER_FL_HAS_FS64, &op->server->flags))
1115bd80d8a8SDavid Howells 		return afs_fs_store_data64(op);
111631143d5dSDavid Howells 
1117e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData,
111831143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
111931143d5dSDavid Howells 				   (21 + 6) * 4);
112031143d5dSDavid Howells 	if (!call)
1121e49c7b2fSDavid Howells 		return afs_op_nomem(op);
112231143d5dSDavid Howells 
1123bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
112431143d5dSDavid Howells 
112531143d5dSDavid Howells 	/* marshall the parameters */
112631143d5dSDavid Howells 	bp = call->request;
112731143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1128e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1129e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1130e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
113131143d5dSDavid Howells 
1132ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1133e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
113431143d5dSDavid Howells 	*bp++ = 0; /* owner */
113531143d5dSDavid Howells 	*bp++ = 0; /* group */
113631143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
113731143d5dSDavid Howells 	*bp++ = 0; /* segment size */
113831143d5dSDavid Howells 
1139bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.pos));
1140bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.size));
1141bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.i_size));
114231143d5dSDavid Howells 
1143e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1144e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
114531143d5dSDavid Howells }
114631143d5dSDavid Howells 
114731143d5dSDavid Howells /*
114831143d5dSDavid Howells  * FS.StoreStatus operation type
114931143d5dSDavid Howells  */
115031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
115131143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1152025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
1153e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
115431143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
115531143d5dSDavid Howells };
115631143d5dSDavid Howells 
115731143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
115831143d5dSDavid Howells 	.name		= "FS.StoreData",
1159025db80cSDavid Howells 	.op		= afs_FS_StoreData,
1160e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
116131143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
116231143d5dSDavid Howells };
116331143d5dSDavid Howells 
1164b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1165b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1166025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1167e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1168b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1169b9b1f8d5SDavid Howells };
1170b9b1f8d5SDavid Howells 
1171b9b1f8d5SDavid Howells /*
1172b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1173b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1174b9b1f8d5SDavid Howells  */
afs_fs_setattr_size64(struct afs_operation * op)1175e49c7b2fSDavid Howells static void afs_fs_setattr_size64(struct afs_operation *op)
1176b9b1f8d5SDavid Howells {
1177e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1178b9b1f8d5SDavid Howells 	struct afs_call *call;
1179e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
1180b9b1f8d5SDavid Howells 	__be32 *bp;
1181b9b1f8d5SDavid Howells 
11823b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1183e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1184b9b1f8d5SDavid Howells 
1185b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1186b9b1f8d5SDavid Howells 
1187e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status,
1188b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1189b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1190b9b1f8d5SDavid Howells 	if (!call)
1191e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1192b9b1f8d5SDavid Howells 
1193b9b1f8d5SDavid Howells 	/* marshall the parameters */
1194b9b1f8d5SDavid Howells 	bp = call->request;
1195b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1196e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1197e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1198e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1199b9b1f8d5SDavid Howells 
1200b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1201b9b1f8d5SDavid Howells 
1202e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* position of start of write */
1203e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1204b9b1f8d5SDavid Howells 	*bp++ = 0;					/* size of write */
1205b9b1f8d5SDavid Howells 	*bp++ = 0;
1206e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* new file length */
1207e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1208b9b1f8d5SDavid Howells 
1209e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1210e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1211b9b1f8d5SDavid Howells }
1212b9b1f8d5SDavid Howells 
121331143d5dSDavid Howells /*
121431143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
121531143d5dSDavid Howells  * so as to alter the file size also
121631143d5dSDavid Howells  */
afs_fs_setattr_size(struct afs_operation * op)1217e49c7b2fSDavid Howells static void afs_fs_setattr_size(struct afs_operation *op)
121831143d5dSDavid Howells {
1219e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
122031143d5dSDavid Howells 	struct afs_call *call;
1221e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
122231143d5dSDavid Howells 	__be32 *bp;
122331143d5dSDavid Howells 
12243b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1225e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
122631143d5dSDavid Howells 
122731143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1228b537a3c2SDavid Howells 	if (test_bit(AFS_SERVER_FL_HAS_FS64, &op->server->flags))
1229e49c7b2fSDavid Howells 		return afs_fs_setattr_size64(op);
123031143d5dSDavid Howells 
1231e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status,
123231143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
123331143d5dSDavid Howells 				   (21 + 6) * 4);
123431143d5dSDavid Howells 	if (!call)
1235e49c7b2fSDavid Howells 		return afs_op_nomem(op);
123631143d5dSDavid Howells 
123731143d5dSDavid Howells 	/* marshall the parameters */
123831143d5dSDavid Howells 	bp = call->request;
123931143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1240e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1241e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1242e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
124331143d5dSDavid Howells 
124431143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
124531143d5dSDavid Howells 
12468c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
124731143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
124831143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
124931143d5dSDavid Howells 
1250e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1251e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
125231143d5dSDavid Howells }
125331143d5dSDavid Howells 
125431143d5dSDavid Howells /*
125531143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
125631143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
125731143d5dSDavid Howells  */
afs_fs_setattr(struct afs_operation * op)1258e49c7b2fSDavid Howells void afs_fs_setattr(struct afs_operation *op)
125931143d5dSDavid Howells {
1260e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
126131143d5dSDavid Howells 	struct afs_call *call;
1262e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
126331143d5dSDavid Howells 	__be32 *bp;
126431143d5dSDavid Howells 
126531143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1266e49c7b2fSDavid Howells 		return afs_fs_setattr_size(op);
126731143d5dSDavid Howells 
12683b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1269e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
127031143d5dSDavid Howells 
1271e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus,
127231143d5dSDavid Howells 				   (4 + 6) * 4,
127331143d5dSDavid Howells 				   (21 + 6) * 4);
127431143d5dSDavid Howells 	if (!call)
1275e49c7b2fSDavid Howells 		return afs_op_nomem(op);
127631143d5dSDavid Howells 
127731143d5dSDavid Howells 	/* marshall the parameters */
127831143d5dSDavid Howells 	bp = call->request;
127931143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
1280e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1281e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1282e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
128331143d5dSDavid Howells 
1284e49c7b2fSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr);
128531143d5dSDavid Howells 
1286e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1287e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
128831143d5dSDavid Howells }
128945222b9eSDavid Howells 
129045222b9eSDavid Howells /*
129145222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
129245222b9eSDavid Howells  */
afs_deliver_fs_get_volume_status(struct afs_call * call)1293d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
129445222b9eSDavid Howells {
1295e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
129645222b9eSDavid Howells 	const __be32 *bp;
129745222b9eSDavid Howells 	char *p;
129812bdcf33SDavid Howells 	u32 size;
129945222b9eSDavid Howells 	int ret;
130045222b9eSDavid Howells 
1301d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
130245222b9eSDavid Howells 
130345222b9eSDavid Howells 	switch (call->unmarshall) {
130445222b9eSDavid Howells 	case 0:
130545222b9eSDavid Howells 		call->unmarshall++;
130612bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
1307df561f66SGustavo A. R. Silva 		fallthrough;
130845222b9eSDavid Howells 
130929881608SGustavo A. R. Silva 		/* extract the returned status record */
131045222b9eSDavid Howells 	case 1:
131145222b9eSDavid Howells 		_debug("extract status");
131212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1313372ee163SDavid Howells 		if (ret < 0)
1314372ee163SDavid Howells 			return ret;
131545222b9eSDavid Howells 
131645222b9eSDavid Howells 		bp = call->buffer;
1317e49c7b2fSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs);
131845222b9eSDavid Howells 		call->unmarshall++;
131912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1320df561f66SGustavo A. R. Silva 		fallthrough;
132145222b9eSDavid Howells 
132229881608SGustavo A. R. Silva 		/* extract the volume name length */
132345222b9eSDavid Howells 	case 2:
132412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1325372ee163SDavid Howells 		if (ret < 0)
1326372ee163SDavid Howells 			return ret;
132745222b9eSDavid Howells 
132845222b9eSDavid Howells 		call->count = ntohl(call->tmp);
132945222b9eSDavid Howells 		_debug("volname length: %u", call->count);
133045222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13317126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
133212bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1333ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
133445222b9eSDavid Howells 		call->unmarshall++;
1335df561f66SGustavo A. R. Silva 		fallthrough;
133645222b9eSDavid Howells 
133729881608SGustavo A. R. Silva 		/* extract the volume name */
133845222b9eSDavid Howells 	case 3:
133945222b9eSDavid Howells 		_debug("extract volname");
134012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1341372ee163SDavid Howells 		if (ret < 0)
1342372ee163SDavid Howells 			return ret;
134345222b9eSDavid Howells 
1344ffba718eSDavid Howells 		p = call->buffer;
134545222b9eSDavid Howells 		p[call->count] = 0;
134645222b9eSDavid Howells 		_debug("volname '%s'", p);
134712bdcf33SDavid Howells 		afs_extract_to_tmp(call);
134845222b9eSDavid Howells 		call->unmarshall++;
1349df561f66SGustavo A. R. Silva 		fallthrough;
135045222b9eSDavid Howells 
135129881608SGustavo A. R. Silva 		/* extract the offline message length */
135212bdcf33SDavid Howells 	case 4:
135312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1354372ee163SDavid Howells 		if (ret < 0)
1355372ee163SDavid Howells 			return ret;
135645222b9eSDavid Howells 
135745222b9eSDavid Howells 		call->count = ntohl(call->tmp);
135845222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
135945222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13607126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
136112bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1362ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
136345222b9eSDavid Howells 		call->unmarshall++;
1364df561f66SGustavo A. R. Silva 		fallthrough;
136545222b9eSDavid Howells 
136629881608SGustavo A. R. Silva 		/* extract the offline message */
136712bdcf33SDavid Howells 	case 5:
136845222b9eSDavid Howells 		_debug("extract offline");
136912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1370372ee163SDavid Howells 		if (ret < 0)
1371372ee163SDavid Howells 			return ret;
137245222b9eSDavid Howells 
1373ffba718eSDavid Howells 		p = call->buffer;
137445222b9eSDavid Howells 		p[call->count] = 0;
137545222b9eSDavid Howells 		_debug("offline '%s'", p);
137645222b9eSDavid Howells 
137712bdcf33SDavid Howells 		afs_extract_to_tmp(call);
137845222b9eSDavid Howells 		call->unmarshall++;
1379df561f66SGustavo A. R. Silva 		fallthrough;
138045222b9eSDavid Howells 
138129881608SGustavo A. R. Silva 		/* extract the message of the day length */
138212bdcf33SDavid Howells 	case 6:
138312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1384372ee163SDavid Howells 		if (ret < 0)
1385372ee163SDavid Howells 			return ret;
138645222b9eSDavid Howells 
138745222b9eSDavid Howells 		call->count = ntohl(call->tmp);
138845222b9eSDavid Howells 		_debug("motd length: %u", call->count);
138945222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13907126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
139112bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1392ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
139345222b9eSDavid Howells 		call->unmarshall++;
1394df561f66SGustavo A. R. Silva 		fallthrough;
139545222b9eSDavid Howells 
139629881608SGustavo A. R. Silva 		/* extract the message of the day */
139712bdcf33SDavid Howells 	case 7:
139845222b9eSDavid Howells 		_debug("extract motd");
139912bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1400372ee163SDavid Howells 		if (ret < 0)
1401372ee163SDavid Howells 			return ret;
140245222b9eSDavid Howells 
1403ffba718eSDavid Howells 		p = call->buffer;
140445222b9eSDavid Howells 		p[call->count] = 0;
140545222b9eSDavid Howells 		_debug("motd '%s'", p);
140645222b9eSDavid Howells 
140745222b9eSDavid Howells 		call->unmarshall++;
1408b2db6c35SGustavo A. R. Silva 		fallthrough;
140945222b9eSDavid Howells 
141012bdcf33SDavid Howells 	case 8:
141145222b9eSDavid Howells 		break;
141245222b9eSDavid Howells 	}
141345222b9eSDavid Howells 
141445222b9eSDavid Howells 	_leave(" = 0 [done]");
141545222b9eSDavid Howells 	return 0;
141645222b9eSDavid Howells }
141745222b9eSDavid Howells 
141845222b9eSDavid Howells /*
141945222b9eSDavid Howells  * FS.GetVolumeStatus operation type
142045222b9eSDavid Howells  */
142145222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
142245222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1423025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
142445222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1425ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
142645222b9eSDavid Howells };
142745222b9eSDavid Howells 
142845222b9eSDavid Howells /*
142945222b9eSDavid Howells  * fetch the status of a volume
143045222b9eSDavid Howells  */
afs_fs_get_volume_status(struct afs_operation * op)1431e49c7b2fSDavid Howells void afs_fs_get_volume_status(struct afs_operation *op)
143245222b9eSDavid Howells {
1433e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
143445222b9eSDavid Howells 	struct afs_call *call;
143545222b9eSDavid Howells 	__be32 *bp;
143645222b9eSDavid Howells 
143745222b9eSDavid Howells 	_enter("");
143845222b9eSDavid Howells 
1439e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4,
1440ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1441ffba718eSDavid Howells 	if (!call)
1442e49c7b2fSDavid Howells 		return afs_op_nomem(op);
144345222b9eSDavid Howells 
144445222b9eSDavid Howells 	/* marshall the parameters */
144545222b9eSDavid Howells 	bp = call->request;
144645222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
1447e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
144845222b9eSDavid Howells 
1449e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1450e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
145145222b9eSDavid Howells }
1452e8d6c554SDavid Howells 
1453e8d6c554SDavid Howells /*
1454e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1455e8d6c554SDavid Howells  */
afs_deliver_fs_xxxx_lock(struct afs_call * call)1456d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1457e8d6c554SDavid Howells {
1458e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1459e8d6c554SDavid Howells 	const __be32 *bp;
1460372ee163SDavid Howells 	int ret;
1461e8d6c554SDavid Howells 
1462d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1463e8d6c554SDavid Howells 
1464d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1465372ee163SDavid Howells 	if (ret < 0)
1466372ee163SDavid Howells 		return ret;
1467e8d6c554SDavid Howells 
1468e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1469e8d6c554SDavid Howells 	bp = call->buffer;
1470e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
1471e8d6c554SDavid Howells 
1472e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1473e8d6c554SDavid Howells 	return 0;
1474e8d6c554SDavid Howells }
1475e8d6c554SDavid Howells 
1476e8d6c554SDavid Howells /*
1477e8d6c554SDavid Howells  * FS.SetLock operation type
1478e8d6c554SDavid Howells  */
1479e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1480e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1481025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1482e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1483a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1484e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1485e8d6c554SDavid Howells };
1486e8d6c554SDavid Howells 
1487e8d6c554SDavid Howells /*
1488e8d6c554SDavid Howells  * FS.ExtendLock operation type
1489e8d6c554SDavid Howells  */
1490e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1491e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1492025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1493e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1494a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1495e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1496e8d6c554SDavid Howells };
1497e8d6c554SDavid Howells 
1498e8d6c554SDavid Howells /*
1499e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1500e8d6c554SDavid Howells  */
1501e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1502e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1503025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1504e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1505e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1506e8d6c554SDavid Howells };
1507e8d6c554SDavid Howells 
1508e8d6c554SDavid Howells /*
1509d2ddc776SDavid Howells  * Set a lock on a file
1510e8d6c554SDavid Howells  */
afs_fs_set_lock(struct afs_operation * op)1511e49c7b2fSDavid Howells void afs_fs_set_lock(struct afs_operation *op)
1512e8d6c554SDavid Howells {
1513e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1514e8d6c554SDavid Howells 	struct afs_call *call;
1515e8d6c554SDavid Howells 	__be32 *bp;
1516e8d6c554SDavid Howells 
1517e8d6c554SDavid Howells 	_enter("");
1518e8d6c554SDavid Howells 
1519e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1520e8d6c554SDavid Howells 	if (!call)
1521e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1522e8d6c554SDavid Howells 
1523e8d6c554SDavid Howells 	/* marshall the parameters */
1524e8d6c554SDavid Howells 	bp = call->request;
1525e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1526e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1527e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1528e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1529e49c7b2fSDavid Howells 	*bp++ = htonl(op->lock.type);
1530e8d6c554SDavid Howells 
1531e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1532e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1533e8d6c554SDavid Howells }
1534e8d6c554SDavid Howells 
1535e8d6c554SDavid Howells /*
1536e8d6c554SDavid Howells  * extend a lock on a file
1537e8d6c554SDavid Howells  */
afs_fs_extend_lock(struct afs_operation * op)1538e49c7b2fSDavid Howells void afs_fs_extend_lock(struct afs_operation *op)
1539e8d6c554SDavid Howells {
1540e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1541e8d6c554SDavid Howells 	struct afs_call *call;
1542e8d6c554SDavid Howells 	__be32 *bp;
1543e8d6c554SDavid Howells 
1544e8d6c554SDavid Howells 	_enter("");
1545e8d6c554SDavid Howells 
1546e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1547e8d6c554SDavid Howells 	if (!call)
1548e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1549e8d6c554SDavid Howells 
1550e8d6c554SDavid Howells 	/* marshall the parameters */
1551e8d6c554SDavid Howells 	bp = call->request;
1552e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1553e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1554e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1555e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1556e8d6c554SDavid Howells 
1557e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1558e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1559e8d6c554SDavid Howells }
1560e8d6c554SDavid Howells 
1561e8d6c554SDavid Howells /*
1562e8d6c554SDavid Howells  * release a lock on a file
1563e8d6c554SDavid Howells  */
afs_fs_release_lock(struct afs_operation * op)1564e49c7b2fSDavid Howells void afs_fs_release_lock(struct afs_operation *op)
1565e8d6c554SDavid Howells {
1566e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1567e8d6c554SDavid Howells 	struct afs_call *call;
1568e8d6c554SDavid Howells 	__be32 *bp;
1569e8d6c554SDavid Howells 
1570e8d6c554SDavid Howells 	_enter("");
1571e8d6c554SDavid Howells 
1572e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1573e8d6c554SDavid Howells 	if (!call)
1574e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1575e8d6c554SDavid Howells 
1576e8d6c554SDavid Howells 	/* marshall the parameters */
1577e8d6c554SDavid Howells 	bp = call->request;
1578e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1579e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1580e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1581e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1582e8d6c554SDavid Howells 
1583e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1584e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1585c435ee34SDavid Howells }
1586c435ee34SDavid Howells 
1587c435ee34SDavid Howells /*
1588c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1589c435ee34SDavid Howells  */
afs_deliver_fs_give_up_all_callbacks(struct afs_call * call)1590c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1591c435ee34SDavid Howells {
1592c435ee34SDavid Howells 	return afs_transfer_reply(call);
1593c435ee34SDavid Howells }
1594c435ee34SDavid Howells 
1595c435ee34SDavid Howells /*
1596c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1597c435ee34SDavid Howells  */
1598c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1599c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1600025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1601c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1602c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1603c435ee34SDavid Howells };
1604c435ee34SDavid Howells 
1605c435ee34SDavid Howells /*
1606c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1607c435ee34SDavid Howells  */
afs_fs_give_up_all_callbacks(struct afs_net * net,struct afs_server * server,struct afs_addr_cursor * ac,struct key * key)1608d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1609d2ddc776SDavid Howells 				 struct afs_server *server,
16108b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1611d2ddc776SDavid Howells 				 struct key *key)
1612c435ee34SDavid Howells {
1613c435ee34SDavid Howells 	struct afs_call *call;
1614c435ee34SDavid Howells 	__be32 *bp;
1615c435ee34SDavid Howells 
1616c435ee34SDavid Howells 	_enter("");
1617c435ee34SDavid Howells 
1618d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1619c435ee34SDavid Howells 	if (!call)
1620c435ee34SDavid Howells 		return -ENOMEM;
1621c435ee34SDavid Howells 
1622c435ee34SDavid Howells 	call->key = key;
1623c435ee34SDavid Howells 
1624c435ee34SDavid Howells 	/* marshall the parameters */
1625c435ee34SDavid Howells 	bp = call->request;
1626c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1627c435ee34SDavid Howells 
1628977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_give_up_cb);
16290b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
16300b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1631d2ddc776SDavid Howells }
1632d2ddc776SDavid Howells 
1633d2ddc776SDavid Howells /*
1634d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1635d2ddc776SDavid Howells  */
afs_deliver_fs_get_capabilities(struct afs_call * call)1636d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1637d2ddc776SDavid Howells {
1638d2ddc776SDavid Howells 	u32 count;
1639d2ddc776SDavid Howells 	int ret;
1640d2ddc776SDavid Howells 
1641fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1642d2ddc776SDavid Howells 
1643d2ddc776SDavid Howells 	switch (call->unmarshall) {
1644d2ddc776SDavid Howells 	case 0:
164512bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1646d2ddc776SDavid Howells 		call->unmarshall++;
1647df561f66SGustavo A. R. Silva 		fallthrough;
1648d2ddc776SDavid Howells 
164929881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1650d2ddc776SDavid Howells 	case 1:
165112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1652d2ddc776SDavid Howells 		if (ret < 0)
1653d2ddc776SDavid Howells 			return ret;
1654d2ddc776SDavid Howells 
1655d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1656d2ddc776SDavid Howells 		call->count = count;
1657d2ddc776SDavid Howells 		call->count2 = count;
1658b537a3c2SDavid Howells 		if (count == 0) {
1659b537a3c2SDavid Howells 			call->unmarshall = 4;
1660b537a3c2SDavid Howells 			call->tmp = 0;
1661b537a3c2SDavid Howells 			break;
1662b537a3c2SDavid Howells 		}
1663b537a3c2SDavid Howells 
1664b537a3c2SDavid Howells 		/* Extract the first word of the capabilities to call->tmp */
1665b537a3c2SDavid Howells 		afs_extract_to_tmp(call);
1666d2ddc776SDavid Howells 		call->unmarshall++;
1667df561f66SGustavo A. R. Silva 		fallthrough;
1668d2ddc776SDavid Howells 
1669d2ddc776SDavid Howells 	case 2:
167012bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1671d2ddc776SDavid Howells 		if (ret < 0)
1672d2ddc776SDavid Howells 			return ret;
1673d2ddc776SDavid Howells 
1674b537a3c2SDavid Howells 		afs_extract_discard(call, (count - 1) * sizeof(__be32));
1675b537a3c2SDavid Howells 		call->unmarshall++;
1676b537a3c2SDavid Howells 		fallthrough;
1677b537a3c2SDavid Howells 
1678b537a3c2SDavid Howells 		/* Extract remaining capabilities words */
1679b537a3c2SDavid Howells 	case 3:
1680b537a3c2SDavid Howells 		ret = afs_extract_data(call, false);
1681b537a3c2SDavid Howells 		if (ret < 0)
1682b537a3c2SDavid Howells 			return ret;
1683d2ddc776SDavid Howells 
1684d2ddc776SDavid Howells 		call->unmarshall++;
1685d2ddc776SDavid Howells 		break;
1686d2ddc776SDavid Howells 	}
1687d2ddc776SDavid Howells 
1688d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1689d2ddc776SDavid Howells 	return 0;
1690d2ddc776SDavid Howells }
1691d2ddc776SDavid Howells 
1692d2ddc776SDavid Howells /*
1693d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1694d2ddc776SDavid Howells  */
1695d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1696d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1697025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1698d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
16993bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1700ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1701d2ddc776SDavid Howells };
1702d2ddc776SDavid Howells 
1703d2ddc776SDavid Howells /*
1704f6cbb368SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This RPC can
1705f6cbb368SDavid Howells  * reply with up to 196 words.  The operation is asynchronous and if we managed
1706f6cbb368SDavid Howells  * to allocate a call, true is returned the result is delivered through the
1707f6cbb368SDavid Howells  * ->done() - otherwise we return false to indicate we didn't even try.
1708d2ddc776SDavid Howells  */
afs_fs_get_capabilities(struct afs_net * net,struct afs_server * server,struct afs_addr_cursor * ac,struct key * key)1709f6cbb368SDavid Howells bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
1710f6cbb368SDavid Howells 			     struct afs_addr_cursor *ac, struct key *key)
1711d2ddc776SDavid Howells {
1712d2ddc776SDavid Howells 	struct afs_call *call;
1713d2ddc776SDavid Howells 	__be32 *bp;
1714d2ddc776SDavid Howells 
1715d2ddc776SDavid Howells 	_enter("");
1716d2ddc776SDavid Howells 
1717d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1718d2ddc776SDavid Howells 	if (!call)
1719f6cbb368SDavid Howells 		return false;
1720d2ddc776SDavid Howells 
1721d2ddc776SDavid Howells 	call->key = key;
1722977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_get_caps);
172330062bd1SDavid Howells 	call->upgrade = true;
17240b9bf381SDavid Howells 	call->async = true;
172594f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1726d2ddc776SDavid Howells 
1727d2ddc776SDavid Howells 	/* marshall the parameters */
1728d2ddc776SDavid Howells 	bp = call->request;
1729d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1730d2ddc776SDavid Howells 
1731025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
17320b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
1733f6cbb368SDavid Howells 	afs_put_call(call);
1734f6cbb368SDavid Howells 	return true;
1735e8d6c554SDavid Howells }
17365cf9dd55SDavid Howells 
17375cf9dd55SDavid Howells /*
17385cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
17395cf9dd55SDavid Howells  */
afs_deliver_fs_inline_bulk_status(struct afs_call * call)17405cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
17415cf9dd55SDavid Howells {
1742e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
174387182759SDavid Howells 	struct afs_status_cb *scb;
17445cf9dd55SDavid Howells 	const __be32 *bp;
17455cf9dd55SDavid Howells 	u32 tmp;
17465cf9dd55SDavid Howells 	int ret;
17475cf9dd55SDavid Howells 
17485cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
17495cf9dd55SDavid Howells 
17505cf9dd55SDavid Howells 	switch (call->unmarshall) {
17515cf9dd55SDavid Howells 	case 0:
175212bdcf33SDavid Howells 		afs_extract_to_tmp(call);
17535cf9dd55SDavid Howells 		call->unmarshall++;
1754df561f66SGustavo A. R. Silva 		fallthrough;
17555cf9dd55SDavid Howells 
17565cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
17575cf9dd55SDavid Howells 	case 1:
17585cf9dd55SDavid Howells 		_debug("extract status count");
175912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17605cf9dd55SDavid Howells 		if (ret < 0)
17615cf9dd55SDavid Howells 			return ret;
17625cf9dd55SDavid Howells 
17635cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
1764e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1765e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
17667126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
17675cf9dd55SDavid Howells 
17685cf9dd55SDavid Howells 		call->count = 0;
17695cf9dd55SDavid Howells 		call->unmarshall++;
17705cf9dd55SDavid Howells 	more_counts:
177112bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
1772df561f66SGustavo A. R. Silva 		fallthrough;
177329881608SGustavo A. R. Silva 
17745cf9dd55SDavid Howells 	case 2:
17755cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
177612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17775cf9dd55SDavid Howells 		if (ret < 0)
17785cf9dd55SDavid Howells 			return ret;
17795cf9dd55SDavid Howells 
1780e49c7b2fSDavid Howells 		switch (call->count) {
1781e49c7b2fSDavid Howells 		case 0:
1782e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1783e49c7b2fSDavid Howells 			break;
1784e49c7b2fSDavid Howells 		case 1:
1785e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1786e49c7b2fSDavid Howells 			break;
1787e49c7b2fSDavid Howells 		default:
1788e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1789e49c7b2fSDavid Howells 			break;
1790e49c7b2fSDavid Howells 		}
1791e49c7b2fSDavid Howells 
17925cf9dd55SDavid Howells 		bp = call->buffer;
179338355eecSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, scb);
1794e49c7b2fSDavid Howells 
17955cf9dd55SDavid Howells 		call->count++;
1796e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
17975cf9dd55SDavid Howells 			goto more_counts;
17985cf9dd55SDavid Howells 
17995cf9dd55SDavid Howells 		call->count = 0;
18005cf9dd55SDavid Howells 		call->unmarshall++;
180112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1802df561f66SGustavo A. R. Silva 		fallthrough;
18035cf9dd55SDavid Howells 
18045cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
18055cf9dd55SDavid Howells 	case 3:
18065cf9dd55SDavid Howells 		_debug("extract CB count");
180712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18085cf9dd55SDavid Howells 		if (ret < 0)
18095cf9dd55SDavid Howells 			return ret;
18105cf9dd55SDavid Howells 
18115cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
18125cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
1813e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
18147126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
18155cf9dd55SDavid Howells 		call->count = 0;
18165cf9dd55SDavid Howells 		call->unmarshall++;
18175cf9dd55SDavid Howells 	more_cbs:
181812bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
1819df561f66SGustavo A. R. Silva 		fallthrough;
182029881608SGustavo A. R. Silva 
18215cf9dd55SDavid Howells 	case 4:
18225cf9dd55SDavid Howells 		_debug("extract CB array");
182312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18245cf9dd55SDavid Howells 		if (ret < 0)
18255cf9dd55SDavid Howells 			return ret;
18265cf9dd55SDavid Howells 
18275cf9dd55SDavid Howells 		_debug("unmarshall CB array");
1828e49c7b2fSDavid Howells 		switch (call->count) {
1829e49c7b2fSDavid Howells 		case 0:
1830e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1831e49c7b2fSDavid Howells 			break;
1832e49c7b2fSDavid Howells 		case 1:
1833e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1834e49c7b2fSDavid Howells 			break;
1835e49c7b2fSDavid Howells 		default:
1836e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1837e49c7b2fSDavid Howells 			break;
1838e49c7b2fSDavid Howells 		}
1839e49c7b2fSDavid Howells 
18405cf9dd55SDavid Howells 		bp = call->buffer;
1841a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
18425cf9dd55SDavid Howells 		call->count++;
1843e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
18445cf9dd55SDavid Howells 			goto more_cbs;
18455cf9dd55SDavid Howells 
184612bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
18475cf9dd55SDavid Howells 		call->unmarshall++;
1848df561f66SGustavo A. R. Silva 		fallthrough;
184929881608SGustavo A. R. Silva 
18505cf9dd55SDavid Howells 	case 5:
185112bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
18525cf9dd55SDavid Howells 		if (ret < 0)
18535cf9dd55SDavid Howells 			return ret;
18545cf9dd55SDavid Howells 
18555cf9dd55SDavid Howells 		bp = call->buffer;
1856e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
18575cf9dd55SDavid Howells 
18585cf9dd55SDavid Howells 		call->unmarshall++;
1859b2db6c35SGustavo A. R. Silva 		fallthrough;
18605cf9dd55SDavid Howells 
18615cf9dd55SDavid Howells 	case 6:
18625cf9dd55SDavid Howells 		break;
18635cf9dd55SDavid Howells 	}
18645cf9dd55SDavid Howells 
18655cf9dd55SDavid Howells 	_leave(" = 0 [done]");
18665cf9dd55SDavid Howells 	return 0;
18675cf9dd55SDavid Howells }
18685cf9dd55SDavid Howells 
afs_done_fs_inline_bulk_status(struct afs_call * call)1869e49c7b2fSDavid Howells static void afs_done_fs_inline_bulk_status(struct afs_call *call)
1870e49c7b2fSDavid Howells {
1871e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
187220325960SDavid Howells 	    call->abort_code == RX_INVALID_OPERATION) {
1873e49c7b2fSDavid Howells 		set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags);
187420325960SDavid Howells 		if (call->op)
187520325960SDavid Howells 			set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags);
187620325960SDavid Howells 	}
1877e49c7b2fSDavid Howells }
1878e49c7b2fSDavid Howells 
18795cf9dd55SDavid Howells /*
18805cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
18815cf9dd55SDavid Howells  */
18825cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
18835cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
18845cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
18855cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
1886e49c7b2fSDavid Howells 	.done		= afs_done_fs_inline_bulk_status,
18875cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
18885cf9dd55SDavid Howells };
18895cf9dd55SDavid Howells 
18905cf9dd55SDavid Howells /*
18915cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
18925cf9dd55SDavid Howells  */
afs_fs_inline_bulk_status(struct afs_operation * op)1893e49c7b2fSDavid Howells void afs_fs_inline_bulk_status(struct afs_operation *op)
18945cf9dd55SDavid Howells {
1895e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1896e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
18975cf9dd55SDavid Howells 	struct afs_call *call;
18985cf9dd55SDavid Howells 	__be32 *bp;
18995cf9dd55SDavid Howells 	int i;
19005cf9dd55SDavid Howells 
190120325960SDavid Howells 	if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) {
1902e49c7b2fSDavid Howells 		op->error = -ENOTSUPP;
1903e49c7b2fSDavid Howells 		return;
19045cf9dd55SDavid Howells 	}
19055cf9dd55SDavid Howells 
1906e49c7b2fSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1907e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
1908e49c7b2fSDavid Howells 
1909e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus,
1910e49c7b2fSDavid Howells 				   (2 + op->nr_files * 3) * 4,
1911e49c7b2fSDavid Howells 				   21 * 4);
1912e49c7b2fSDavid Howells 	if (!call)
1913e49c7b2fSDavid Howells 		return afs_op_nomem(op);
19145cf9dd55SDavid Howells 
19155cf9dd55SDavid Howells 	/* marshall the parameters */
19165cf9dd55SDavid Howells 	bp = call->request;
19175cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
1918e49c7b2fSDavid Howells 	*bp++ = htonl(op->nr_files);
1919e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
1920e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
1921e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
1922e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1923e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1924e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1925e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++) {
1926e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vid);
1927e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vnode);
1928e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.unique);
19295cf9dd55SDavid Howells 	}
19305cf9dd55SDavid Howells 
1931e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1932e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
19335cf9dd55SDavid Howells }
1934260f082bSDavid Howells 
1935260f082bSDavid Howells /*
1936260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
1937260f082bSDavid Howells  */
afs_deliver_fs_fetch_acl(struct afs_call * call)1938260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
1939260f082bSDavid Howells {
1940e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1941e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1942260f082bSDavid Howells 	struct afs_acl *acl;
1943260f082bSDavid Howells 	const __be32 *bp;
1944260f082bSDavid Howells 	unsigned int size;
1945260f082bSDavid Howells 	int ret;
1946260f082bSDavid Howells 
1947260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
1948260f082bSDavid Howells 
1949260f082bSDavid Howells 	switch (call->unmarshall) {
1950260f082bSDavid Howells 	case 0:
1951260f082bSDavid Howells 		afs_extract_to_tmp(call);
1952260f082bSDavid Howells 		call->unmarshall++;
1953df561f66SGustavo A. R. Silva 		fallthrough;
1954260f082bSDavid Howells 
1955260f082bSDavid Howells 		/* extract the returned data length */
1956260f082bSDavid Howells 	case 1:
1957260f082bSDavid Howells 		ret = afs_extract_data(call, true);
1958260f082bSDavid Howells 		if (ret < 0)
1959260f082bSDavid Howells 			return ret;
1960260f082bSDavid Howells 
1961260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1962260f082bSDavid Howells 		size = round_up(size, 4);
1963260f082bSDavid Howells 
1964260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1965260f082bSDavid Howells 		if (!acl)
1966260f082bSDavid Howells 			return -ENOMEM;
1967e49c7b2fSDavid Howells 		op->acl = acl;
1968260f082bSDavid Howells 		acl->size = call->count2;
1969260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
1970260f082bSDavid Howells 		call->unmarshall++;
1971df561f66SGustavo A. R. Silva 		fallthrough;
1972260f082bSDavid Howells 
1973260f082bSDavid Howells 		/* extract the returned data */
1974260f082bSDavid Howells 	case 2:
1975260f082bSDavid Howells 		ret = afs_extract_data(call, true);
1976260f082bSDavid Howells 		if (ret < 0)
1977260f082bSDavid Howells 			return ret;
1978260f082bSDavid Howells 
1979260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
1980260f082bSDavid Howells 		call->unmarshall++;
1981df561f66SGustavo A. R. Silva 		fallthrough;
1982260f082bSDavid Howells 
1983260f082bSDavid Howells 		/* extract the metadata */
1984260f082bSDavid Howells 	case 3:
1985260f082bSDavid Howells 		ret = afs_extract_data(call, false);
1986260f082bSDavid Howells 		if (ret < 0)
1987260f082bSDavid Howells 			return ret;
1988260f082bSDavid Howells 
1989260f082bSDavid Howells 		bp = call->buffer;
1990e49c7b2fSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
1991e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
1992260f082bSDavid Howells 
1993260f082bSDavid Howells 		call->unmarshall++;
1994b2db6c35SGustavo A. R. Silva 		fallthrough;
1995260f082bSDavid Howells 
1996260f082bSDavid Howells 	case 4:
1997260f082bSDavid Howells 		break;
1998260f082bSDavid Howells 	}
1999260f082bSDavid Howells 
2000260f082bSDavid Howells 	_leave(" = 0 [done]");
2001260f082bSDavid Howells 	return 0;
2002260f082bSDavid Howells }
2003260f082bSDavid Howells 
2004260f082bSDavid Howells /*
2005260f082bSDavid Howells  * FS.FetchACL operation type
2006260f082bSDavid Howells  */
2007260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2008260f082bSDavid Howells 	.name		= "FS.FetchACL",
2009260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2010260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2011260f082bSDavid Howells };
2012260f082bSDavid Howells 
2013260f082bSDavid Howells /*
2014260f082bSDavid Howells  * Fetch the ACL for a file.
2015260f082bSDavid Howells  */
afs_fs_fetch_acl(struct afs_operation * op)2016e49c7b2fSDavid Howells void afs_fs_fetch_acl(struct afs_operation *op)
2017260f082bSDavid Howells {
2018e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2019260f082bSDavid Howells 	struct afs_call *call;
2020260f082bSDavid Howells 	__be32 *bp;
2021260f082bSDavid Howells 
2022260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2023e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2024260f082bSDavid Howells 
2025e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2026e49c7b2fSDavid Howells 	if (!call)
2027e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2028260f082bSDavid Howells 
2029260f082bSDavid Howells 	/* marshall the parameters */
2030260f082bSDavid Howells 	bp = call->request;
2031260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2032e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2033e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2034e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2035260f082bSDavid Howells 
2036e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2037e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
2038ffba718eSDavid Howells }
2039ffba718eSDavid Howells 
2040ffba718eSDavid Howells /*
2041b10494afSJoe Gorse  * FS.StoreACL operation type
2042b10494afSJoe Gorse  */
2043b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2044b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2045b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2046ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2047b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2048b10494afSJoe Gorse };
2049b10494afSJoe Gorse 
2050b10494afSJoe Gorse /*
2051b10494afSJoe Gorse  * Fetch the ACL for a file.
2052b10494afSJoe Gorse  */
afs_fs_store_acl(struct afs_operation * op)2053e49c7b2fSDavid Howells void afs_fs_store_acl(struct afs_operation *op)
2054b10494afSJoe Gorse {
2055e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2056b10494afSJoe Gorse 	struct afs_call *call;
2057e49c7b2fSDavid Howells 	const struct afs_acl *acl = op->acl;
2058b10494afSJoe Gorse 	size_t size;
2059b10494afSJoe Gorse 	__be32 *bp;
2060b10494afSJoe Gorse 
2061b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2062e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2063b10494afSJoe Gorse 
2064b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2065e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL,
2066b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2067e49c7b2fSDavid Howells 	if (!call)
2068e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2069b10494afSJoe Gorse 
2070b10494afSJoe Gorse 	/* marshall the parameters */
2071b10494afSJoe Gorse 	bp = call->request;
2072b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2073e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2074e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2075e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2076b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2077b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2078b10494afSJoe Gorse 	if (acl->size != size)
2079b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2080b10494afSJoe Gorse 
2081e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2082e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
20831da177e4SLinus Torvalds }
2084