xref: /openbmc/linux/fs/afs/fsclient.c (revision b2db6c35)
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  */
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  */
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  */
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 
13278107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
13378107055SDavid Howells {
13478107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
13578107055SDavid Howells }
13678107055SDavid Howells 
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  */
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  */
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  */
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  */
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  */
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  */
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++;
391*b2db6c35SGustavo 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  */
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  */
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 
459196ee9cdSDavid Howells 	if (upper_32_bits(req->pos) ||
460196ee9cdSDavid Howells 	    upper_32_bits(req->len) ||
461196ee9cdSDavid Howells 	    upper_32_bits(req->pos + req->len))
462e49c7b2fSDavid Howells 		return afs_fs_fetch_data64(op);
463b9b1f8d5SDavid Howells 
46408e0e7c8SDavid Howells 	_enter("");
4651da177e4SLinus Torvalds 
466e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
46708e0e7c8SDavid Howells 	if (!call)
468e49c7b2fSDavid Howells 		return afs_op_nomem(op);
4691da177e4SLinus Torvalds 
470c4508464SDavid Howells 	req->call_debug_id = call->debug_id;
471c4508464SDavid Howells 
4721da177e4SLinus Torvalds 	/* marshall the parameters */
47308e0e7c8SDavid Howells 	bp = call->request;
47408e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
475e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
476e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
477e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
478196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
479196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
4801da177e4SLinus Torvalds 
481e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
482e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
48308e0e7c8SDavid Howells }
484260a9803SDavid Howells 
485260a9803SDavid Howells /*
486260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
487260a9803SDavid Howells  */
488d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
489260a9803SDavid Howells {
490e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
491e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
492e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
493260a9803SDavid Howells 	const __be32 *bp;
494372ee163SDavid Howells 	int ret;
495260a9803SDavid Howells 
496d001648eSDavid Howells 	ret = afs_transfer_reply(call);
497372ee163SDavid Howells 	if (ret < 0)
498372ee163SDavid Howells 		return ret;
499260a9803SDavid Howells 
500260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
501260a9803SDavid Howells 	bp = call->buffer;
502e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &op->file[1].fid);
503e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
504e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
505e49c7b2fSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
506e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
507260a9803SDavid Howells 
508260a9803SDavid Howells 	_leave(" = 0 [done]");
509260a9803SDavid Howells 	return 0;
510260a9803SDavid Howells }
511260a9803SDavid Howells 
512260a9803SDavid Howells /*
513260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
514260a9803SDavid Howells  */
515025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
516025db80cSDavid Howells 	.name		= "FS.CreateFile",
517025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
518025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
519025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
520025db80cSDavid Howells };
521025db80cSDavid Howells 
522e49c7b2fSDavid Howells /*
523e49c7b2fSDavid Howells  * Create a file.
524e49c7b2fSDavid Howells  */
525e49c7b2fSDavid Howells void afs_fs_create_file(struct afs_operation *op)
526e49c7b2fSDavid Howells {
527e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
528e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
529e49c7b2fSDavid Howells 	struct afs_call *call;
530e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
531e49c7b2fSDavid Howells 	__be32 *bp;
532e49c7b2fSDavid Howells 
533e49c7b2fSDavid Howells 	_enter("");
534e49c7b2fSDavid Howells 
535e49c7b2fSDavid Howells 	namesz = name->len;
536e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
537e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
538e49c7b2fSDavid Howells 
539e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile,
540e49c7b2fSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
541e49c7b2fSDavid Howells 	if (!call)
542e49c7b2fSDavid Howells 		return afs_op_nomem(op);
543e49c7b2fSDavid Howells 
544e49c7b2fSDavid Howells 	/* marshall the parameters */
545e49c7b2fSDavid Howells 	bp = call->request;
546e49c7b2fSDavid Howells 	*bp++ = htonl(FSCREATEFILE);
547e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
548e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
549e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
550e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
551e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
552e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
553e49c7b2fSDavid Howells 	if (padsz > 0) {
554e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
555e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
556e49c7b2fSDavid Howells 	}
557e49c7b2fSDavid Howells 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
558e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
559e49c7b2fSDavid Howells 	*bp++ = 0; /* owner */
560e49c7b2fSDavid Howells 	*bp++ = 0; /* group */
561e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
562e49c7b2fSDavid Howells 	*bp++ = 0; /* segment size */
563e49c7b2fSDavid Howells 
564e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
565e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
566e49c7b2fSDavid Howells }
567e49c7b2fSDavid Howells 
568025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
569025db80cSDavid Howells 	.name		= "FS.MakeDir",
570025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
571260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
572260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
573260a9803SDavid Howells };
574260a9803SDavid Howells 
575260a9803SDavid Howells /*
576e49c7b2fSDavid Howells  * Create a new directory
577260a9803SDavid Howells  */
578e49c7b2fSDavid Howells void afs_fs_make_dir(struct afs_operation *op)
579260a9803SDavid Howells {
580e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
581e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
582260a9803SDavid Howells 	struct afs_call *call;
583260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
584260a9803SDavid Howells 	__be32 *bp;
585260a9803SDavid Howells 
586260a9803SDavid Howells 	_enter("");
587260a9803SDavid Howells 
588e49c7b2fSDavid Howells 	namesz = name->len;
589260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
590260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
591260a9803SDavid Howells 
592e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir,
593025db80cSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
594260a9803SDavid Howells 	if (!call)
595e49c7b2fSDavid Howells 		return afs_op_nomem(op);
596260a9803SDavid Howells 
597260a9803SDavid Howells 	/* marshall the parameters */
598260a9803SDavid Howells 	bp = call->request;
599e49c7b2fSDavid Howells 	*bp++ = htonl(FSMAKEDIR);
600e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
601e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
602e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
603260a9803SDavid Howells 	*bp++ = htonl(namesz);
604e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
605260a9803SDavid Howells 	bp = (void *) bp + namesz;
606260a9803SDavid Howells 	if (padsz > 0) {
607260a9803SDavid Howells 		memset(bp, 0, padsz);
608260a9803SDavid Howells 		bp = (void *) bp + padsz;
609260a9803SDavid Howells 	}
610ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
611e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
612260a9803SDavid Howells 	*bp++ = 0; /* owner */
613260a9803SDavid Howells 	*bp++ = 0; /* group */
614e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
615260a9803SDavid Howells 	*bp++ = 0; /* segment size */
616260a9803SDavid Howells 
617e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
618e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
619260a9803SDavid Howells }
620260a9803SDavid Howells 
621260a9803SDavid Howells /*
622e49c7b2fSDavid Howells  * Deliver reply data to any operation that returns status and volume sync.
623260a9803SDavid Howells  */
624e49c7b2fSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
625260a9803SDavid Howells {
626e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
627e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
628260a9803SDavid Howells 	const __be32 *bp;
629372ee163SDavid Howells 	int ret;
630260a9803SDavid Howells 
631d001648eSDavid Howells 	ret = afs_transfer_reply(call);
632372ee163SDavid Howells 	if (ret < 0)
633372ee163SDavid Howells 		return ret;
634260a9803SDavid Howells 
635260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
636260a9803SDavid Howells 	bp = call->buffer;
637e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
638e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
639260a9803SDavid Howells 
640260a9803SDavid Howells 	_leave(" = 0 [done]");
641260a9803SDavid Howells 	return 0;
642260a9803SDavid Howells }
643260a9803SDavid Howells 
644260a9803SDavid Howells /*
645e49c7b2fSDavid Howells  * FS.RemoveFile operation type
646260a9803SDavid Howells  */
647025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
648025db80cSDavid Howells 	.name		= "FS.RemoveFile",
649025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
650e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
651260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
652260a9803SDavid Howells };
653260a9803SDavid Howells 
654260a9803SDavid Howells /*
655e49c7b2fSDavid Howells  * Remove a file.
656260a9803SDavid Howells  */
657e49c7b2fSDavid Howells void afs_fs_remove_file(struct afs_operation *op)
658260a9803SDavid Howells {
659e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
660e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
661260a9803SDavid Howells 	struct afs_call *call;
662260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
663260a9803SDavid Howells 	__be32 *bp;
664260a9803SDavid Howells 
665260a9803SDavid Howells 	_enter("");
666260a9803SDavid Howells 
667e49c7b2fSDavid Howells 	namesz = name->len;
668260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
669260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
670260a9803SDavid Howells 
671e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile,
672025db80cSDavid Howells 				   reqsz, (21 + 6) * 4);
673260a9803SDavid Howells 	if (!call)
674e49c7b2fSDavid Howells 		return afs_op_nomem(op);
675260a9803SDavid Howells 
676260a9803SDavid Howells 	/* marshall the parameters */
677260a9803SDavid Howells 	bp = call->request;
678e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEFILE);
679e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
680e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
681e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
682260a9803SDavid Howells 	*bp++ = htonl(namesz);
683e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
684260a9803SDavid Howells 	bp = (void *) bp + namesz;
685260a9803SDavid Howells 	if (padsz > 0) {
686260a9803SDavid Howells 		memset(bp, 0, padsz);
687260a9803SDavid Howells 		bp = (void *) bp + padsz;
688260a9803SDavid Howells 	}
689260a9803SDavid Howells 
690e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
691e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
692e49c7b2fSDavid Howells }
693e49c7b2fSDavid Howells 
694e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
695e49c7b2fSDavid Howells 	.name		= "FS.RemoveDir",
696e49c7b2fSDavid Howells 	.op		= afs_FS_RemoveDir,
697e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
698e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
699e49c7b2fSDavid Howells };
700e49c7b2fSDavid Howells 
701e49c7b2fSDavid Howells /*
702e49c7b2fSDavid Howells  * Remove a directory.
703e49c7b2fSDavid Howells  */
704e49c7b2fSDavid Howells void afs_fs_remove_dir(struct afs_operation *op)
705e49c7b2fSDavid Howells {
706e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
707e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
708e49c7b2fSDavid Howells 	struct afs_call *call;
709e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
710e49c7b2fSDavid Howells 	__be32 *bp;
711e49c7b2fSDavid Howells 
712e49c7b2fSDavid Howells 	_enter("");
713e49c7b2fSDavid Howells 
714e49c7b2fSDavid Howells 	namesz = name->len;
715e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
716e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
717e49c7b2fSDavid Howells 
718e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir,
719e49c7b2fSDavid Howells 				   reqsz, (21 + 6) * 4);
720e49c7b2fSDavid Howells 	if (!call)
721e49c7b2fSDavid Howells 		return afs_op_nomem(op);
722e49c7b2fSDavid Howells 
723e49c7b2fSDavid Howells 	/* marshall the parameters */
724e49c7b2fSDavid Howells 	bp = call->request;
725e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEDIR);
726e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
727e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
728e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
729e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
730e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
731e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
732e49c7b2fSDavid Howells 	if (padsz > 0) {
733e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
734e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
735e49c7b2fSDavid Howells 	}
736e49c7b2fSDavid Howells 
737e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
738e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
739260a9803SDavid Howells }
740260a9803SDavid Howells 
741260a9803SDavid Howells /*
742260a9803SDavid Howells  * deliver reply data to an FS.Link
743260a9803SDavid Howells  */
744d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
745260a9803SDavid Howells {
746e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
747e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
748e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
749260a9803SDavid Howells 	const __be32 *bp;
750372ee163SDavid Howells 	int ret;
751260a9803SDavid Howells 
752d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
753260a9803SDavid Howells 
754d001648eSDavid Howells 	ret = afs_transfer_reply(call);
755372ee163SDavid Howells 	if (ret < 0)
756372ee163SDavid Howells 		return ret;
757260a9803SDavid Howells 
758260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
759260a9803SDavid Howells 	bp = call->buffer;
760e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
761e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
762e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
763260a9803SDavid Howells 
764260a9803SDavid Howells 	_leave(" = 0 [done]");
765260a9803SDavid Howells 	return 0;
766260a9803SDavid Howells }
767260a9803SDavid Howells 
768260a9803SDavid Howells /*
769260a9803SDavid Howells  * FS.Link operation type
770260a9803SDavid Howells  */
771260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
772260a9803SDavid Howells 	.name		= "FS.Link",
773025db80cSDavid Howells 	.op		= afs_FS_Link,
774260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
775260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
776260a9803SDavid Howells };
777260a9803SDavid Howells 
778260a9803SDavid Howells /*
779260a9803SDavid Howells  * make a hard link
780260a9803SDavid Howells  */
781e49c7b2fSDavid Howells void afs_fs_link(struct afs_operation *op)
782260a9803SDavid Howells {
783e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
784e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
785e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
786260a9803SDavid Howells 	struct afs_call *call;
787260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
788260a9803SDavid Howells 	__be32 *bp;
789260a9803SDavid Howells 
790260a9803SDavid Howells 	_enter("");
791260a9803SDavid Howells 
792e49c7b2fSDavid Howells 	namesz = name->len;
793260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
794260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
795260a9803SDavid Howells 
796e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
797260a9803SDavid Howells 	if (!call)
798e49c7b2fSDavid Howells 		return afs_op_nomem(op);
799260a9803SDavid Howells 
800260a9803SDavid Howells 	/* marshall the parameters */
801260a9803SDavid Howells 	bp = call->request;
802260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
803e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
804e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
805e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
806260a9803SDavid Howells 	*bp++ = htonl(namesz);
807e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
808260a9803SDavid Howells 	bp = (void *) bp + namesz;
809260a9803SDavid Howells 	if (padsz > 0) {
810260a9803SDavid Howells 		memset(bp, 0, padsz);
811260a9803SDavid Howells 		bp = (void *) bp + padsz;
812260a9803SDavid Howells 	}
813e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
814e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
815e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
816260a9803SDavid Howells 
817e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
818e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
819260a9803SDavid Howells }
820260a9803SDavid Howells 
821260a9803SDavid Howells /*
822260a9803SDavid Howells  * deliver reply data to an FS.Symlink
823260a9803SDavid Howells  */
824d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
825260a9803SDavid Howells {
826e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
827e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
828e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
829260a9803SDavid Howells 	const __be32 *bp;
830372ee163SDavid Howells 	int ret;
831260a9803SDavid Howells 
832d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
833260a9803SDavid Howells 
834d001648eSDavid Howells 	ret = afs_transfer_reply(call);
835372ee163SDavid Howells 	if (ret < 0)
836372ee163SDavid Howells 		return ret;
837260a9803SDavid Howells 
838260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
839260a9803SDavid Howells 	bp = call->buffer;
840e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &vp->fid);
841e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
842e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
843e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
844260a9803SDavid Howells 
845260a9803SDavid Howells 	_leave(" = 0 [done]");
846260a9803SDavid Howells 	return 0;
847260a9803SDavid Howells }
848260a9803SDavid Howells 
849260a9803SDavid Howells /*
850260a9803SDavid Howells  * FS.Symlink operation type
851260a9803SDavid Howells  */
852260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
853260a9803SDavid Howells 	.name		= "FS.Symlink",
854025db80cSDavid Howells 	.op		= afs_FS_Symlink,
855260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
856260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
857260a9803SDavid Howells };
858260a9803SDavid Howells 
859260a9803SDavid Howells /*
860260a9803SDavid Howells  * create a symbolic link
861260a9803SDavid Howells  */
862e49c7b2fSDavid Howells void afs_fs_symlink(struct afs_operation *op)
863260a9803SDavid Howells {
864e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
865e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
866260a9803SDavid Howells 	struct afs_call *call;
867260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
868260a9803SDavid Howells 	__be32 *bp;
869260a9803SDavid Howells 
870260a9803SDavid Howells 	_enter("");
871260a9803SDavid Howells 
872e49c7b2fSDavid Howells 	namesz = name->len;
873260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
874260a9803SDavid Howells 
875e49c7b2fSDavid Howells 	c_namesz = strlen(op->create.symlink);
876260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
877260a9803SDavid Howells 
878260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
879260a9803SDavid Howells 
880e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz,
881260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
882260a9803SDavid Howells 	if (!call)
883e49c7b2fSDavid Howells 		return afs_op_nomem(op);
884260a9803SDavid Howells 
885260a9803SDavid Howells 	/* marshall the parameters */
886260a9803SDavid Howells 	bp = call->request;
887260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
888e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
889e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
890e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
891260a9803SDavid Howells 	*bp++ = htonl(namesz);
892e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
893260a9803SDavid Howells 	bp = (void *) bp + namesz;
894260a9803SDavid Howells 	if (padsz > 0) {
895260a9803SDavid Howells 		memset(bp, 0, padsz);
896260a9803SDavid Howells 		bp = (void *) bp + padsz;
897260a9803SDavid Howells 	}
898260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
899e49c7b2fSDavid Howells 	memcpy(bp, op->create.symlink, c_namesz);
900260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
901260a9803SDavid Howells 	if (c_padsz > 0) {
902260a9803SDavid Howells 		memset(bp, 0, c_padsz);
903260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
904260a9803SDavid Howells 	}
905ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
906e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
907260a9803SDavid Howells 	*bp++ = 0; /* owner */
908260a9803SDavid Howells 	*bp++ = 0; /* group */
909260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
910260a9803SDavid Howells 	*bp++ = 0; /* segment size */
911260a9803SDavid Howells 
912e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
913e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
914260a9803SDavid Howells }
915260a9803SDavid Howells 
916260a9803SDavid Howells /*
917260a9803SDavid Howells  * deliver reply data to an FS.Rename
918260a9803SDavid Howells  */
919d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
920260a9803SDavid Howells {
921e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
922e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
923e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
924260a9803SDavid Howells 	const __be32 *bp;
925372ee163SDavid Howells 	int ret;
926260a9803SDavid Howells 
927d001648eSDavid Howells 	ret = afs_transfer_reply(call);
928372ee163SDavid Howells 	if (ret < 0)
929372ee163SDavid Howells 		return ret;
930260a9803SDavid Howells 
93138355eecSDavid Howells 	bp = call->buffer;
932b98f0ec9SDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
933b98f0ec9SDavid Howells 	 * report, so we just decode it twice.
934b98f0ec9SDavid Howells 	 */
935e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb);
936e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb);
937e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
938260a9803SDavid Howells 
939260a9803SDavid Howells 	_leave(" = 0 [done]");
940260a9803SDavid Howells 	return 0;
941260a9803SDavid Howells }
942260a9803SDavid Howells 
943260a9803SDavid Howells /*
944260a9803SDavid Howells  * FS.Rename operation type
945260a9803SDavid Howells  */
946260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
947260a9803SDavid Howells 	.name		= "FS.Rename",
948025db80cSDavid Howells 	.op		= afs_FS_Rename,
949260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
950260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
951260a9803SDavid Howells };
952260a9803SDavid Howells 
953260a9803SDavid Howells /*
954a58823acSDavid Howells  * Rename/move a file or directory.
955260a9803SDavid Howells  */
956e49c7b2fSDavid Howells void afs_fs_rename(struct afs_operation *op)
957260a9803SDavid Howells {
958e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
959e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
960e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
961e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
962260a9803SDavid Howells 	struct afs_call *call;
963260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
964260a9803SDavid Howells 	__be32 *bp;
965260a9803SDavid Howells 
966260a9803SDavid Howells 	_enter("");
967260a9803SDavid Howells 
968e49c7b2fSDavid Howells 	o_namesz = orig_name->len;
969260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
970260a9803SDavid Howells 
971e49c7b2fSDavid Howells 	n_namesz = new_name->len;
972260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
973260a9803SDavid Howells 
974260a9803SDavid Howells 	reqsz = (4 * 4) +
975260a9803SDavid Howells 		4 + o_namesz + o_padsz +
976260a9803SDavid Howells 		(3 * 4) +
977260a9803SDavid Howells 		4 + n_namesz + n_padsz;
978260a9803SDavid Howells 
979e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
980260a9803SDavid Howells 	if (!call)
981e49c7b2fSDavid Howells 		return afs_op_nomem(op);
982260a9803SDavid Howells 
983260a9803SDavid Howells 	/* marshall the parameters */
984260a9803SDavid Howells 	bp = call->request;
985260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
986e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vid);
987e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vnode);
988e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.unique);
989260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
990e49c7b2fSDavid Howells 	memcpy(bp, orig_name->name, o_namesz);
991260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
992260a9803SDavid Howells 	if (o_padsz > 0) {
993260a9803SDavid Howells 		memset(bp, 0, o_padsz);
994260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
995260a9803SDavid Howells 	}
996260a9803SDavid Howells 
997e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vid);
998e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vnode);
999e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.unique);
1000260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1001e49c7b2fSDavid Howells 	memcpy(bp, new_name->name, n_namesz);
1002260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1003260a9803SDavid Howells 	if (n_padsz > 0) {
1004260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1005260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1006260a9803SDavid Howells 	}
1007260a9803SDavid Howells 
1008e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1009e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1010260a9803SDavid Howells }
101131143d5dSDavid Howells 
101231143d5dSDavid Howells /*
1013e49c7b2fSDavid Howells  * Deliver reply data to FS.StoreData or FS.StoreStatus
101431143d5dSDavid Howells  */
1015d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
101631143d5dSDavid Howells {
1017e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1018e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
101931143d5dSDavid Howells 	const __be32 *bp;
1020372ee163SDavid Howells 	int ret;
102131143d5dSDavid Howells 
1022d001648eSDavid Howells 	_enter("");
102331143d5dSDavid Howells 
1024d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1025372ee163SDavid Howells 	if (ret < 0)
1026372ee163SDavid Howells 		return ret;
102731143d5dSDavid Howells 
102831143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
102931143d5dSDavid Howells 	bp = call->buffer;
1030e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
1031e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
103231143d5dSDavid Howells 
103331143d5dSDavid Howells 	_leave(" = 0 [done]");
103431143d5dSDavid Howells 	return 0;
103531143d5dSDavid Howells }
103631143d5dSDavid Howells 
103731143d5dSDavid Howells /*
103831143d5dSDavid Howells  * FS.StoreData operation type
103931143d5dSDavid Howells  */
104031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
104131143d5dSDavid Howells 	.name		= "FS.StoreData",
1042025db80cSDavid Howells 	.op		= afs_FS_StoreData,
104331143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
104431143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
104531143d5dSDavid Howells };
104631143d5dSDavid Howells 
1047b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1048b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1049025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1050b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1051b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1052b9b1f8d5SDavid Howells };
1053b9b1f8d5SDavid Howells 
1054b9b1f8d5SDavid Howells /*
1055b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1056b9b1f8d5SDavid Howells  */
1057bd80d8a8SDavid Howells static void afs_fs_store_data64(struct afs_operation *op)
1058b9b1f8d5SDavid Howells {
1059e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1060b9b1f8d5SDavid Howells 	struct afs_call *call;
1061b9b1f8d5SDavid Howells 	__be32 *bp;
1062b9b1f8d5SDavid Howells 
10633b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1064e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1065b9b1f8d5SDavid Howells 
1066e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64,
1067b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1068b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1069b9b1f8d5SDavid Howells 	if (!call)
1070e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1071b9b1f8d5SDavid Howells 
1072bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
1073b9b1f8d5SDavid Howells 
1074b9b1f8d5SDavid Howells 	/* marshall the parameters */
1075b9b1f8d5SDavid Howells 	bp = call->request;
1076b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1077e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1078e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1079e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1080b9b1f8d5SDavid Howells 
1081ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1082e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
1083b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1084b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1085b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1086b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1087b9b1f8d5SDavid Howells 
1088bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.pos));
1089bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.pos));
1090bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.size));
1091bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.size));
1092bd80d8a8SDavid Howells 	*bp++ = htonl(upper_32_bits(op->store.i_size));
1093bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.i_size));
1094b9b1f8d5SDavid Howells 
1095e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1096e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1097b9b1f8d5SDavid Howells }
1098b9b1f8d5SDavid Howells 
109931143d5dSDavid Howells /*
1100bd80d8a8SDavid Howells  * Write data to a file on the server.
110131143d5dSDavid Howells  */
1102e49c7b2fSDavid Howells void afs_fs_store_data(struct afs_operation *op)
110331143d5dSDavid Howells {
1104e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
110531143d5dSDavid Howells 	struct afs_call *call;
110631143d5dSDavid Howells 	__be32 *bp;
110731143d5dSDavid Howells 
11083b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1109e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
111031143d5dSDavid Howells 
111131143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
1112bd80d8a8SDavid Howells 	       (unsigned long long)op->store.size,
1113bd80d8a8SDavid Howells 	       (unsigned long long)op->store.pos,
1114bd80d8a8SDavid Howells 	       (unsigned long long)op->store.i_size);
111531143d5dSDavid Howells 
1116bd80d8a8SDavid Howells 	if (upper_32_bits(op->store.pos) ||
1117bd80d8a8SDavid Howells 	    upper_32_bits(op->store.size) ||
1118bd80d8a8SDavid Howells 	    upper_32_bits(op->store.i_size))
1119bd80d8a8SDavid Howells 		return afs_fs_store_data64(op);
112031143d5dSDavid Howells 
1121e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData,
112231143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
112331143d5dSDavid Howells 				   (21 + 6) * 4);
112431143d5dSDavid Howells 	if (!call)
1125e49c7b2fSDavid Howells 		return afs_op_nomem(op);
112631143d5dSDavid Howells 
1127bd80d8a8SDavid Howells 	call->write_iter = op->store.write_iter;
112831143d5dSDavid Howells 
112931143d5dSDavid Howells 	/* marshall the parameters */
113031143d5dSDavid Howells 	bp = call->request;
113131143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1132e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1133e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1134e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
113531143d5dSDavid Howells 
1136ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1137e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
113831143d5dSDavid Howells 	*bp++ = 0; /* owner */
113931143d5dSDavid Howells 	*bp++ = 0; /* group */
114031143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
114131143d5dSDavid Howells 	*bp++ = 0; /* segment size */
114231143d5dSDavid Howells 
1143bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.pos));
1144bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.size));
1145bd80d8a8SDavid Howells 	*bp++ = htonl(lower_32_bits(op->store.i_size));
114631143d5dSDavid Howells 
1147e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1148e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
114931143d5dSDavid Howells }
115031143d5dSDavid Howells 
115131143d5dSDavid Howells /*
115231143d5dSDavid Howells  * FS.StoreStatus operation type
115331143d5dSDavid Howells  */
115431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
115531143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1156025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
1157e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
115831143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
115931143d5dSDavid Howells };
116031143d5dSDavid Howells 
116131143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
116231143d5dSDavid Howells 	.name		= "FS.StoreData",
1163025db80cSDavid Howells 	.op		= afs_FS_StoreData,
1164e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
116531143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
116631143d5dSDavid Howells };
116731143d5dSDavid Howells 
1168b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1169b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1170025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1171e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1172b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1173b9b1f8d5SDavid Howells };
1174b9b1f8d5SDavid Howells 
1175b9b1f8d5SDavid Howells /*
1176b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1177b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1178b9b1f8d5SDavid Howells  */
1179e49c7b2fSDavid Howells static void afs_fs_setattr_size64(struct afs_operation *op)
1180b9b1f8d5SDavid Howells {
1181e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1182b9b1f8d5SDavid Howells 	struct afs_call *call;
1183e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
1184b9b1f8d5SDavid Howells 	__be32 *bp;
1185b9b1f8d5SDavid Howells 
11863b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1187e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1188b9b1f8d5SDavid Howells 
1189b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1190b9b1f8d5SDavid Howells 
1191e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status,
1192b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1193b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1194b9b1f8d5SDavid Howells 	if (!call)
1195e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1196b9b1f8d5SDavid Howells 
1197b9b1f8d5SDavid Howells 	/* marshall the parameters */
1198b9b1f8d5SDavid Howells 	bp = call->request;
1199b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1200e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1201e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1202e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1203b9b1f8d5SDavid Howells 
1204b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1205b9b1f8d5SDavid Howells 
1206e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* position of start of write */
1207e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1208b9b1f8d5SDavid Howells 	*bp++ = 0;					/* size of write */
1209b9b1f8d5SDavid Howells 	*bp++ = 0;
1210e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* new file length */
1211e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1212b9b1f8d5SDavid Howells 
1213e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1214e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1215b9b1f8d5SDavid Howells }
1216b9b1f8d5SDavid Howells 
121731143d5dSDavid Howells /*
121831143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
121931143d5dSDavid Howells  * so as to alter the file size also
122031143d5dSDavid Howells  */
1221e49c7b2fSDavid Howells static void afs_fs_setattr_size(struct afs_operation *op)
122231143d5dSDavid Howells {
1223e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
122431143d5dSDavid Howells 	struct afs_call *call;
1225e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
122631143d5dSDavid Howells 	__be32 *bp;
122731143d5dSDavid Howells 
12283b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1229e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
123031143d5dSDavid Howells 
123131143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1232e49c7b2fSDavid Howells 	if (upper_32_bits(attr->ia_size))
1233e49c7b2fSDavid Howells 		return afs_fs_setattr_size64(op);
123431143d5dSDavid Howells 
1235e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status,
123631143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
123731143d5dSDavid Howells 				   (21 + 6) * 4);
123831143d5dSDavid Howells 	if (!call)
1239e49c7b2fSDavid Howells 		return afs_op_nomem(op);
124031143d5dSDavid Howells 
124131143d5dSDavid Howells 	/* marshall the parameters */
124231143d5dSDavid Howells 	bp = call->request;
124331143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1244e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1245e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1246e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
124731143d5dSDavid Howells 
124831143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
124931143d5dSDavid Howells 
12508c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
125131143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
125231143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
125331143d5dSDavid Howells 
1254e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1255e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
125631143d5dSDavid Howells }
125731143d5dSDavid Howells 
125831143d5dSDavid Howells /*
125931143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
126031143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
126131143d5dSDavid Howells  */
1262e49c7b2fSDavid Howells void afs_fs_setattr(struct afs_operation *op)
126331143d5dSDavid Howells {
1264e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
126531143d5dSDavid Howells 	struct afs_call *call;
1266e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
126731143d5dSDavid Howells 	__be32 *bp;
126831143d5dSDavid Howells 
126931143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1270e49c7b2fSDavid Howells 		return afs_fs_setattr_size(op);
127131143d5dSDavid Howells 
12723b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1273e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
127431143d5dSDavid Howells 
1275e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus,
127631143d5dSDavid Howells 				   (4 + 6) * 4,
127731143d5dSDavid Howells 				   (21 + 6) * 4);
127831143d5dSDavid Howells 	if (!call)
1279e49c7b2fSDavid Howells 		return afs_op_nomem(op);
128031143d5dSDavid Howells 
128131143d5dSDavid Howells 	/* marshall the parameters */
128231143d5dSDavid Howells 	bp = call->request;
128331143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
1284e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1285e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1286e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
128731143d5dSDavid Howells 
1288e49c7b2fSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr);
128931143d5dSDavid Howells 
1290e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1291e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
129231143d5dSDavid Howells }
129345222b9eSDavid Howells 
129445222b9eSDavid Howells /*
129545222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
129645222b9eSDavid Howells  */
1297d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
129845222b9eSDavid Howells {
1299e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
130045222b9eSDavid Howells 	const __be32 *bp;
130145222b9eSDavid Howells 	char *p;
130212bdcf33SDavid Howells 	u32 size;
130345222b9eSDavid Howells 	int ret;
130445222b9eSDavid Howells 
1305d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
130645222b9eSDavid Howells 
130745222b9eSDavid Howells 	switch (call->unmarshall) {
130845222b9eSDavid Howells 	case 0:
130945222b9eSDavid Howells 		call->unmarshall++;
131012bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
1311df561f66SGustavo A. R. Silva 		fallthrough;
131245222b9eSDavid Howells 
131329881608SGustavo A. R. Silva 		/* extract the returned status record */
131445222b9eSDavid Howells 	case 1:
131545222b9eSDavid Howells 		_debug("extract status");
131612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1317372ee163SDavid Howells 		if (ret < 0)
1318372ee163SDavid Howells 			return ret;
131945222b9eSDavid Howells 
132045222b9eSDavid Howells 		bp = call->buffer;
1321e49c7b2fSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs);
132245222b9eSDavid Howells 		call->unmarshall++;
132312bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1324df561f66SGustavo A. R. Silva 		fallthrough;
132545222b9eSDavid Howells 
132629881608SGustavo A. R. Silva 		/* extract the volume name length */
132745222b9eSDavid Howells 	case 2:
132812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1329372ee163SDavid Howells 		if (ret < 0)
1330372ee163SDavid Howells 			return ret;
133145222b9eSDavid Howells 
133245222b9eSDavid Howells 		call->count = ntohl(call->tmp);
133345222b9eSDavid Howells 		_debug("volname length: %u", call->count);
133445222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13357126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
133612bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1337ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
133845222b9eSDavid Howells 		call->unmarshall++;
1339df561f66SGustavo A. R. Silva 		fallthrough;
134045222b9eSDavid Howells 
134129881608SGustavo A. R. Silva 		/* extract the volume name */
134245222b9eSDavid Howells 	case 3:
134345222b9eSDavid Howells 		_debug("extract volname");
134412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1345372ee163SDavid Howells 		if (ret < 0)
1346372ee163SDavid Howells 			return ret;
134745222b9eSDavid Howells 
1348ffba718eSDavid Howells 		p = call->buffer;
134945222b9eSDavid Howells 		p[call->count] = 0;
135045222b9eSDavid Howells 		_debug("volname '%s'", p);
135112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
135245222b9eSDavid Howells 		call->unmarshall++;
1353df561f66SGustavo A. R. Silva 		fallthrough;
135445222b9eSDavid Howells 
135529881608SGustavo A. R. Silva 		/* extract the offline message length */
135612bdcf33SDavid Howells 	case 4:
135712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1358372ee163SDavid Howells 		if (ret < 0)
1359372ee163SDavid Howells 			return ret;
136045222b9eSDavid Howells 
136145222b9eSDavid Howells 		call->count = ntohl(call->tmp);
136245222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
136345222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13647126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
136512bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1366ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
136745222b9eSDavid Howells 		call->unmarshall++;
1368df561f66SGustavo A. R. Silva 		fallthrough;
136945222b9eSDavid Howells 
137029881608SGustavo A. R. Silva 		/* extract the offline message */
137112bdcf33SDavid Howells 	case 5:
137245222b9eSDavid Howells 		_debug("extract offline");
137312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1374372ee163SDavid Howells 		if (ret < 0)
1375372ee163SDavid Howells 			return ret;
137645222b9eSDavid Howells 
1377ffba718eSDavid Howells 		p = call->buffer;
137845222b9eSDavid Howells 		p[call->count] = 0;
137945222b9eSDavid Howells 		_debug("offline '%s'", p);
138045222b9eSDavid Howells 
138112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
138245222b9eSDavid Howells 		call->unmarshall++;
1383df561f66SGustavo A. R. Silva 		fallthrough;
138445222b9eSDavid Howells 
138529881608SGustavo A. R. Silva 		/* extract the message of the day length */
138612bdcf33SDavid Howells 	case 6:
138712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1388372ee163SDavid Howells 		if (ret < 0)
1389372ee163SDavid Howells 			return ret;
139045222b9eSDavid Howells 
139145222b9eSDavid Howells 		call->count = ntohl(call->tmp);
139245222b9eSDavid Howells 		_debug("motd length: %u", call->count);
139345222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13947126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
139512bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1396ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
139745222b9eSDavid Howells 		call->unmarshall++;
1398df561f66SGustavo A. R. Silva 		fallthrough;
139945222b9eSDavid Howells 
140029881608SGustavo A. R. Silva 		/* extract the message of the day */
140112bdcf33SDavid Howells 	case 7:
140245222b9eSDavid Howells 		_debug("extract motd");
140312bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1404372ee163SDavid Howells 		if (ret < 0)
1405372ee163SDavid Howells 			return ret;
140645222b9eSDavid Howells 
1407ffba718eSDavid Howells 		p = call->buffer;
140845222b9eSDavid Howells 		p[call->count] = 0;
140945222b9eSDavid Howells 		_debug("motd '%s'", p);
141045222b9eSDavid Howells 
141145222b9eSDavid Howells 		call->unmarshall++;
1412*b2db6c35SGustavo A. R. Silva 		fallthrough;
141345222b9eSDavid Howells 
141412bdcf33SDavid Howells 	case 8:
141545222b9eSDavid Howells 		break;
141645222b9eSDavid Howells 	}
141745222b9eSDavid Howells 
141845222b9eSDavid Howells 	_leave(" = 0 [done]");
141945222b9eSDavid Howells 	return 0;
142045222b9eSDavid Howells }
142145222b9eSDavid Howells 
142245222b9eSDavid Howells /*
142345222b9eSDavid Howells  * FS.GetVolumeStatus operation type
142445222b9eSDavid Howells  */
142545222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
142645222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1427025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
142845222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1429ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
143045222b9eSDavid Howells };
143145222b9eSDavid Howells 
143245222b9eSDavid Howells /*
143345222b9eSDavid Howells  * fetch the status of a volume
143445222b9eSDavid Howells  */
1435e49c7b2fSDavid Howells void afs_fs_get_volume_status(struct afs_operation *op)
143645222b9eSDavid Howells {
1437e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
143845222b9eSDavid Howells 	struct afs_call *call;
143945222b9eSDavid Howells 	__be32 *bp;
144045222b9eSDavid Howells 
144145222b9eSDavid Howells 	_enter("");
144245222b9eSDavid Howells 
1443e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4,
1444ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1445ffba718eSDavid Howells 	if (!call)
1446e49c7b2fSDavid Howells 		return afs_op_nomem(op);
144745222b9eSDavid Howells 
144845222b9eSDavid Howells 	/* marshall the parameters */
144945222b9eSDavid Howells 	bp = call->request;
145045222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
1451e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
145245222b9eSDavid Howells 
1453e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1454e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
145545222b9eSDavid Howells }
1456e8d6c554SDavid Howells 
1457e8d6c554SDavid Howells /*
1458e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1459e8d6c554SDavid Howells  */
1460d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1461e8d6c554SDavid Howells {
1462e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1463e8d6c554SDavid Howells 	const __be32 *bp;
1464372ee163SDavid Howells 	int ret;
1465e8d6c554SDavid Howells 
1466d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1467e8d6c554SDavid Howells 
1468d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1469372ee163SDavid Howells 	if (ret < 0)
1470372ee163SDavid Howells 		return ret;
1471e8d6c554SDavid Howells 
1472e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1473e8d6c554SDavid Howells 	bp = call->buffer;
1474e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
1475e8d6c554SDavid Howells 
1476e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1477e8d6c554SDavid Howells 	return 0;
1478e8d6c554SDavid Howells }
1479e8d6c554SDavid Howells 
1480e8d6c554SDavid Howells /*
1481e8d6c554SDavid Howells  * FS.SetLock operation type
1482e8d6c554SDavid Howells  */
1483e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1484e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1485025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1486e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1487a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1488e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1489e8d6c554SDavid Howells };
1490e8d6c554SDavid Howells 
1491e8d6c554SDavid Howells /*
1492e8d6c554SDavid Howells  * FS.ExtendLock operation type
1493e8d6c554SDavid Howells  */
1494e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1495e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1496025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1497e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1498a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1499e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1500e8d6c554SDavid Howells };
1501e8d6c554SDavid Howells 
1502e8d6c554SDavid Howells /*
1503e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1504e8d6c554SDavid Howells  */
1505e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1506e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1507025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1508e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1509e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1510e8d6c554SDavid Howells };
1511e8d6c554SDavid Howells 
1512e8d6c554SDavid Howells /*
1513d2ddc776SDavid Howells  * Set a lock on a file
1514e8d6c554SDavid Howells  */
1515e49c7b2fSDavid Howells void afs_fs_set_lock(struct afs_operation *op)
1516e8d6c554SDavid Howells {
1517e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1518e8d6c554SDavid Howells 	struct afs_call *call;
1519e8d6c554SDavid Howells 	__be32 *bp;
1520e8d6c554SDavid Howells 
1521e8d6c554SDavid Howells 	_enter("");
1522e8d6c554SDavid Howells 
1523e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1524e8d6c554SDavid Howells 	if (!call)
1525e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1526e8d6c554SDavid Howells 
1527e8d6c554SDavid Howells 	/* marshall the parameters */
1528e8d6c554SDavid Howells 	bp = call->request;
1529e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1530e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1531e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1532e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1533e49c7b2fSDavid Howells 	*bp++ = htonl(op->lock.type);
1534e8d6c554SDavid Howells 
1535e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1536e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1537e8d6c554SDavid Howells }
1538e8d6c554SDavid Howells 
1539e8d6c554SDavid Howells /*
1540e8d6c554SDavid Howells  * extend a lock on a file
1541e8d6c554SDavid Howells  */
1542e49c7b2fSDavid Howells void afs_fs_extend_lock(struct afs_operation *op)
1543e8d6c554SDavid Howells {
1544e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1545e8d6c554SDavid Howells 	struct afs_call *call;
1546e8d6c554SDavid Howells 	__be32 *bp;
1547e8d6c554SDavid Howells 
1548e8d6c554SDavid Howells 	_enter("");
1549e8d6c554SDavid Howells 
1550e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1551e8d6c554SDavid Howells 	if (!call)
1552e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1553e8d6c554SDavid Howells 
1554e8d6c554SDavid Howells 	/* marshall the parameters */
1555e8d6c554SDavid Howells 	bp = call->request;
1556e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1557e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1558e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1559e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1560e8d6c554SDavid Howells 
1561e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1562e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1563e8d6c554SDavid Howells }
1564e8d6c554SDavid Howells 
1565e8d6c554SDavid Howells /*
1566e8d6c554SDavid Howells  * release a lock on a file
1567e8d6c554SDavid Howells  */
1568e49c7b2fSDavid Howells void afs_fs_release_lock(struct afs_operation *op)
1569e8d6c554SDavid Howells {
1570e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1571e8d6c554SDavid Howells 	struct afs_call *call;
1572e8d6c554SDavid Howells 	__be32 *bp;
1573e8d6c554SDavid Howells 
1574e8d6c554SDavid Howells 	_enter("");
1575e8d6c554SDavid Howells 
1576e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1577e8d6c554SDavid Howells 	if (!call)
1578e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1579e8d6c554SDavid Howells 
1580e8d6c554SDavid Howells 	/* marshall the parameters */
1581e8d6c554SDavid Howells 	bp = call->request;
1582e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1583e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1584e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1585e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1586e8d6c554SDavid Howells 
1587e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1588e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1589c435ee34SDavid Howells }
1590c435ee34SDavid Howells 
1591c435ee34SDavid Howells /*
1592c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1593c435ee34SDavid Howells  */
1594c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1595c435ee34SDavid Howells {
1596c435ee34SDavid Howells 	return afs_transfer_reply(call);
1597c435ee34SDavid Howells }
1598c435ee34SDavid Howells 
1599c435ee34SDavid Howells /*
1600c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1601c435ee34SDavid Howells  */
1602c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1603c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1604025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1605c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1606c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1607c435ee34SDavid Howells };
1608c435ee34SDavid Howells 
1609c435ee34SDavid Howells /*
1610c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1611c435ee34SDavid Howells  */
1612d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1613d2ddc776SDavid Howells 				 struct afs_server *server,
16148b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1615d2ddc776SDavid Howells 				 struct key *key)
1616c435ee34SDavid Howells {
1617c435ee34SDavid Howells 	struct afs_call *call;
1618c435ee34SDavid Howells 	__be32 *bp;
1619c435ee34SDavid Howells 
1620c435ee34SDavid Howells 	_enter("");
1621c435ee34SDavid Howells 
1622d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1623c435ee34SDavid Howells 	if (!call)
1624c435ee34SDavid Howells 		return -ENOMEM;
1625c435ee34SDavid Howells 
1626c435ee34SDavid Howells 	call->key = key;
1627c435ee34SDavid Howells 
1628c435ee34SDavid Howells 	/* marshall the parameters */
1629c435ee34SDavid Howells 	bp = call->request;
1630c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1631c435ee34SDavid Howells 
1632977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_give_up_cb);
16330b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
16340b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1635d2ddc776SDavid Howells }
1636d2ddc776SDavid Howells 
1637d2ddc776SDavid Howells /*
1638d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1639d2ddc776SDavid Howells  */
1640d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1641d2ddc776SDavid Howells {
1642d2ddc776SDavid Howells 	u32 count;
1643d2ddc776SDavid Howells 	int ret;
1644d2ddc776SDavid Howells 
1645fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1646d2ddc776SDavid Howells 
1647d2ddc776SDavid Howells 	switch (call->unmarshall) {
1648d2ddc776SDavid Howells 	case 0:
164912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1650d2ddc776SDavid Howells 		call->unmarshall++;
1651df561f66SGustavo A. R. Silva 		fallthrough;
1652d2ddc776SDavid Howells 
165329881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1654d2ddc776SDavid Howells 	case 1:
165512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1656d2ddc776SDavid Howells 		if (ret < 0)
1657d2ddc776SDavid Howells 			return ret;
1658d2ddc776SDavid Howells 
1659d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1660d2ddc776SDavid Howells 
1661d2ddc776SDavid Howells 		call->count = count;
1662d2ddc776SDavid Howells 		call->count2 = count;
166323a28913SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
1664d2ddc776SDavid Howells 		call->unmarshall++;
1665df561f66SGustavo A. R. Silva 		fallthrough;
1666d2ddc776SDavid Howells 
166729881608SGustavo A. R. Silva 		/* Extract capabilities words */
1668d2ddc776SDavid Howells 	case 2:
166912bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1670d2ddc776SDavid Howells 		if (ret < 0)
1671d2ddc776SDavid Howells 			return ret;
1672d2ddc776SDavid Howells 
1673d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1674d2ddc776SDavid Howells 
1675d2ddc776SDavid Howells 		call->unmarshall++;
1676d2ddc776SDavid Howells 		break;
1677d2ddc776SDavid Howells 	}
1678d2ddc776SDavid Howells 
1679d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1680d2ddc776SDavid Howells 	return 0;
1681d2ddc776SDavid Howells }
1682d2ddc776SDavid Howells 
1683d2ddc776SDavid Howells /*
1684d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1685d2ddc776SDavid Howells  */
1686d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1687d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1688025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1689d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
16903bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1691ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1692d2ddc776SDavid Howells };
1693d2ddc776SDavid Howells 
1694d2ddc776SDavid Howells /*
1695f6cbb368SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This RPC can
1696f6cbb368SDavid Howells  * reply with up to 196 words.  The operation is asynchronous and if we managed
1697f6cbb368SDavid Howells  * to allocate a call, true is returned the result is delivered through the
1698f6cbb368SDavid Howells  * ->done() - otherwise we return false to indicate we didn't even try.
1699d2ddc776SDavid Howells  */
1700f6cbb368SDavid Howells bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
1701f6cbb368SDavid Howells 			     struct afs_addr_cursor *ac, struct key *key)
1702d2ddc776SDavid Howells {
1703d2ddc776SDavid Howells 	struct afs_call *call;
1704d2ddc776SDavid Howells 	__be32 *bp;
1705d2ddc776SDavid Howells 
1706d2ddc776SDavid Howells 	_enter("");
1707d2ddc776SDavid Howells 
1708d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1709d2ddc776SDavid Howells 	if (!call)
1710f6cbb368SDavid Howells 		return false;
1711d2ddc776SDavid Howells 
1712d2ddc776SDavid Howells 	call->key = key;
1713977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_get_caps);
171430062bd1SDavid Howells 	call->upgrade = true;
17150b9bf381SDavid Howells 	call->async = true;
171694f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1717d2ddc776SDavid Howells 
1718d2ddc776SDavid Howells 	/* marshall the parameters */
1719d2ddc776SDavid Howells 	bp = call->request;
1720d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1721d2ddc776SDavid Howells 
1722025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
17230b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
1724f6cbb368SDavid Howells 	afs_put_call(call);
1725f6cbb368SDavid Howells 	return true;
1726e8d6c554SDavid Howells }
17275cf9dd55SDavid Howells 
17285cf9dd55SDavid Howells /*
17295cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
17305cf9dd55SDavid Howells  */
17315cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
17325cf9dd55SDavid Howells {
1733e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
173487182759SDavid Howells 	struct afs_status_cb *scb;
17355cf9dd55SDavid Howells 	const __be32 *bp;
17365cf9dd55SDavid Howells 	u32 tmp;
17375cf9dd55SDavid Howells 	int ret;
17385cf9dd55SDavid Howells 
17395cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
17405cf9dd55SDavid Howells 
17415cf9dd55SDavid Howells 	switch (call->unmarshall) {
17425cf9dd55SDavid Howells 	case 0:
174312bdcf33SDavid Howells 		afs_extract_to_tmp(call);
17445cf9dd55SDavid Howells 		call->unmarshall++;
1745df561f66SGustavo A. R. Silva 		fallthrough;
17465cf9dd55SDavid Howells 
17475cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
17485cf9dd55SDavid Howells 	case 1:
17495cf9dd55SDavid Howells 		_debug("extract status count");
175012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17515cf9dd55SDavid Howells 		if (ret < 0)
17525cf9dd55SDavid Howells 			return ret;
17535cf9dd55SDavid Howells 
17545cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
1755e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1756e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
17577126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
17585cf9dd55SDavid Howells 
17595cf9dd55SDavid Howells 		call->count = 0;
17605cf9dd55SDavid Howells 		call->unmarshall++;
17615cf9dd55SDavid Howells 	more_counts:
176212bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
1763df561f66SGustavo A. R. Silva 		fallthrough;
176429881608SGustavo A. R. Silva 
17655cf9dd55SDavid Howells 	case 2:
17665cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
176712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17685cf9dd55SDavid Howells 		if (ret < 0)
17695cf9dd55SDavid Howells 			return ret;
17705cf9dd55SDavid Howells 
1771e49c7b2fSDavid Howells 		switch (call->count) {
1772e49c7b2fSDavid Howells 		case 0:
1773e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1774e49c7b2fSDavid Howells 			break;
1775e49c7b2fSDavid Howells 		case 1:
1776e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1777e49c7b2fSDavid Howells 			break;
1778e49c7b2fSDavid Howells 		default:
1779e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1780e49c7b2fSDavid Howells 			break;
1781e49c7b2fSDavid Howells 		}
1782e49c7b2fSDavid Howells 
17835cf9dd55SDavid Howells 		bp = call->buffer;
178438355eecSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, scb);
1785e49c7b2fSDavid Howells 
17865cf9dd55SDavid Howells 		call->count++;
1787e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
17885cf9dd55SDavid Howells 			goto more_counts;
17895cf9dd55SDavid Howells 
17905cf9dd55SDavid Howells 		call->count = 0;
17915cf9dd55SDavid Howells 		call->unmarshall++;
179212bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1793df561f66SGustavo A. R. Silva 		fallthrough;
17945cf9dd55SDavid Howells 
17955cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
17965cf9dd55SDavid Howells 	case 3:
17975cf9dd55SDavid Howells 		_debug("extract CB count");
179812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17995cf9dd55SDavid Howells 		if (ret < 0)
18005cf9dd55SDavid Howells 			return ret;
18015cf9dd55SDavid Howells 
18025cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
18035cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
1804e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
18057126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
18065cf9dd55SDavid Howells 		call->count = 0;
18075cf9dd55SDavid Howells 		call->unmarshall++;
18085cf9dd55SDavid Howells 	more_cbs:
180912bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
1810df561f66SGustavo A. R. Silva 		fallthrough;
181129881608SGustavo A. R. Silva 
18125cf9dd55SDavid Howells 	case 4:
18135cf9dd55SDavid Howells 		_debug("extract CB array");
181412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18155cf9dd55SDavid Howells 		if (ret < 0)
18165cf9dd55SDavid Howells 			return ret;
18175cf9dd55SDavid Howells 
18185cf9dd55SDavid Howells 		_debug("unmarshall CB array");
1819e49c7b2fSDavid Howells 		switch (call->count) {
1820e49c7b2fSDavid Howells 		case 0:
1821e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1822e49c7b2fSDavid Howells 			break;
1823e49c7b2fSDavid Howells 		case 1:
1824e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1825e49c7b2fSDavid Howells 			break;
1826e49c7b2fSDavid Howells 		default:
1827e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1828e49c7b2fSDavid Howells 			break;
1829e49c7b2fSDavid Howells 		}
1830e49c7b2fSDavid Howells 
18315cf9dd55SDavid Howells 		bp = call->buffer;
1832a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
18335cf9dd55SDavid Howells 		call->count++;
1834e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
18355cf9dd55SDavid Howells 			goto more_cbs;
18365cf9dd55SDavid Howells 
183712bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
18385cf9dd55SDavid Howells 		call->unmarshall++;
1839df561f66SGustavo A. R. Silva 		fallthrough;
184029881608SGustavo A. R. Silva 
18415cf9dd55SDavid Howells 	case 5:
184212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
18435cf9dd55SDavid Howells 		if (ret < 0)
18445cf9dd55SDavid Howells 			return ret;
18455cf9dd55SDavid Howells 
18465cf9dd55SDavid Howells 		bp = call->buffer;
1847e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
18485cf9dd55SDavid Howells 
18495cf9dd55SDavid Howells 		call->unmarshall++;
1850*b2db6c35SGustavo A. R. Silva 		fallthrough;
18515cf9dd55SDavid Howells 
18525cf9dd55SDavid Howells 	case 6:
18535cf9dd55SDavid Howells 		break;
18545cf9dd55SDavid Howells 	}
18555cf9dd55SDavid Howells 
18565cf9dd55SDavid Howells 	_leave(" = 0 [done]");
18575cf9dd55SDavid Howells 	return 0;
18585cf9dd55SDavid Howells }
18595cf9dd55SDavid Howells 
1860e49c7b2fSDavid Howells static void afs_done_fs_inline_bulk_status(struct afs_call *call)
1861e49c7b2fSDavid Howells {
1862e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
186320325960SDavid Howells 	    call->abort_code == RX_INVALID_OPERATION) {
1864e49c7b2fSDavid Howells 		set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags);
186520325960SDavid Howells 		if (call->op)
186620325960SDavid Howells 			set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags);
186720325960SDavid Howells 	}
1868e49c7b2fSDavid Howells }
1869e49c7b2fSDavid Howells 
18705cf9dd55SDavid Howells /*
18715cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
18725cf9dd55SDavid Howells  */
18735cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
18745cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
18755cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
18765cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
1877e49c7b2fSDavid Howells 	.done		= afs_done_fs_inline_bulk_status,
18785cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
18795cf9dd55SDavid Howells };
18805cf9dd55SDavid Howells 
18815cf9dd55SDavid Howells /*
18825cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
18835cf9dd55SDavid Howells  */
1884e49c7b2fSDavid Howells void afs_fs_inline_bulk_status(struct afs_operation *op)
18855cf9dd55SDavid Howells {
1886e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1887e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
18885cf9dd55SDavid Howells 	struct afs_call *call;
18895cf9dd55SDavid Howells 	__be32 *bp;
18905cf9dd55SDavid Howells 	int i;
18915cf9dd55SDavid Howells 
189220325960SDavid Howells 	if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) {
1893e49c7b2fSDavid Howells 		op->error = -ENOTSUPP;
1894e49c7b2fSDavid Howells 		return;
18955cf9dd55SDavid Howells 	}
18965cf9dd55SDavid Howells 
1897e49c7b2fSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1898e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
1899e49c7b2fSDavid Howells 
1900e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus,
1901e49c7b2fSDavid Howells 				   (2 + op->nr_files * 3) * 4,
1902e49c7b2fSDavid Howells 				   21 * 4);
1903e49c7b2fSDavid Howells 	if (!call)
1904e49c7b2fSDavid Howells 		return afs_op_nomem(op);
19055cf9dd55SDavid Howells 
19065cf9dd55SDavid Howells 	/* marshall the parameters */
19075cf9dd55SDavid Howells 	bp = call->request;
19085cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
1909e49c7b2fSDavid Howells 	*bp++ = htonl(op->nr_files);
1910e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
1911e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
1912e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
1913e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1914e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1915e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1916e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++) {
1917e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vid);
1918e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vnode);
1919e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.unique);
19205cf9dd55SDavid Howells 	}
19215cf9dd55SDavid Howells 
1922e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1923e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
19245cf9dd55SDavid Howells }
1925260f082bSDavid Howells 
1926260f082bSDavid Howells /*
1927260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
1928260f082bSDavid Howells  */
1929260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
1930260f082bSDavid Howells {
1931e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1932e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1933260f082bSDavid Howells 	struct afs_acl *acl;
1934260f082bSDavid Howells 	const __be32 *bp;
1935260f082bSDavid Howells 	unsigned int size;
1936260f082bSDavid Howells 	int ret;
1937260f082bSDavid Howells 
1938260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
1939260f082bSDavid Howells 
1940260f082bSDavid Howells 	switch (call->unmarshall) {
1941260f082bSDavid Howells 	case 0:
1942260f082bSDavid Howells 		afs_extract_to_tmp(call);
1943260f082bSDavid Howells 		call->unmarshall++;
1944df561f66SGustavo A. R. Silva 		fallthrough;
1945260f082bSDavid Howells 
1946260f082bSDavid Howells 		/* extract the returned data length */
1947260f082bSDavid Howells 	case 1:
1948260f082bSDavid Howells 		ret = afs_extract_data(call, true);
1949260f082bSDavid Howells 		if (ret < 0)
1950260f082bSDavid Howells 			return ret;
1951260f082bSDavid Howells 
1952260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1953260f082bSDavid Howells 		size = round_up(size, 4);
1954260f082bSDavid Howells 
1955260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1956260f082bSDavid Howells 		if (!acl)
1957260f082bSDavid Howells 			return -ENOMEM;
1958e49c7b2fSDavid Howells 		op->acl = acl;
1959260f082bSDavid Howells 		acl->size = call->count2;
1960260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
1961260f082bSDavid Howells 		call->unmarshall++;
1962df561f66SGustavo A. R. Silva 		fallthrough;
1963260f082bSDavid Howells 
1964260f082bSDavid Howells 		/* extract the returned data */
1965260f082bSDavid Howells 	case 2:
1966260f082bSDavid Howells 		ret = afs_extract_data(call, true);
1967260f082bSDavid Howells 		if (ret < 0)
1968260f082bSDavid Howells 			return ret;
1969260f082bSDavid Howells 
1970260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
1971260f082bSDavid Howells 		call->unmarshall++;
1972df561f66SGustavo A. R. Silva 		fallthrough;
1973260f082bSDavid Howells 
1974260f082bSDavid Howells 		/* extract the metadata */
1975260f082bSDavid Howells 	case 3:
1976260f082bSDavid Howells 		ret = afs_extract_data(call, false);
1977260f082bSDavid Howells 		if (ret < 0)
1978260f082bSDavid Howells 			return ret;
1979260f082bSDavid Howells 
1980260f082bSDavid Howells 		bp = call->buffer;
1981e49c7b2fSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
1982e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
1983260f082bSDavid Howells 
1984260f082bSDavid Howells 		call->unmarshall++;
1985*b2db6c35SGustavo A. R. Silva 		fallthrough;
1986260f082bSDavid Howells 
1987260f082bSDavid Howells 	case 4:
1988260f082bSDavid Howells 		break;
1989260f082bSDavid Howells 	}
1990260f082bSDavid Howells 
1991260f082bSDavid Howells 	_leave(" = 0 [done]");
1992260f082bSDavid Howells 	return 0;
1993260f082bSDavid Howells }
1994260f082bSDavid Howells 
1995260f082bSDavid Howells /*
1996260f082bSDavid Howells  * FS.FetchACL operation type
1997260f082bSDavid Howells  */
1998260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
1999260f082bSDavid Howells 	.name		= "FS.FetchACL",
2000260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2001260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2002260f082bSDavid Howells };
2003260f082bSDavid Howells 
2004260f082bSDavid Howells /*
2005260f082bSDavid Howells  * Fetch the ACL for a file.
2006260f082bSDavid Howells  */
2007e49c7b2fSDavid Howells void afs_fs_fetch_acl(struct afs_operation *op)
2008260f082bSDavid Howells {
2009e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2010260f082bSDavid Howells 	struct afs_call *call;
2011260f082bSDavid Howells 	__be32 *bp;
2012260f082bSDavid Howells 
2013260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2014e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2015260f082bSDavid Howells 
2016e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2017e49c7b2fSDavid Howells 	if (!call)
2018e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2019260f082bSDavid Howells 
2020260f082bSDavid Howells 	/* marshall the parameters */
2021260f082bSDavid Howells 	bp = call->request;
2022260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2023e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2024e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2025e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2026260f082bSDavid Howells 
2027e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2028e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
2029ffba718eSDavid Howells }
2030ffba718eSDavid Howells 
2031ffba718eSDavid Howells /*
2032b10494afSJoe Gorse  * FS.StoreACL operation type
2033b10494afSJoe Gorse  */
2034b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2035b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2036b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2037ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2038b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2039b10494afSJoe Gorse };
2040b10494afSJoe Gorse 
2041b10494afSJoe Gorse /*
2042b10494afSJoe Gorse  * Fetch the ACL for a file.
2043b10494afSJoe Gorse  */
2044e49c7b2fSDavid Howells void afs_fs_store_acl(struct afs_operation *op)
2045b10494afSJoe Gorse {
2046e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2047b10494afSJoe Gorse 	struct afs_call *call;
2048e49c7b2fSDavid Howells 	const struct afs_acl *acl = op->acl;
2049b10494afSJoe Gorse 	size_t size;
2050b10494afSJoe Gorse 	__be32 *bp;
2051b10494afSJoe Gorse 
2052b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2053e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2054b10494afSJoe Gorse 
2055b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2056e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL,
2057b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2058e49c7b2fSDavid Howells 	if (!call)
2059e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2060b10494afSJoe Gorse 
2061b10494afSJoe Gorse 	/* marshall the parameters */
2062b10494afSJoe Gorse 	bp = call->request;
2063b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2064e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2065e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2066e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2067b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2068b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2069b10494afSJoe Gorse 	if (acl->size != size)
2070b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2071b10494afSJoe Gorse 
2072e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2073e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
20741da177e4SLinus Torvalds }
2075