xref: /openbmc/linux/fs/afs/fsclient.c (revision df561f66)
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>
131da177e4SLinus Torvalds #include "internal.h"
1408e0e7c8SDavid Howells #include "afs_fs.h"
15dd9fbcb8SDavid Howells #include "xdr_fs.h"
16c435ee34SDavid Howells 
176db3ac3cSDavid Howells /*
18260a9803SDavid Howells  * decode an AFSFid block
19260a9803SDavid Howells  */
20260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
21260a9803SDavid Howells {
22260a9803SDavid Howells 	const __be32 *bp = *_bp;
23260a9803SDavid Howells 
24260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
25260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
26260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
27260a9803SDavid Howells 	*_bp = bp;
28260a9803SDavid Howells }
29260a9803SDavid Howells 
30260a9803SDavid Howells /*
31888b3384SDavid Howells  * Dump a bad file status record.
32888b3384SDavid Howells  */
33888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
34888b3384SDavid Howells {
35888b3384SDavid Howells 	__be32 x[4];
36888b3384SDavid Howells 	int i;
37888b3384SDavid Howells 
38888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
39888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
40888b3384SDavid Howells 		memcpy(x, bp, 16);
41888b3384SDavid Howells 		bp += 4;
42888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
43888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
44888b3384SDavid Howells 	}
45888b3384SDavid Howells 
46888b3384SDavid Howells 	memcpy(x, bp, 4);
47888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
48888b3384SDavid Howells }
49888b3384SDavid Howells 
50888b3384SDavid Howells /*
51dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
52dd9fbcb8SDavid Howells  */
5338355eecSDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
54a58823acSDavid Howells 				      struct afs_call *call,
55a58823acSDavid Howells 				      struct afs_status_cb *scb)
56dd9fbcb8SDavid Howells {
57dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
58a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
59684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
60dd9fbcb8SDavid Howells 	u64 data_version, size;
61dd9fbcb8SDavid Howells 	u32 type, abort_code;
62dd9fbcb8SDavid Howells 
63684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
64684b0f68SDavid Howells 
65dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
66684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
67684b0f68SDavid Howells 		    abort_code != 0 &&
68684b0f68SDavid Howells 		    inline_error) {
69684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
70684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
71684b0f68SDavid Howells 			 * case.
72684b0f68SDavid Howells 			 */
73684b0f68SDavid Howells 			status->abort_code = abort_code;
74a38a7558SDavid Howells 			scb->have_error = true;
7538355eecSDavid Howells 			goto advance;
76684b0f68SDavid Howells 		}
77684b0f68SDavid Howells 
78dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
79dd9fbcb8SDavid Howells 		goto bad;
80dd9fbcb8SDavid Howells 	}
81dd9fbcb8SDavid Howells 
82684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
83684b0f68SDavid Howells 		status->abort_code = abort_code;
843e0d9892SDavid Howells 		scb->have_error = true;
8538355eecSDavid Howells 		goto advance;
86684b0f68SDavid Howells 	}
87684b0f68SDavid Howells 
88dd9fbcb8SDavid Howells 	type = ntohl(xdr->type);
89dd9fbcb8SDavid Howells 	switch (type) {
90dd9fbcb8SDavid Howells 	case AFS_FTYPE_FILE:
91dd9fbcb8SDavid Howells 	case AFS_FTYPE_DIR:
92dd9fbcb8SDavid Howells 	case AFS_FTYPE_SYMLINK:
93dd9fbcb8SDavid Howells 		status->type = type;
94dd9fbcb8SDavid Howells 		break;
95dd9fbcb8SDavid Howells 	default:
96dd9fbcb8SDavid Howells 		goto bad;
97dd9fbcb8SDavid Howells 	}
98dd9fbcb8SDavid Howells 
99a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
100a58823acSDavid Howells 	status->author		= ntohl(xdr->author);
101a58823acSDavid Howells 	status->owner		= ntohl(xdr->owner);
102a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
103a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
104a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
105a58823acSDavid Howells 	status->group		= ntohl(xdr->group);
106a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
107dd9fbcb8SDavid Howells 
108d4936803SDavid Howells 	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
109d4936803SDavid Howells 	status->mtime_client.tv_nsec = 0;
110d4936803SDavid Howells 	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
111d4936803SDavid Howells 	status->mtime_server.tv_nsec = 0;
112dd9fbcb8SDavid Howells 
113dd9fbcb8SDavid Howells 	size  = (u64)ntohl(xdr->size_lo);
114dd9fbcb8SDavid Howells 	size |= (u64)ntohl(xdr->size_hi) << 32;
115dd9fbcb8SDavid Howells 	status->size = size;
116dd9fbcb8SDavid Howells 
117dd9fbcb8SDavid Howells 	data_version  = (u64)ntohl(xdr->data_version_lo);
118dd9fbcb8SDavid Howells 	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
119dd9fbcb8SDavid Howells 	status->data_version = data_version;
120a38a7558SDavid Howells 	scb->have_status = true;
121c72057b5SDavid Howells advance:
122dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
12338355eecSDavid Howells 	return;
124dd9fbcb8SDavid Howells 
125dd9fbcb8SDavid Howells bad:
126dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
1277126ead9SDavid Howells 	afs_protocol_error(call, afs_eproto_bad_status);
128c72057b5SDavid Howells 	goto advance;
129c875c76aSDavid Howells }
130c875c76aSDavid Howells 
13178107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
13278107055SDavid Howells {
13378107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
13478107055SDavid Howells }
13578107055SDavid Howells 
136a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
137a58823acSDavid Howells 				   struct afs_call *call,
138a58823acSDavid Howells 				   struct afs_status_cb *scb)
13978107055SDavid Howells {
140a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
14178107055SDavid Howells 	const __be32 *bp = *_bp;
14278107055SDavid Howells 
1437c712458SDavid Howells 	bp++; /* version */
14478107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1457c712458SDavid Howells 	bp++; /* type */
146a58823acSDavid Howells 	scb->have_cb	= true;
14778107055SDavid Howells 	*_bp = bp;
14878107055SDavid Howells }
14978107055SDavid Howells 
1501da177e4SLinus Torvalds /*
15108e0e7c8SDavid Howells  * decode an AFSVolSync block
1521da177e4SLinus Torvalds  */
15308e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
15408e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1551da177e4SLinus Torvalds {
15608e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
15730062bd1SDavid Howells 	u32 creation;
1581da177e4SLinus Torvalds 
15930062bd1SDavid Howells 	creation = ntohl(*bp++);
16008e0e7c8SDavid Howells 	bp++; /* spare2 */
16108e0e7c8SDavid Howells 	bp++; /* spare3 */
16208e0e7c8SDavid Howells 	bp++; /* spare4 */
16308e0e7c8SDavid Howells 	bp++; /* spare5 */
16408e0e7c8SDavid Howells 	bp++; /* spare6 */
16508e0e7c8SDavid Howells 	*_bp = bp;
16630062bd1SDavid Howells 
16730062bd1SDavid Howells 	if (volsync)
16830062bd1SDavid Howells 		volsync->creation = creation;
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds 
17108e0e7c8SDavid Howells /*
17231143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
17331143d5dSDavid Howells  */
17431143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
17531143d5dSDavid Howells {
17631143d5dSDavid Howells 	__be32 *bp = *_bp;
17731143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
17831143d5dSDavid Howells 
17931143d5dSDavid Howells 	mask = 0;
18031143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18131143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
18231143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
18331143d5dSDavid Howells 	}
18431143d5dSDavid Howells 
18531143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
18631143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
187a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
18831143d5dSDavid Howells 	}
18931143d5dSDavid Howells 
19031143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19131143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
192a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
19331143d5dSDavid Howells 	}
19431143d5dSDavid Howells 
19531143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
19631143d5dSDavid Howells 		mask |= AFS_SET_MODE;
19731143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
19831143d5dSDavid Howells 	}
19931143d5dSDavid Howells 
20031143d5dSDavid Howells 	*bp++ = htonl(mask);
20131143d5dSDavid Howells 	*bp++ = htonl(mtime);
20231143d5dSDavid Howells 	*bp++ = htonl(owner);
20331143d5dSDavid Howells 	*bp++ = htonl(group);
20431143d5dSDavid Howells 	*bp++ = htonl(mode);
20531143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
20631143d5dSDavid Howells 	*_bp = bp;
20731143d5dSDavid Howells }
20831143d5dSDavid Howells 
20931143d5dSDavid Howells /*
21045222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21145222b9eSDavid Howells  */
21245222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
21345222b9eSDavid Howells 					    struct afs_volume_status *vs)
21445222b9eSDavid Howells {
21545222b9eSDavid Howells 	const __be32 *bp = *_bp;
21645222b9eSDavid Howells 
21745222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
21845222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
21945222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22045222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22145222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
22245222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
22345222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
22445222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
22545222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
22930062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23030062bd1SDavid Howells 	vs->vol_backup_date	= 0;
23145222b9eSDavid Howells 	*_bp = bp;
23245222b9eSDavid Howells }
23345222b9eSDavid Howells 
23445222b9eSDavid Howells /*
23508e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
23608e0e7c8SDavid Howells  */
237e49c7b2fSDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
23808e0e7c8SDavid Howells {
239e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
240e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
24108e0e7c8SDavid Howells 	const __be32 *bp;
242372ee163SDavid Howells 	int ret;
2431da177e4SLinus Torvalds 
244d001648eSDavid Howells 	ret = afs_transfer_reply(call);
245372ee163SDavid Howells 	if (ret < 0)
246372ee163SDavid Howells 		return ret;
2471da177e4SLinus Torvalds 
24808e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
24908e0e7c8SDavid Howells 	bp = call->buffer;
250e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
251e49c7b2fSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
252e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
2531da177e4SLinus Torvalds 
25408e0e7c8SDavid Howells 	_leave(" = 0 [done]");
25508e0e7c8SDavid Howells 	return 0;
256ec26815aSDavid Howells }
25708e0e7c8SDavid Howells 
25808e0e7c8SDavid Howells /*
25908e0e7c8SDavid Howells  * FS.FetchStatus operation type
26008e0e7c8SDavid Howells  */
261e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
262e49c7b2fSDavid Howells 	.name		= "FS.FetchStatus",
263025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
264e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
26508e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
26608e0e7c8SDavid Howells };
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds /*
2691da177e4SLinus Torvalds  * fetch the status information for a file
2701da177e4SLinus Torvalds  */
271e49c7b2fSDavid Howells void afs_fs_fetch_status(struct afs_operation *op)
2721da177e4SLinus Torvalds {
273e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[op->fetch_status.which];
27408e0e7c8SDavid Howells 	struct afs_call *call;
2751da177e4SLinus Torvalds 	__be32 *bp;
2761da177e4SLinus Torvalds 
2773b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
278e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2791da177e4SLinus Torvalds 
280e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchStatus,
2815cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
282e49c7b2fSDavid Howells 	if (!call)
283e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	/* marshall the parameters */
28608e0e7c8SDavid Howells 	bp = call->request;
2871da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
288e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
289e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
290e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2911da177e4SLinus Torvalds 
292e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
293e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
294ec26815aSDavid Howells }
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds /*
29708e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
2981da177e4SLinus Torvalds  */
299d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3001da177e4SLinus Torvalds {
301e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
302e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
303e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
30408e0e7c8SDavid Howells 	const __be32 *bp;
305196ee9cdSDavid Howells 	unsigned int size;
3061da177e4SLinus Torvalds 	int ret;
3071da177e4SLinus Torvalds 
30812bdcf33SDavid Howells 	_enter("{%u,%zu/%llu}",
309fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
3101da177e4SLinus Torvalds 
31108e0e7c8SDavid Howells 	switch (call->unmarshall) {
31208e0e7c8SDavid Howells 	case 0:
313196ee9cdSDavid Howells 		req->actual_len = 0;
31412bdcf33SDavid Howells 		req->index = 0;
31512bdcf33SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
31608e0e7c8SDavid Howells 		call->unmarshall++;
31712bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
31812bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
31912bdcf33SDavid Howells 		} else {
32012bdcf33SDavid Howells 			call->tmp_u = htonl(0);
32112bdcf33SDavid Howells 			afs_extract_to_tmp(call);
322b9b1f8d5SDavid Howells 		}
323df561f66SGustavo A. R. Silva 		fallthrough;
3241da177e4SLinus Torvalds 
32529881608SGustavo A. R. Silva 		/* extract the returned data length */
32612bdcf33SDavid Howells 	case 1:
32708e0e7c8SDavid Howells 		_debug("extract data length");
32812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
329372ee163SDavid Howells 		if (ret < 0)
330372ee163SDavid Howells 			return ret;
3311da177e4SLinus Torvalds 
33212bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
333196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
33412bdcf33SDavid Howells 		req->remain = min(req->len, req->actual_len);
33512bdcf33SDavid Howells 		if (req->remain == 0)
336196ee9cdSDavid Howells 			goto no_more_data;
33712bdcf33SDavid Howells 
33808e0e7c8SDavid Howells 		call->unmarshall++;
3391da177e4SLinus Torvalds 
340196ee9cdSDavid Howells 	begin_page:
3416db3ac3cSDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
34212bdcf33SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
34312bdcf33SDavid Howells 			size = PAGE_SIZE - req->offset;
344196ee9cdSDavid Howells 		else
345196ee9cdSDavid Howells 			size = req->remain;
34612bdcf33SDavid Howells 		call->bvec[0].bv_len = size;
34712bdcf33SDavid Howells 		call->bvec[0].bv_offset = req->offset;
34812bdcf33SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
349fc276122SDavid Howells 		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
35012bdcf33SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
351df561f66SGustavo A. R. Silva 		fallthrough;
352196ee9cdSDavid Howells 
35329881608SGustavo A. R. Silva 		/* extract the returned data */
35412bdcf33SDavid Howells 	case 2:
35512bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
356fc276122SDavid Howells 		       iov_iter_count(call->iter), req->remain);
357196ee9cdSDavid Howells 
35812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
359372ee163SDavid Howells 		if (ret < 0)
360372ee163SDavid Howells 			return ret;
36112bdcf33SDavid Howells 		req->remain -= call->bvec[0].bv_len;
36212bdcf33SDavid Howells 		req->offset += call->bvec[0].bv_len;
36312bdcf33SDavid Howells 		ASSERTCMP(req->offset, <=, PAGE_SIZE);
36412bdcf33SDavid Howells 		if (req->offset == PAGE_SIZE) {
36512bdcf33SDavid Howells 			req->offset = 0;
36629f06985SDavid Howells 			req->index++;
36712bdcf33SDavid Howells 			if (req->remain > 0)
368196ee9cdSDavid Howells 				goto begin_page;
369196ee9cdSDavid Howells 		}
37012bdcf33SDavid Howells 
37112bdcf33SDavid Howells 		ASSERTCMP(req->remain, ==, 0);
37212bdcf33SDavid Howells 		if (req->actual_len <= req->len)
3736db3ac3cSDavid Howells 			goto no_more_data;
3746db3ac3cSDavid Howells 
3756db3ac3cSDavid Howells 		/* Discard any excess data the server gave us */
37623a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
37712bdcf33SDavid Howells 		call->unmarshall = 3;
378df561f66SGustavo A. R. Silva 		fallthrough;
37929881608SGustavo A. R. Silva 
38012bdcf33SDavid Howells 	case 3:
38112bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
382fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
3836db3ac3cSDavid Howells 
38412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
3856db3ac3cSDavid Howells 		if (ret < 0)
3866db3ac3cSDavid Howells 			return ret;
3871da177e4SLinus Torvalds 
388196ee9cdSDavid Howells 	no_more_data:
38912bdcf33SDavid Howells 		call->unmarshall = 4;
39012bdcf33SDavid Howells 		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
391df561f66SGustavo A. R. Silva 		fallthrough;
39208e0e7c8SDavid Howells 
39329881608SGustavo A. R. Silva 		/* extract the metadata */
39412bdcf33SDavid Howells 	case 4:
39512bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
396372ee163SDavid Howells 		if (ret < 0)
397372ee163SDavid Howells 			return ret;
3981da177e4SLinus Torvalds 
39908e0e7c8SDavid Howells 		bp = call->buffer;
400e49c7b2fSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
401e49c7b2fSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, &vp->scb);
402e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
4031da177e4SLinus Torvalds 
404e49c7b2fSDavid Howells 		req->data_version = vp->scb.status.data_version;
405e49c7b2fSDavid Howells 		req->file_size = vp->scb.status.size;
406a58823acSDavid Howells 
40708e0e7c8SDavid Howells 		call->unmarshall++;
4081da177e4SLinus Torvalds 
40912bdcf33SDavid Howells 	case 5:
4101da177e4SLinus Torvalds 		break;
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds 
4136db3ac3cSDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
41412bdcf33SDavid Howells 		if (req->offset < PAGE_SIZE)
4156db3ac3cSDavid Howells 			zero_user_segment(req->pages[req->index],
41612bdcf33SDavid Howells 					  req->offset, PAGE_SIZE);
41712bdcf33SDavid Howells 		req->offset = 0;
418416351f2SDavid Howells 	}
419416351f2SDavid Howells 
4209d1be4f4SDavid Howells 	if (req->page_done)
4219d1be4f4SDavid Howells 		for (req->index = 0; req->index < req->nr_pages; req->index++)
4229d1be4f4SDavid Howells 			req->page_done(req);
4239d1be4f4SDavid Howells 
42408e0e7c8SDavid Howells 	_leave(" = 0 [done]");
42508e0e7c8SDavid Howells 	return 0;
426ec26815aSDavid Howells }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds /*
42908e0e7c8SDavid Howells  * FS.FetchData operation type
4301da177e4SLinus Torvalds  */
43108e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
43200d3b7a4SDavid Howells 	.name		= "FS.FetchData",
433025db80cSDavid Howells 	.op		= afs_FS_FetchData,
43408e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
435e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
43608e0e7c8SDavid Howells };
43708e0e7c8SDavid Howells 
438b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
439b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
440025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
441b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
442e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
443b9b1f8d5SDavid Howells };
444b9b1f8d5SDavid Howells 
445b9b1f8d5SDavid Howells /*
446b9b1f8d5SDavid Howells  * fetch data from a very large file
447b9b1f8d5SDavid Howells  */
448e49c7b2fSDavid Howells static void afs_fs_fetch_data64(struct afs_operation *op)
449b9b1f8d5SDavid Howells {
450e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
451e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
452b9b1f8d5SDavid Howells 	struct afs_call *call;
453b9b1f8d5SDavid Howells 	__be32 *bp;
454b9b1f8d5SDavid Howells 
455b9b1f8d5SDavid Howells 	_enter("");
456b9b1f8d5SDavid Howells 
457e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
458b9b1f8d5SDavid Howells 	if (!call)
459e49c7b2fSDavid Howells 		return afs_op_nomem(op);
460b9b1f8d5SDavid Howells 
461b9b1f8d5SDavid Howells 	/* marshall the parameters */
462b9b1f8d5SDavid Howells 	bp = call->request;
463b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
464e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
465e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
466e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
467196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
468196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
469b9b1f8d5SDavid Howells 	bp[6] = 0;
470196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
471b9b1f8d5SDavid Howells 
472e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
473e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
474b9b1f8d5SDavid Howells }
475b9b1f8d5SDavid Howells 
47608e0e7c8SDavid Howells /*
47708e0e7c8SDavid Howells  * fetch data from a file
47808e0e7c8SDavid Howells  */
479e49c7b2fSDavid Howells void afs_fs_fetch_data(struct afs_operation *op)
4801da177e4SLinus Torvalds {
481e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
48208e0e7c8SDavid Howells 	struct afs_call *call;
483e49c7b2fSDavid Howells 	struct afs_read *req = op->fetch.req;
48408e0e7c8SDavid Howells 	__be32 *bp;
4851da177e4SLinus Torvalds 
486196ee9cdSDavid Howells 	if (upper_32_bits(req->pos) ||
487196ee9cdSDavid Howells 	    upper_32_bits(req->len) ||
488196ee9cdSDavid Howells 	    upper_32_bits(req->pos + req->len))
489e49c7b2fSDavid Howells 		return afs_fs_fetch_data64(op);
490b9b1f8d5SDavid Howells 
49108e0e7c8SDavid Howells 	_enter("");
4921da177e4SLinus Torvalds 
493e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
49408e0e7c8SDavid Howells 	if (!call)
495e49c7b2fSDavid Howells 		return afs_op_nomem(op);
4961da177e4SLinus Torvalds 
4971da177e4SLinus Torvalds 	/* marshall the parameters */
49808e0e7c8SDavid Howells 	bp = call->request;
49908e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
500e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
501e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
502e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
503196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
504196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
5051da177e4SLinus Torvalds 
506e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
507e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
50808e0e7c8SDavid Howells }
509260a9803SDavid Howells 
510260a9803SDavid Howells /*
511260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
512260a9803SDavid Howells  */
513d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
514260a9803SDavid Howells {
515e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
516e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
517e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
518260a9803SDavid Howells 	const __be32 *bp;
519372ee163SDavid Howells 	int ret;
520260a9803SDavid Howells 
521d001648eSDavid Howells 	ret = afs_transfer_reply(call);
522372ee163SDavid Howells 	if (ret < 0)
523372ee163SDavid Howells 		return ret;
524260a9803SDavid Howells 
525260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
526260a9803SDavid Howells 	bp = call->buffer;
527e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &op->file[1].fid);
528e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
529e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
530e49c7b2fSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, &vp->scb);
531e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
532260a9803SDavid Howells 
533260a9803SDavid Howells 	_leave(" = 0 [done]");
534260a9803SDavid Howells 	return 0;
535260a9803SDavid Howells }
536260a9803SDavid Howells 
537260a9803SDavid Howells /*
538260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
539260a9803SDavid Howells  */
540025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
541025db80cSDavid Howells 	.name		= "FS.CreateFile",
542025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
543025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
544025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
545025db80cSDavid Howells };
546025db80cSDavid Howells 
547e49c7b2fSDavid Howells /*
548e49c7b2fSDavid Howells  * Create a file.
549e49c7b2fSDavid Howells  */
550e49c7b2fSDavid Howells void afs_fs_create_file(struct afs_operation *op)
551e49c7b2fSDavid Howells {
552e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
553e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
554e49c7b2fSDavid Howells 	struct afs_call *call;
555e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
556e49c7b2fSDavid Howells 	__be32 *bp;
557e49c7b2fSDavid Howells 
558e49c7b2fSDavid Howells 	_enter("");
559e49c7b2fSDavid Howells 
560e49c7b2fSDavid Howells 	namesz = name->len;
561e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
562e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
563e49c7b2fSDavid Howells 
564e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSCreateFile,
565e49c7b2fSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
566e49c7b2fSDavid Howells 	if (!call)
567e49c7b2fSDavid Howells 		return afs_op_nomem(op);
568e49c7b2fSDavid Howells 
569e49c7b2fSDavid Howells 	/* marshall the parameters */
570e49c7b2fSDavid Howells 	bp = call->request;
571e49c7b2fSDavid Howells 	*bp++ = htonl(FSCREATEFILE);
572e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
573e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
574e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
575e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
576e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
577e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
578e49c7b2fSDavid Howells 	if (padsz > 0) {
579e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
580e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
581e49c7b2fSDavid Howells 	}
582e49c7b2fSDavid Howells 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
583e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
584e49c7b2fSDavid Howells 	*bp++ = 0; /* owner */
585e49c7b2fSDavid Howells 	*bp++ = 0; /* group */
586e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
587e49c7b2fSDavid Howells 	*bp++ = 0; /* segment size */
588e49c7b2fSDavid Howells 
589e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
590e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
591e49c7b2fSDavid Howells }
592e49c7b2fSDavid Howells 
593025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
594025db80cSDavid Howells 	.name		= "FS.MakeDir",
595025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
596260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
597260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
598260a9803SDavid Howells };
599260a9803SDavid Howells 
600260a9803SDavid Howells /*
601e49c7b2fSDavid Howells  * Create a new directory
602260a9803SDavid Howells  */
603e49c7b2fSDavid Howells void afs_fs_make_dir(struct afs_operation *op)
604260a9803SDavid Howells {
605e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
606e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
607260a9803SDavid Howells 	struct afs_call *call;
608260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
609260a9803SDavid Howells 	__be32 *bp;
610260a9803SDavid Howells 
611260a9803SDavid Howells 	_enter("");
612260a9803SDavid Howells 
613e49c7b2fSDavid Howells 	namesz = name->len;
614260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
615260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
616260a9803SDavid Howells 
617e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSMakeDir,
618025db80cSDavid Howells 				   reqsz, (3 + 21 + 21 + 3 + 6) * 4);
619260a9803SDavid Howells 	if (!call)
620e49c7b2fSDavid Howells 		return afs_op_nomem(op);
621260a9803SDavid Howells 
622260a9803SDavid Howells 	/* marshall the parameters */
623260a9803SDavid Howells 	bp = call->request;
624e49c7b2fSDavid Howells 	*bp++ = htonl(FSMAKEDIR);
625e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
626e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
627e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
628260a9803SDavid Howells 	*bp++ = htonl(namesz);
629e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
630260a9803SDavid Howells 	bp = (void *) bp + namesz;
631260a9803SDavid Howells 	if (padsz > 0) {
632260a9803SDavid Howells 		memset(bp, 0, padsz);
633260a9803SDavid Howells 		bp = (void *) bp + padsz;
634260a9803SDavid Howells 	}
635ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
636e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
637260a9803SDavid Howells 	*bp++ = 0; /* owner */
638260a9803SDavid Howells 	*bp++ = 0; /* group */
639e49c7b2fSDavid Howells 	*bp++ = htonl(op->create.mode & S_IALLUGO); /* unix mode */
640260a9803SDavid Howells 	*bp++ = 0; /* segment size */
641260a9803SDavid Howells 
642e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
643e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
644260a9803SDavid Howells }
645260a9803SDavid Howells 
646260a9803SDavid Howells /*
647e49c7b2fSDavid Howells  * Deliver reply data to any operation that returns status and volume sync.
648260a9803SDavid Howells  */
649e49c7b2fSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
650260a9803SDavid Howells {
651e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
652e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
653260a9803SDavid Howells 	const __be32 *bp;
654372ee163SDavid Howells 	int ret;
655260a9803SDavid Howells 
656d001648eSDavid Howells 	ret = afs_transfer_reply(call);
657372ee163SDavid Howells 	if (ret < 0)
658372ee163SDavid Howells 		return ret;
659260a9803SDavid Howells 
660260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
661260a9803SDavid Howells 	bp = call->buffer;
662e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
663e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
664260a9803SDavid Howells 
665260a9803SDavid Howells 	_leave(" = 0 [done]");
666260a9803SDavid Howells 	return 0;
667260a9803SDavid Howells }
668260a9803SDavid Howells 
669260a9803SDavid Howells /*
670e49c7b2fSDavid Howells  * FS.RemoveFile operation type
671260a9803SDavid Howells  */
672025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
673025db80cSDavid Howells 	.name		= "FS.RemoveFile",
674025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
675e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
676260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
677260a9803SDavid Howells };
678260a9803SDavid Howells 
679260a9803SDavid Howells /*
680e49c7b2fSDavid Howells  * Remove a file.
681260a9803SDavid Howells  */
682e49c7b2fSDavid Howells void afs_fs_remove_file(struct afs_operation *op)
683260a9803SDavid Howells {
684e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
685e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
686260a9803SDavid Howells 	struct afs_call *call;
687260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
688260a9803SDavid Howells 	__be32 *bp;
689260a9803SDavid Howells 
690260a9803SDavid Howells 	_enter("");
691260a9803SDavid Howells 
692e49c7b2fSDavid Howells 	namesz = name->len;
693260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
694260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
695260a9803SDavid Howells 
696e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveFile,
697025db80cSDavid Howells 				   reqsz, (21 + 6) * 4);
698260a9803SDavid Howells 	if (!call)
699e49c7b2fSDavid Howells 		return afs_op_nomem(op);
700260a9803SDavid Howells 
701260a9803SDavid Howells 	/* marshall the parameters */
702260a9803SDavid Howells 	bp = call->request;
703e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEFILE);
704e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
705e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
706e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
707260a9803SDavid Howells 	*bp++ = htonl(namesz);
708e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
709260a9803SDavid Howells 	bp = (void *) bp + namesz;
710260a9803SDavid Howells 	if (padsz > 0) {
711260a9803SDavid Howells 		memset(bp, 0, padsz);
712260a9803SDavid Howells 		bp = (void *) bp + padsz;
713260a9803SDavid Howells 	}
714260a9803SDavid Howells 
715e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
716e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
717e49c7b2fSDavid Howells }
718e49c7b2fSDavid Howells 
719e49c7b2fSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
720e49c7b2fSDavid Howells 	.name		= "FS.RemoveDir",
721e49c7b2fSDavid Howells 	.op		= afs_FS_RemoveDir,
722e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
723e49c7b2fSDavid Howells 	.destructor	= afs_flat_call_destructor,
724e49c7b2fSDavid Howells };
725e49c7b2fSDavid Howells 
726e49c7b2fSDavid Howells /*
727e49c7b2fSDavid Howells  * Remove a directory.
728e49c7b2fSDavid Howells  */
729e49c7b2fSDavid Howells void afs_fs_remove_dir(struct afs_operation *op)
730e49c7b2fSDavid Howells {
731e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
732e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
733e49c7b2fSDavid Howells 	struct afs_call *call;
734e49c7b2fSDavid Howells 	size_t namesz, reqsz, padsz;
735e49c7b2fSDavid Howells 	__be32 *bp;
736e49c7b2fSDavid Howells 
737e49c7b2fSDavid Howells 	_enter("");
738e49c7b2fSDavid Howells 
739e49c7b2fSDavid Howells 	namesz = name->len;
740e49c7b2fSDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
741e49c7b2fSDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
742e49c7b2fSDavid Howells 
743e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRemoveDir,
744e49c7b2fSDavid Howells 				   reqsz, (21 + 6) * 4);
745e49c7b2fSDavid Howells 	if (!call)
746e49c7b2fSDavid Howells 		return afs_op_nomem(op);
747e49c7b2fSDavid Howells 
748e49c7b2fSDavid Howells 	/* marshall the parameters */
749e49c7b2fSDavid Howells 	bp = call->request;
750e49c7b2fSDavid Howells 	*bp++ = htonl(FSREMOVEDIR);
751e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
752e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
753e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
754e49c7b2fSDavid Howells 	*bp++ = htonl(namesz);
755e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
756e49c7b2fSDavid Howells 	bp = (void *) bp + namesz;
757e49c7b2fSDavid Howells 	if (padsz > 0) {
758e49c7b2fSDavid Howells 		memset(bp, 0, padsz);
759e49c7b2fSDavid Howells 		bp = (void *) bp + padsz;
760e49c7b2fSDavid Howells 	}
761e49c7b2fSDavid Howells 
762e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
763e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
764260a9803SDavid Howells }
765260a9803SDavid Howells 
766260a9803SDavid Howells /*
767260a9803SDavid Howells  * deliver reply data to an FS.Link
768260a9803SDavid Howells  */
769d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
770260a9803SDavid Howells {
771e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
772e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
773e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
774260a9803SDavid Howells 	const __be32 *bp;
775372ee163SDavid Howells 	int ret;
776260a9803SDavid Howells 
777d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
778260a9803SDavid Howells 
779d001648eSDavid Howells 	ret = afs_transfer_reply(call);
780372ee163SDavid Howells 	if (ret < 0)
781372ee163SDavid Howells 		return ret;
782260a9803SDavid Howells 
783260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
784260a9803SDavid Howells 	bp = call->buffer;
785e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
786e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
787e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
788260a9803SDavid Howells 
789260a9803SDavid Howells 	_leave(" = 0 [done]");
790260a9803SDavid Howells 	return 0;
791260a9803SDavid Howells }
792260a9803SDavid Howells 
793260a9803SDavid Howells /*
794260a9803SDavid Howells  * FS.Link operation type
795260a9803SDavid Howells  */
796260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
797260a9803SDavid Howells 	.name		= "FS.Link",
798025db80cSDavid Howells 	.op		= afs_FS_Link,
799260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
800260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
801260a9803SDavid Howells };
802260a9803SDavid Howells 
803260a9803SDavid Howells /*
804260a9803SDavid Howells  * make a hard link
805260a9803SDavid Howells  */
806e49c7b2fSDavid Howells void afs_fs_link(struct afs_operation *op)
807260a9803SDavid Howells {
808e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
809e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
810e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
811260a9803SDavid Howells 	struct afs_call *call;
812260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
813260a9803SDavid Howells 	__be32 *bp;
814260a9803SDavid Howells 
815260a9803SDavid Howells 	_enter("");
816260a9803SDavid Howells 
817e49c7b2fSDavid Howells 	namesz = name->len;
818260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
819260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
820260a9803SDavid Howells 
821e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
822260a9803SDavid Howells 	if (!call)
823e49c7b2fSDavid Howells 		return afs_op_nomem(op);
824260a9803SDavid Howells 
825260a9803SDavid Howells 	/* marshall the parameters */
826260a9803SDavid Howells 	bp = call->request;
827260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
828e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
829e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
830e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
831260a9803SDavid Howells 	*bp++ = htonl(namesz);
832e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
833260a9803SDavid Howells 	bp = (void *) bp + namesz;
834260a9803SDavid Howells 	if (padsz > 0) {
835260a9803SDavid Howells 		memset(bp, 0, padsz);
836260a9803SDavid Howells 		bp = (void *) bp + padsz;
837260a9803SDavid Howells 	}
838e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
839e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
840e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
841260a9803SDavid Howells 
842e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &vp->fid, name);
843e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
844260a9803SDavid Howells }
845260a9803SDavid Howells 
846260a9803SDavid Howells /*
847260a9803SDavid Howells  * deliver reply data to an FS.Symlink
848260a9803SDavid Howells  */
849d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
850260a9803SDavid Howells {
851e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
852e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
853e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
854260a9803SDavid Howells 	const __be32 *bp;
855372ee163SDavid Howells 	int ret;
856260a9803SDavid Howells 
857d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
858260a9803SDavid Howells 
859d001648eSDavid Howells 	ret = afs_transfer_reply(call);
860372ee163SDavid Howells 	if (ret < 0)
861372ee163SDavid Howells 		return ret;
862260a9803SDavid Howells 
863260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
864260a9803SDavid Howells 	bp = call->buffer;
865e49c7b2fSDavid Howells 	xdr_decode_AFSFid(&bp, &vp->fid);
866e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
867e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &dvp->scb);
868e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
869260a9803SDavid Howells 
870260a9803SDavid Howells 	_leave(" = 0 [done]");
871260a9803SDavid Howells 	return 0;
872260a9803SDavid Howells }
873260a9803SDavid Howells 
874260a9803SDavid Howells /*
875260a9803SDavid Howells  * FS.Symlink operation type
876260a9803SDavid Howells  */
877260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
878260a9803SDavid Howells 	.name		= "FS.Symlink",
879025db80cSDavid Howells 	.op		= afs_FS_Symlink,
880260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
881260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
882260a9803SDavid Howells };
883260a9803SDavid Howells 
884260a9803SDavid Howells /*
885260a9803SDavid Howells  * create a symbolic link
886260a9803SDavid Howells  */
887e49c7b2fSDavid Howells void afs_fs_symlink(struct afs_operation *op)
888260a9803SDavid Howells {
889e49c7b2fSDavid Howells 	const struct qstr *name = &op->dentry->d_name;
890e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
891260a9803SDavid Howells 	struct afs_call *call;
892260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
893260a9803SDavid Howells 	__be32 *bp;
894260a9803SDavid Howells 
895260a9803SDavid Howells 	_enter("");
896260a9803SDavid Howells 
897e49c7b2fSDavid Howells 	namesz = name->len;
898260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
899260a9803SDavid Howells 
900e49c7b2fSDavid Howells 	c_namesz = strlen(op->create.symlink);
901260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
902260a9803SDavid Howells 
903260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
904260a9803SDavid Howells 
905e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSymlink, reqsz,
906260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
907260a9803SDavid Howells 	if (!call)
908e49c7b2fSDavid Howells 		return afs_op_nomem(op);
909260a9803SDavid Howells 
910260a9803SDavid Howells 	/* marshall the parameters */
911260a9803SDavid Howells 	bp = call->request;
912260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
913e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
914e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
915e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
916260a9803SDavid Howells 	*bp++ = htonl(namesz);
917e49c7b2fSDavid Howells 	memcpy(bp, name->name, namesz);
918260a9803SDavid Howells 	bp = (void *) bp + namesz;
919260a9803SDavid Howells 	if (padsz > 0) {
920260a9803SDavid Howells 		memset(bp, 0, padsz);
921260a9803SDavid Howells 		bp = (void *) bp + padsz;
922260a9803SDavid Howells 	}
923260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
924e49c7b2fSDavid Howells 	memcpy(bp, op->create.symlink, c_namesz);
925260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
926260a9803SDavid Howells 	if (c_padsz > 0) {
927260a9803SDavid Howells 		memset(bp, 0, c_padsz);
928260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
929260a9803SDavid Howells 	}
930ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
931e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
932260a9803SDavid Howells 	*bp++ = 0; /* owner */
933260a9803SDavid Howells 	*bp++ = 0; /* group */
934260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
935260a9803SDavid Howells 	*bp++ = 0; /* segment size */
936260a9803SDavid Howells 
937e49c7b2fSDavid Howells 	trace_afs_make_fs_call1(call, &dvp->fid, name);
938e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
939260a9803SDavid Howells }
940260a9803SDavid Howells 
941260a9803SDavid Howells /*
942260a9803SDavid Howells  * deliver reply data to an FS.Rename
943260a9803SDavid Howells  */
944d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
945260a9803SDavid Howells {
946e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
947e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
948e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
949260a9803SDavid Howells 	const __be32 *bp;
950372ee163SDavid Howells 	int ret;
951260a9803SDavid Howells 
952d001648eSDavid Howells 	ret = afs_transfer_reply(call);
953372ee163SDavid Howells 	if (ret < 0)
954372ee163SDavid Howells 		return ret;
955260a9803SDavid Howells 
95638355eecSDavid Howells 	bp = call->buffer;
957b98f0ec9SDavid Howells 	/* If the two dirs are the same, we have two copies of the same status
958b98f0ec9SDavid Howells 	 * report, so we just decode it twice.
959b98f0ec9SDavid Howells 	 */
960e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &orig_dvp->scb);
961e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &new_dvp->scb);
962e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
963260a9803SDavid Howells 
964260a9803SDavid Howells 	_leave(" = 0 [done]");
965260a9803SDavid Howells 	return 0;
966260a9803SDavid Howells }
967260a9803SDavid Howells 
968260a9803SDavid Howells /*
969260a9803SDavid Howells  * FS.Rename operation type
970260a9803SDavid Howells  */
971260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
972260a9803SDavid Howells 	.name		= "FS.Rename",
973025db80cSDavid Howells 	.op		= afs_FS_Rename,
974260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
975260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
976260a9803SDavid Howells };
977260a9803SDavid Howells 
978260a9803SDavid Howells /*
979a58823acSDavid Howells  * Rename/move a file or directory.
980260a9803SDavid Howells  */
981e49c7b2fSDavid Howells void afs_fs_rename(struct afs_operation *op)
982260a9803SDavid Howells {
983e49c7b2fSDavid Howells 	struct afs_vnode_param *orig_dvp = &op->file[0];
984e49c7b2fSDavid Howells 	struct afs_vnode_param *new_dvp = &op->file[1];
985e49c7b2fSDavid Howells 	const struct qstr *orig_name = &op->dentry->d_name;
986e49c7b2fSDavid Howells 	const struct qstr *new_name = &op->dentry_2->d_name;
987260a9803SDavid Howells 	struct afs_call *call;
988260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
989260a9803SDavid Howells 	__be32 *bp;
990260a9803SDavid Howells 
991260a9803SDavid Howells 	_enter("");
992260a9803SDavid Howells 
993e49c7b2fSDavid Howells 	o_namesz = orig_name->len;
994260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
995260a9803SDavid Howells 
996e49c7b2fSDavid Howells 	n_namesz = new_name->len;
997260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
998260a9803SDavid Howells 
999260a9803SDavid Howells 	reqsz = (4 * 4) +
1000260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1001260a9803SDavid Howells 		(3 * 4) +
1002260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1003260a9803SDavid Howells 
1004e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1005260a9803SDavid Howells 	if (!call)
1006e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1007260a9803SDavid Howells 
1008260a9803SDavid Howells 	/* marshall the parameters */
1009260a9803SDavid Howells 	bp = call->request;
1010260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1011e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vid);
1012e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.vnode);
1013e49c7b2fSDavid Howells 	*bp++ = htonl(orig_dvp->fid.unique);
1014260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1015e49c7b2fSDavid Howells 	memcpy(bp, orig_name->name, o_namesz);
1016260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1017260a9803SDavid Howells 	if (o_padsz > 0) {
1018260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1019260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1020260a9803SDavid Howells 	}
1021260a9803SDavid Howells 
1022e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vid);
1023e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.vnode);
1024e49c7b2fSDavid Howells 	*bp++ = htonl(new_dvp->fid.unique);
1025260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1026e49c7b2fSDavid Howells 	memcpy(bp, new_name->name, n_namesz);
1027260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1028260a9803SDavid Howells 	if (n_padsz > 0) {
1029260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1030260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1031260a9803SDavid Howells 	}
1032260a9803SDavid Howells 
1033e49c7b2fSDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvp->fid, orig_name, new_name);
1034e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1035260a9803SDavid Howells }
103631143d5dSDavid Howells 
103731143d5dSDavid Howells /*
1038e49c7b2fSDavid Howells  * Deliver reply data to FS.StoreData or FS.StoreStatus
103931143d5dSDavid Howells  */
1040d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
104131143d5dSDavid Howells {
1042e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1043e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
104431143d5dSDavid Howells 	const __be32 *bp;
1045372ee163SDavid Howells 	int ret;
104631143d5dSDavid Howells 
1047d001648eSDavid Howells 	_enter("");
104831143d5dSDavid Howells 
1049d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1050372ee163SDavid Howells 	if (ret < 0)
1051372ee163SDavid Howells 		return ret;
105231143d5dSDavid Howells 
105331143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
105431143d5dSDavid Howells 	bp = call->buffer;
1055e49c7b2fSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
1056e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
105731143d5dSDavid Howells 
105831143d5dSDavid Howells 	_leave(" = 0 [done]");
105931143d5dSDavid Howells 	return 0;
106031143d5dSDavid Howells }
106131143d5dSDavid Howells 
106231143d5dSDavid Howells /*
106331143d5dSDavid Howells  * FS.StoreData operation type
106431143d5dSDavid Howells  */
106531143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
106631143d5dSDavid Howells 	.name		= "FS.StoreData",
1067025db80cSDavid Howells 	.op		= afs_FS_StoreData,
106831143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
106931143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
107031143d5dSDavid Howells };
107131143d5dSDavid Howells 
1072b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1073b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1074025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1075b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1076b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1077b9b1f8d5SDavid Howells };
1078b9b1f8d5SDavid Howells 
1079b9b1f8d5SDavid Howells /*
1080b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1081b9b1f8d5SDavid Howells  */
1082e49c7b2fSDavid Howells static void afs_fs_store_data64(struct afs_operation *op,
1083e49c7b2fSDavid Howells 				loff_t pos, loff_t size, loff_t i_size)
1084b9b1f8d5SDavid Howells {
1085e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1086b9b1f8d5SDavid Howells 	struct afs_call *call;
1087b9b1f8d5SDavid Howells 	__be32 *bp;
1088b9b1f8d5SDavid Howells 
10893b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1090e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1091b9b1f8d5SDavid Howells 
1092e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64,
1093b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1094b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1095b9b1f8d5SDavid Howells 	if (!call)
1096e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1097b9b1f8d5SDavid Howells 
1098b9b1f8d5SDavid Howells 	call->send_pages = true;
1099b9b1f8d5SDavid Howells 
1100b9b1f8d5SDavid Howells 	/* marshall the parameters */
1101b9b1f8d5SDavid Howells 	bp = call->request;
1102b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1103e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1104e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1105e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1106b9b1f8d5SDavid Howells 
1107ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1108e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
1109b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1110b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1111b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1112b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1113b9b1f8d5SDavid Howells 
1114e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(pos));
1115e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(pos));
1116e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(size));
1117e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(size));
1118e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(i_size));
1119e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(i_size));
1120b9b1f8d5SDavid Howells 
1121e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1122e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1123b9b1f8d5SDavid Howells }
1124b9b1f8d5SDavid Howells 
112531143d5dSDavid Howells /*
112631143d5dSDavid Howells  * store a set of pages
112731143d5dSDavid Howells  */
1128e49c7b2fSDavid Howells void afs_fs_store_data(struct afs_operation *op)
112931143d5dSDavid Howells {
1130e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
113131143d5dSDavid Howells 	struct afs_call *call;
113231143d5dSDavid Howells 	loff_t size, pos, i_size;
113331143d5dSDavid Howells 	__be32 *bp;
113431143d5dSDavid Howells 
11353b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1136e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
113731143d5dSDavid Howells 
1138e49c7b2fSDavid Howells 	size = (loff_t)op->store.last_to - (loff_t)op->store.first_offset;
1139e49c7b2fSDavid Howells 	if (op->store.first != op->store.last)
1140e49c7b2fSDavid Howells 		size += (loff_t)(op->store.last - op->store.first) << PAGE_SHIFT;
1141e49c7b2fSDavid Howells 	pos = (loff_t)op->store.first << PAGE_SHIFT;
1142e49c7b2fSDavid Howells 	pos += op->store.first_offset;
114331143d5dSDavid Howells 
1144e49c7b2fSDavid Howells 	i_size = i_size_read(&vp->vnode->vfs_inode);
114531143d5dSDavid Howells 	if (pos + size > i_size)
114631143d5dSDavid Howells 		i_size = size + pos;
114731143d5dSDavid Howells 
114831143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
114931143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
115031143d5dSDavid Howells 	       (unsigned long long) i_size);
115131143d5dSDavid Howells 
1152e49c7b2fSDavid Howells 	if (upper_32_bits(pos) || upper_32_bits(i_size) || upper_32_bits(size) ||
1153e49c7b2fSDavid Howells 	    upper_32_bits(pos + size))
1154e49c7b2fSDavid Howells 		return afs_fs_store_data64(op, pos, size, i_size);
115531143d5dSDavid Howells 
1156e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData,
115731143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
115831143d5dSDavid Howells 				   (21 + 6) * 4);
115931143d5dSDavid Howells 	if (!call)
1160e49c7b2fSDavid Howells 		return afs_op_nomem(op);
116131143d5dSDavid Howells 
116231143d5dSDavid Howells 	call->send_pages = true;
116331143d5dSDavid Howells 
116431143d5dSDavid Howells 	/* marshall the parameters */
116531143d5dSDavid Howells 	bp = call->request;
116631143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1167e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1168e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1169e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
117031143d5dSDavid Howells 
1171ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1172e49c7b2fSDavid Howells 	*bp++ = htonl(op->mtime.tv_sec); /* mtime */
117331143d5dSDavid Howells 	*bp++ = 0; /* owner */
117431143d5dSDavid Howells 	*bp++ = 0; /* group */
117531143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
117631143d5dSDavid Howells 	*bp++ = 0; /* segment size */
117731143d5dSDavid Howells 
1178e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(pos));
1179e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(size));
1180e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(i_size));
118131143d5dSDavid Howells 
1182e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1183e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
118431143d5dSDavid Howells }
118531143d5dSDavid Howells 
118631143d5dSDavid Howells /*
118731143d5dSDavid Howells  * FS.StoreStatus operation type
118831143d5dSDavid Howells  */
118931143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
119031143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1191025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
1192e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
119331143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
119431143d5dSDavid Howells };
119531143d5dSDavid Howells 
119631143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
119731143d5dSDavid Howells 	.name		= "FS.StoreData",
1198025db80cSDavid Howells 	.op		= afs_FS_StoreData,
1199e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
120031143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
120131143d5dSDavid Howells };
120231143d5dSDavid Howells 
1203b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1204b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1205025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1206e49c7b2fSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1207b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1208b9b1f8d5SDavid Howells };
1209b9b1f8d5SDavid Howells 
1210b9b1f8d5SDavid Howells /*
1211b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1212b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1213b9b1f8d5SDavid Howells  */
1214e49c7b2fSDavid Howells static void afs_fs_setattr_size64(struct afs_operation *op)
1215b9b1f8d5SDavid Howells {
1216e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1217b9b1f8d5SDavid Howells 	struct afs_call *call;
1218e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
1219b9b1f8d5SDavid Howells 	__be32 *bp;
1220b9b1f8d5SDavid Howells 
12213b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1222e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
1223b9b1f8d5SDavid Howells 
1224b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1225b9b1f8d5SDavid Howells 
1226e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData64_as_Status,
1227b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1228b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1229b9b1f8d5SDavid Howells 	if (!call)
1230e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1231b9b1f8d5SDavid Howells 
1232b9b1f8d5SDavid Howells 	/* marshall the parameters */
1233b9b1f8d5SDavid Howells 	bp = call->request;
1234b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1235e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1236e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1237e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1238b9b1f8d5SDavid Howells 
1239b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1240b9b1f8d5SDavid Howells 
1241e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* position of start of write */
1242e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1243b9b1f8d5SDavid Howells 	*bp++ = 0;					/* size of write */
1244b9b1f8d5SDavid Howells 	*bp++ = 0;
1245e49c7b2fSDavid Howells 	*bp++ = htonl(upper_32_bits(attr->ia_size));	/* new file length */
1246e49c7b2fSDavid Howells 	*bp++ = htonl(lower_32_bits(attr->ia_size));
1247b9b1f8d5SDavid Howells 
1248e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1249e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1250b9b1f8d5SDavid Howells }
1251b9b1f8d5SDavid Howells 
125231143d5dSDavid Howells /*
125331143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
125431143d5dSDavid Howells  * so as to alter the file size also
125531143d5dSDavid Howells  */
1256e49c7b2fSDavid Howells static void afs_fs_setattr_size(struct afs_operation *op)
125731143d5dSDavid Howells {
1258e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
125931143d5dSDavid Howells 	struct afs_call *call;
1260e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
126131143d5dSDavid Howells 	__be32 *bp;
126231143d5dSDavid Howells 
12633b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1264e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
126531143d5dSDavid Howells 
126631143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1267e49c7b2fSDavid Howells 	if (upper_32_bits(attr->ia_size))
1268e49c7b2fSDavid Howells 		return afs_fs_setattr_size64(op);
126931143d5dSDavid Howells 
1270e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreData_as_Status,
127131143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
127231143d5dSDavid Howells 				   (21 + 6) * 4);
127331143d5dSDavid Howells 	if (!call)
1274e49c7b2fSDavid Howells 		return afs_op_nomem(op);
127531143d5dSDavid Howells 
127631143d5dSDavid Howells 	/* marshall the parameters */
127731143d5dSDavid Howells 	bp = call->request;
127831143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
1279e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1280e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1281e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
128231143d5dSDavid Howells 
128331143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
128431143d5dSDavid Howells 
12858c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
128631143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
128731143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
128831143d5dSDavid Howells 
1289e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1290e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
129131143d5dSDavid Howells }
129231143d5dSDavid Howells 
129331143d5dSDavid Howells /*
129431143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
129531143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
129631143d5dSDavid Howells  */
1297e49c7b2fSDavid Howells void afs_fs_setattr(struct afs_operation *op)
129831143d5dSDavid Howells {
1299e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
130031143d5dSDavid Howells 	struct afs_call *call;
1301e49c7b2fSDavid Howells 	struct iattr *attr = op->setattr.attr;
130231143d5dSDavid Howells 	__be32 *bp;
130331143d5dSDavid Howells 
130431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1305e49c7b2fSDavid Howells 		return afs_fs_setattr_size(op);
130631143d5dSDavid Howells 
13073b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1308e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
130931143d5dSDavid Howells 
1310e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreStatus,
131131143d5dSDavid Howells 				   (4 + 6) * 4,
131231143d5dSDavid Howells 				   (21 + 6) * 4);
131331143d5dSDavid Howells 	if (!call)
1314e49c7b2fSDavid Howells 		return afs_op_nomem(op);
131531143d5dSDavid Howells 
131631143d5dSDavid Howells 	/* marshall the parameters */
131731143d5dSDavid Howells 	bp = call->request;
131831143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
1319e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1320e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1321e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
132231143d5dSDavid Howells 
1323e49c7b2fSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, op->setattr.attr);
132431143d5dSDavid Howells 
1325e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1326e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
132731143d5dSDavid Howells }
132845222b9eSDavid Howells 
132945222b9eSDavid Howells /*
133045222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
133145222b9eSDavid Howells  */
1332d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
133345222b9eSDavid Howells {
1334e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
133545222b9eSDavid Howells 	const __be32 *bp;
133645222b9eSDavid Howells 	char *p;
133712bdcf33SDavid Howells 	u32 size;
133845222b9eSDavid Howells 	int ret;
133945222b9eSDavid Howells 
1340d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
134145222b9eSDavid Howells 
134245222b9eSDavid Howells 	switch (call->unmarshall) {
134345222b9eSDavid Howells 	case 0:
134445222b9eSDavid Howells 		call->unmarshall++;
134512bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
1346df561f66SGustavo A. R. Silva 		fallthrough;
134745222b9eSDavid Howells 
134829881608SGustavo A. R. Silva 		/* extract the returned status record */
134945222b9eSDavid Howells 	case 1:
135045222b9eSDavid Howells 		_debug("extract status");
135112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1352372ee163SDavid Howells 		if (ret < 0)
1353372ee163SDavid Howells 			return ret;
135445222b9eSDavid Howells 
135545222b9eSDavid Howells 		bp = call->buffer;
1356e49c7b2fSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, &op->volstatus.vs);
135745222b9eSDavid Howells 		call->unmarshall++;
135812bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1359df561f66SGustavo A. R. Silva 		fallthrough;
136045222b9eSDavid Howells 
136129881608SGustavo A. R. Silva 		/* extract the volume name length */
136245222b9eSDavid Howells 	case 2:
136312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1364372ee163SDavid Howells 		if (ret < 0)
1365372ee163SDavid Howells 			return ret;
136645222b9eSDavid Howells 
136745222b9eSDavid Howells 		call->count = ntohl(call->tmp);
136845222b9eSDavid Howells 		_debug("volname length: %u", call->count);
136945222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13707126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_volname_len);
137112bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1372ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
137345222b9eSDavid Howells 		call->unmarshall++;
1374df561f66SGustavo A. R. Silva 		fallthrough;
137545222b9eSDavid Howells 
137629881608SGustavo A. R. Silva 		/* extract the volume name */
137745222b9eSDavid Howells 	case 3:
137845222b9eSDavid Howells 		_debug("extract volname");
137912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1380372ee163SDavid Howells 		if (ret < 0)
1381372ee163SDavid Howells 			return ret;
138245222b9eSDavid Howells 
1383ffba718eSDavid Howells 		p = call->buffer;
138445222b9eSDavid Howells 		p[call->count] = 0;
138545222b9eSDavid Howells 		_debug("volname '%s'", p);
138612bdcf33SDavid Howells 		afs_extract_to_tmp(call);
138745222b9eSDavid Howells 		call->unmarshall++;
1388df561f66SGustavo A. R. Silva 		fallthrough;
138945222b9eSDavid Howells 
139029881608SGustavo A. R. Silva 		/* extract the offline message length */
139112bdcf33SDavid Howells 	case 4:
139212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1393372ee163SDavid Howells 		if (ret < 0)
1394372ee163SDavid Howells 			return ret;
139545222b9eSDavid Howells 
139645222b9eSDavid Howells 		call->count = ntohl(call->tmp);
139745222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
139845222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
13997126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_offline_msg_len);
140012bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1401ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
140245222b9eSDavid Howells 		call->unmarshall++;
1403df561f66SGustavo A. R. Silva 		fallthrough;
140445222b9eSDavid Howells 
140529881608SGustavo A. R. Silva 		/* extract the offline message */
140612bdcf33SDavid Howells 	case 5:
140745222b9eSDavid Howells 		_debug("extract offline");
140812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1409372ee163SDavid Howells 		if (ret < 0)
1410372ee163SDavid Howells 			return ret;
141145222b9eSDavid Howells 
1412ffba718eSDavid Howells 		p = call->buffer;
141345222b9eSDavid Howells 		p[call->count] = 0;
141445222b9eSDavid Howells 		_debug("offline '%s'", p);
141545222b9eSDavid Howells 
141612bdcf33SDavid Howells 		afs_extract_to_tmp(call);
141745222b9eSDavid Howells 		call->unmarshall++;
1418df561f66SGustavo A. R. Silva 		fallthrough;
141945222b9eSDavid Howells 
142029881608SGustavo A. R. Silva 		/* extract the message of the day length */
142112bdcf33SDavid Howells 	case 6:
142212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1423372ee163SDavid Howells 		if (ret < 0)
1424372ee163SDavid Howells 			return ret;
142545222b9eSDavid Howells 
142645222b9eSDavid Howells 		call->count = ntohl(call->tmp);
142745222b9eSDavid Howells 		_debug("motd length: %u", call->count);
142845222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
14297126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_motd_len);
143012bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1431ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
143245222b9eSDavid Howells 		call->unmarshall++;
1433df561f66SGustavo A. R. Silva 		fallthrough;
143445222b9eSDavid Howells 
143529881608SGustavo A. R. Silva 		/* extract the message of the day */
143612bdcf33SDavid Howells 	case 7:
143745222b9eSDavid Howells 		_debug("extract motd");
143812bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1439372ee163SDavid Howells 		if (ret < 0)
1440372ee163SDavid Howells 			return ret;
144145222b9eSDavid Howells 
1442ffba718eSDavid Howells 		p = call->buffer;
144345222b9eSDavid Howells 		p[call->count] = 0;
144445222b9eSDavid Howells 		_debug("motd '%s'", p);
144545222b9eSDavid Howells 
144645222b9eSDavid Howells 		call->unmarshall++;
144745222b9eSDavid Howells 
144812bdcf33SDavid Howells 	case 8:
144945222b9eSDavid Howells 		break;
145045222b9eSDavid Howells 	}
145145222b9eSDavid Howells 
145245222b9eSDavid Howells 	_leave(" = 0 [done]");
145345222b9eSDavid Howells 	return 0;
145445222b9eSDavid Howells }
145545222b9eSDavid Howells 
145645222b9eSDavid Howells /*
145745222b9eSDavid Howells  * FS.GetVolumeStatus operation type
145845222b9eSDavid Howells  */
145945222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
146045222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1461025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
146245222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1463ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
146445222b9eSDavid Howells };
146545222b9eSDavid Howells 
146645222b9eSDavid Howells /*
146745222b9eSDavid Howells  * fetch the status of a volume
146845222b9eSDavid Howells  */
1469e49c7b2fSDavid Howells void afs_fs_get_volume_status(struct afs_operation *op)
147045222b9eSDavid Howells {
1471e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
147245222b9eSDavid Howells 	struct afs_call *call;
147345222b9eSDavid Howells 	__be32 *bp;
147445222b9eSDavid Howells 
147545222b9eSDavid Howells 	_enter("");
147645222b9eSDavid Howells 
1477e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSGetVolumeStatus, 2 * 4,
1478ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1479ffba718eSDavid Howells 	if (!call)
1480e49c7b2fSDavid Howells 		return afs_op_nomem(op);
148145222b9eSDavid Howells 
148245222b9eSDavid Howells 	/* marshall the parameters */
148345222b9eSDavid Howells 	bp = call->request;
148445222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
1485e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
148645222b9eSDavid Howells 
1487e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1488e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
148945222b9eSDavid Howells }
1490e8d6c554SDavid Howells 
1491e8d6c554SDavid Howells /*
1492e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1493e8d6c554SDavid Howells  */
1494d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1495e8d6c554SDavid Howells {
1496e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1497e8d6c554SDavid Howells 	const __be32 *bp;
1498372ee163SDavid Howells 	int ret;
1499e8d6c554SDavid Howells 
1500d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1501e8d6c554SDavid Howells 
1502d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1503372ee163SDavid Howells 	if (ret < 0)
1504372ee163SDavid Howells 		return ret;
1505e8d6c554SDavid Howells 
1506e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1507e8d6c554SDavid Howells 	bp = call->buffer;
1508e49c7b2fSDavid Howells 	xdr_decode_AFSVolSync(&bp, &op->volsync);
1509e8d6c554SDavid Howells 
1510e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1511e8d6c554SDavid Howells 	return 0;
1512e8d6c554SDavid Howells }
1513e8d6c554SDavid Howells 
1514e8d6c554SDavid Howells /*
1515e8d6c554SDavid Howells  * FS.SetLock operation type
1516e8d6c554SDavid Howells  */
1517e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1518e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1519025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1520e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1521a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1522e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1523e8d6c554SDavid Howells };
1524e8d6c554SDavid Howells 
1525e8d6c554SDavid Howells /*
1526e8d6c554SDavid Howells  * FS.ExtendLock operation type
1527e8d6c554SDavid Howells  */
1528e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1529e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1530025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1531e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1532a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1533e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1534e8d6c554SDavid Howells };
1535e8d6c554SDavid Howells 
1536e8d6c554SDavid Howells /*
1537e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1538e8d6c554SDavid Howells  */
1539e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1540e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1541025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1542e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1543e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1544e8d6c554SDavid Howells };
1545e8d6c554SDavid Howells 
1546e8d6c554SDavid Howells /*
1547d2ddc776SDavid Howells  * Set a lock on a file
1548e8d6c554SDavid Howells  */
1549e49c7b2fSDavid Howells void afs_fs_set_lock(struct afs_operation *op)
1550e8d6c554SDavid Howells {
1551e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1552e8d6c554SDavid Howells 	struct afs_call *call;
1553e8d6c554SDavid Howells 	__be32 *bp;
1554e8d6c554SDavid Howells 
1555e8d6c554SDavid Howells 	_enter("");
1556e8d6c554SDavid Howells 
1557e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1558e8d6c554SDavid Howells 	if (!call)
1559e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1560e8d6c554SDavid Howells 
1561e8d6c554SDavid Howells 	/* marshall the parameters */
1562e8d6c554SDavid Howells 	bp = call->request;
1563e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1564e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1565e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1566e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1567e49c7b2fSDavid Howells 	*bp++ = htonl(op->lock.type);
1568e8d6c554SDavid Howells 
1569e49c7b2fSDavid Howells 	trace_afs_make_fs_calli(call, &vp->fid, op->lock.type);
1570e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1571e8d6c554SDavid Howells }
1572e8d6c554SDavid Howells 
1573e8d6c554SDavid Howells /*
1574e8d6c554SDavid Howells  * extend a lock on a file
1575e8d6c554SDavid Howells  */
1576e49c7b2fSDavid Howells void afs_fs_extend_lock(struct afs_operation *op)
1577e8d6c554SDavid Howells {
1578e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1579e8d6c554SDavid Howells 	struct afs_call *call;
1580e8d6c554SDavid Howells 	__be32 *bp;
1581e8d6c554SDavid Howells 
1582e8d6c554SDavid Howells 	_enter("");
1583e8d6c554SDavid Howells 
1584e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1585e8d6c554SDavid Howells 	if (!call)
1586e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1587e8d6c554SDavid Howells 
1588e8d6c554SDavid Howells 	/* marshall the parameters */
1589e8d6c554SDavid Howells 	bp = call->request;
1590e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1591e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1592e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1593e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1594e8d6c554SDavid Howells 
1595e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1596e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1597e8d6c554SDavid Howells }
1598e8d6c554SDavid Howells 
1599e8d6c554SDavid Howells /*
1600e8d6c554SDavid Howells  * release a lock on a file
1601e8d6c554SDavid Howells  */
1602e49c7b2fSDavid Howells void afs_fs_release_lock(struct afs_operation *op)
1603e8d6c554SDavid Howells {
1604e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1605e8d6c554SDavid Howells 	struct afs_call *call;
1606e8d6c554SDavid Howells 	__be32 *bp;
1607e8d6c554SDavid Howells 
1608e8d6c554SDavid Howells 	_enter("");
1609e8d6c554SDavid Howells 
1610e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1611e8d6c554SDavid Howells 	if (!call)
1612e49c7b2fSDavid Howells 		return afs_op_nomem(op);
1613e8d6c554SDavid Howells 
1614e8d6c554SDavid Howells 	/* marshall the parameters */
1615e8d6c554SDavid Howells 	bp = call->request;
1616e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1617e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1618e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1619e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1620e8d6c554SDavid Howells 
1621e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1622e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
1623c435ee34SDavid Howells }
1624c435ee34SDavid Howells 
1625c435ee34SDavid Howells /*
1626c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1627c435ee34SDavid Howells  */
1628c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1629c435ee34SDavid Howells {
1630c435ee34SDavid Howells 	return afs_transfer_reply(call);
1631c435ee34SDavid Howells }
1632c435ee34SDavid Howells 
1633c435ee34SDavid Howells /*
1634c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1635c435ee34SDavid Howells  */
1636c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1637c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1638025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1639c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1640c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1641c435ee34SDavid Howells };
1642c435ee34SDavid Howells 
1643c435ee34SDavid Howells /*
1644c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1645c435ee34SDavid Howells  */
1646d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1647d2ddc776SDavid Howells 				 struct afs_server *server,
16488b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1649d2ddc776SDavid Howells 				 struct key *key)
1650c435ee34SDavid Howells {
1651c435ee34SDavid Howells 	struct afs_call *call;
1652c435ee34SDavid Howells 	__be32 *bp;
1653c435ee34SDavid Howells 
1654c435ee34SDavid Howells 	_enter("");
1655c435ee34SDavid Howells 
1656d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1657c435ee34SDavid Howells 	if (!call)
1658c435ee34SDavid Howells 		return -ENOMEM;
1659c435ee34SDavid Howells 
1660c435ee34SDavid Howells 	call->key = key;
1661c435ee34SDavid Howells 
1662c435ee34SDavid Howells 	/* marshall the parameters */
1663c435ee34SDavid Howells 	bp = call->request;
1664c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1665c435ee34SDavid Howells 
1666977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_give_up_cb);
16670b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
16680b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1669d2ddc776SDavid Howells }
1670d2ddc776SDavid Howells 
1671d2ddc776SDavid Howells /*
1672d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1673d2ddc776SDavid Howells  */
1674d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1675d2ddc776SDavid Howells {
1676d2ddc776SDavid Howells 	u32 count;
1677d2ddc776SDavid Howells 	int ret;
1678d2ddc776SDavid Howells 
1679fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1680d2ddc776SDavid Howells 
1681d2ddc776SDavid Howells 	switch (call->unmarshall) {
1682d2ddc776SDavid Howells 	case 0:
168312bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1684d2ddc776SDavid Howells 		call->unmarshall++;
1685df561f66SGustavo A. R. Silva 		fallthrough;
1686d2ddc776SDavid Howells 
168729881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1688d2ddc776SDavid Howells 	case 1:
168912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1690d2ddc776SDavid Howells 		if (ret < 0)
1691d2ddc776SDavid Howells 			return ret;
1692d2ddc776SDavid Howells 
1693d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1694d2ddc776SDavid Howells 
1695d2ddc776SDavid Howells 		call->count = count;
1696d2ddc776SDavid Howells 		call->count2 = count;
169723a28913SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
1698d2ddc776SDavid Howells 		call->unmarshall++;
1699df561f66SGustavo A. R. Silva 		fallthrough;
1700d2ddc776SDavid Howells 
170129881608SGustavo A. R. Silva 		/* Extract capabilities words */
1702d2ddc776SDavid Howells 	case 2:
170312bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1704d2ddc776SDavid Howells 		if (ret < 0)
1705d2ddc776SDavid Howells 			return ret;
1706d2ddc776SDavid Howells 
1707d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1708d2ddc776SDavid Howells 
1709d2ddc776SDavid Howells 		call->unmarshall++;
1710d2ddc776SDavid Howells 		break;
1711d2ddc776SDavid Howells 	}
1712d2ddc776SDavid Howells 
1713d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1714d2ddc776SDavid Howells 	return 0;
1715d2ddc776SDavid Howells }
1716d2ddc776SDavid Howells 
1717d2ddc776SDavid Howells /*
1718d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1719d2ddc776SDavid Howells  */
1720d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1721d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1722025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1723d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
17243bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1725ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1726d2ddc776SDavid Howells };
1727d2ddc776SDavid Howells 
1728d2ddc776SDavid Howells /*
1729f6cbb368SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This RPC can
1730f6cbb368SDavid Howells  * reply with up to 196 words.  The operation is asynchronous and if we managed
1731f6cbb368SDavid Howells  * to allocate a call, true is returned the result is delivered through the
1732f6cbb368SDavid Howells  * ->done() - otherwise we return false to indicate we didn't even try.
1733d2ddc776SDavid Howells  */
1734f6cbb368SDavid Howells bool afs_fs_get_capabilities(struct afs_net *net, struct afs_server *server,
1735f6cbb368SDavid Howells 			     struct afs_addr_cursor *ac, struct key *key)
1736d2ddc776SDavid Howells {
1737d2ddc776SDavid Howells 	struct afs_call *call;
1738d2ddc776SDavid Howells 	__be32 *bp;
1739d2ddc776SDavid Howells 
1740d2ddc776SDavid Howells 	_enter("");
1741d2ddc776SDavid Howells 
1742d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1743d2ddc776SDavid Howells 	if (!call)
1744f6cbb368SDavid Howells 		return false;
1745d2ddc776SDavid Howells 
1746d2ddc776SDavid Howells 	call->key = key;
1747977e5f8eSDavid Howells 	call->server = afs_use_server(server, afs_server_trace_get_caps);
174830062bd1SDavid Howells 	call->upgrade = true;
17490b9bf381SDavid Howells 	call->async = true;
175094f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1751d2ddc776SDavid Howells 
1752d2ddc776SDavid Howells 	/* marshall the parameters */
1753d2ddc776SDavid Howells 	bp = call->request;
1754d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1755d2ddc776SDavid Howells 
1756025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
17570b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
1758f6cbb368SDavid Howells 	afs_put_call(call);
1759f6cbb368SDavid Howells 	return true;
1760e8d6c554SDavid Howells }
17615cf9dd55SDavid Howells 
17625cf9dd55SDavid Howells /*
17635cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
17645cf9dd55SDavid Howells  */
17655cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
17665cf9dd55SDavid Howells {
1767e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
176887182759SDavid Howells 	struct afs_status_cb *scb;
17695cf9dd55SDavid Howells 	const __be32 *bp;
17705cf9dd55SDavid Howells 	u32 tmp;
17715cf9dd55SDavid Howells 	int ret;
17725cf9dd55SDavid Howells 
17735cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
17745cf9dd55SDavid Howells 
17755cf9dd55SDavid Howells 	switch (call->unmarshall) {
17765cf9dd55SDavid Howells 	case 0:
177712bdcf33SDavid Howells 		afs_extract_to_tmp(call);
17785cf9dd55SDavid Howells 		call->unmarshall++;
1779df561f66SGustavo A. R. Silva 		fallthrough;
17805cf9dd55SDavid Howells 
17815cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
17825cf9dd55SDavid Howells 	case 1:
17835cf9dd55SDavid Howells 		_debug("extract status count");
178412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
17855cf9dd55SDavid Howells 		if (ret < 0)
17865cf9dd55SDavid Howells 			return ret;
17875cf9dd55SDavid Howells 
17885cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
1789e49c7b2fSDavid Howells 		_debug("status count: %u/%u", tmp, op->nr_files);
1790e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
17917126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_count);
17925cf9dd55SDavid Howells 
17935cf9dd55SDavid Howells 		call->count = 0;
17945cf9dd55SDavid Howells 		call->unmarshall++;
17955cf9dd55SDavid Howells 	more_counts:
179612bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
1797df561f66SGustavo A. R. Silva 		fallthrough;
179829881608SGustavo A. R. Silva 
17995cf9dd55SDavid Howells 	case 2:
18005cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
180112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18025cf9dd55SDavid Howells 		if (ret < 0)
18035cf9dd55SDavid Howells 			return ret;
18045cf9dd55SDavid Howells 
1805e49c7b2fSDavid Howells 		switch (call->count) {
1806e49c7b2fSDavid Howells 		case 0:
1807e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1808e49c7b2fSDavid Howells 			break;
1809e49c7b2fSDavid Howells 		case 1:
1810e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1811e49c7b2fSDavid Howells 			break;
1812e49c7b2fSDavid Howells 		default:
1813e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1814e49c7b2fSDavid Howells 			break;
1815e49c7b2fSDavid Howells 		}
1816e49c7b2fSDavid Howells 
18175cf9dd55SDavid Howells 		bp = call->buffer;
181838355eecSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, scb);
1819e49c7b2fSDavid Howells 
18205cf9dd55SDavid Howells 		call->count++;
1821e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
18225cf9dd55SDavid Howells 			goto more_counts;
18235cf9dd55SDavid Howells 
18245cf9dd55SDavid Howells 		call->count = 0;
18255cf9dd55SDavid Howells 		call->unmarshall++;
182612bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1827df561f66SGustavo A. R. Silva 		fallthrough;
18285cf9dd55SDavid Howells 
18295cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
18305cf9dd55SDavid Howells 	case 3:
18315cf9dd55SDavid Howells 		_debug("extract CB count");
183212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18335cf9dd55SDavid Howells 		if (ret < 0)
18345cf9dd55SDavid Howells 			return ret;
18355cf9dd55SDavid Howells 
18365cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
18375cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
1838e49c7b2fSDavid Howells 		if (tmp != op->nr_files)
18397126ead9SDavid Howells 			return afs_protocol_error(call, afs_eproto_ibulkst_cb_count);
18405cf9dd55SDavid Howells 		call->count = 0;
18415cf9dd55SDavid Howells 		call->unmarshall++;
18425cf9dd55SDavid Howells 	more_cbs:
184312bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
1844df561f66SGustavo A. R. Silva 		fallthrough;
184529881608SGustavo A. R. Silva 
18465cf9dd55SDavid Howells 	case 4:
18475cf9dd55SDavid Howells 		_debug("extract CB array");
184812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
18495cf9dd55SDavid Howells 		if (ret < 0)
18505cf9dd55SDavid Howells 			return ret;
18515cf9dd55SDavid Howells 
18525cf9dd55SDavid Howells 		_debug("unmarshall CB array");
1853e49c7b2fSDavid Howells 		switch (call->count) {
1854e49c7b2fSDavid Howells 		case 0:
1855e49c7b2fSDavid Howells 			scb = &op->file[0].scb;
1856e49c7b2fSDavid Howells 			break;
1857e49c7b2fSDavid Howells 		case 1:
1858e49c7b2fSDavid Howells 			scb = &op->file[1].scb;
1859e49c7b2fSDavid Howells 			break;
1860e49c7b2fSDavid Howells 		default:
1861e49c7b2fSDavid Howells 			scb = &op->more_files[call->count - 2].scb;
1862e49c7b2fSDavid Howells 			break;
1863e49c7b2fSDavid Howells 		}
1864e49c7b2fSDavid Howells 
18655cf9dd55SDavid Howells 		bp = call->buffer;
1866a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
18675cf9dd55SDavid Howells 		call->count++;
1868e49c7b2fSDavid Howells 		if (call->count < op->nr_files)
18695cf9dd55SDavid Howells 			goto more_cbs;
18705cf9dd55SDavid Howells 
187112bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
18725cf9dd55SDavid Howells 		call->unmarshall++;
1873df561f66SGustavo A. R. Silva 		fallthrough;
187429881608SGustavo A. R. Silva 
18755cf9dd55SDavid Howells 	case 5:
187612bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
18775cf9dd55SDavid Howells 		if (ret < 0)
18785cf9dd55SDavid Howells 			return ret;
18795cf9dd55SDavid Howells 
18805cf9dd55SDavid Howells 		bp = call->buffer;
1881e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
18825cf9dd55SDavid Howells 
18835cf9dd55SDavid Howells 		call->unmarshall++;
18845cf9dd55SDavid Howells 
18855cf9dd55SDavid Howells 	case 6:
18865cf9dd55SDavid Howells 		break;
18875cf9dd55SDavid Howells 	}
18885cf9dd55SDavid Howells 
18895cf9dd55SDavid Howells 	_leave(" = 0 [done]");
18905cf9dd55SDavid Howells 	return 0;
18915cf9dd55SDavid Howells }
18925cf9dd55SDavid Howells 
1893e49c7b2fSDavid Howells static void afs_done_fs_inline_bulk_status(struct afs_call *call)
1894e49c7b2fSDavid Howells {
1895e49c7b2fSDavid Howells 	if (call->error == -ECONNABORTED &&
189620325960SDavid Howells 	    call->abort_code == RX_INVALID_OPERATION) {
1897e49c7b2fSDavid Howells 		set_bit(AFS_SERVER_FL_NO_IBULK, &call->server->flags);
189820325960SDavid Howells 		if (call->op)
189920325960SDavid Howells 			set_bit(AFS_VOLUME_MAYBE_NO_IBULK, &call->op->volume->flags);
190020325960SDavid Howells 	}
1901e49c7b2fSDavid Howells }
1902e49c7b2fSDavid Howells 
19035cf9dd55SDavid Howells /*
19045cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
19055cf9dd55SDavid Howells  */
19065cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
19075cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
19085cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
19095cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
1910e49c7b2fSDavid Howells 	.done		= afs_done_fs_inline_bulk_status,
19115cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
19125cf9dd55SDavid Howells };
19135cf9dd55SDavid Howells 
19145cf9dd55SDavid Howells /*
19155cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
19165cf9dd55SDavid Howells  */
1917e49c7b2fSDavid Howells void afs_fs_inline_bulk_status(struct afs_operation *op)
19185cf9dd55SDavid Howells {
1919e49c7b2fSDavid Howells 	struct afs_vnode_param *dvp = &op->file[0];
1920e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[1];
19215cf9dd55SDavid Howells 	struct afs_call *call;
19225cf9dd55SDavid Howells 	__be32 *bp;
19235cf9dd55SDavid Howells 	int i;
19245cf9dd55SDavid Howells 
192520325960SDavid Howells 	if (test_bit(AFS_SERVER_FL_NO_IBULK, &op->server->flags)) {
1926e49c7b2fSDavid Howells 		op->error = -ENOTSUPP;
1927e49c7b2fSDavid Howells 		return;
19285cf9dd55SDavid Howells 	}
19295cf9dd55SDavid Howells 
1930e49c7b2fSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
1931e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode, op->nr_files);
1932e49c7b2fSDavid Howells 
1933e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSInlineBulkStatus,
1934e49c7b2fSDavid Howells 				   (2 + op->nr_files * 3) * 4,
1935e49c7b2fSDavid Howells 				   21 * 4);
1936e49c7b2fSDavid Howells 	if (!call)
1937e49c7b2fSDavid Howells 		return afs_op_nomem(op);
19385cf9dd55SDavid Howells 
19395cf9dd55SDavid Howells 	/* marshall the parameters */
19405cf9dd55SDavid Howells 	bp = call->request;
19415cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
1942e49c7b2fSDavid Howells 	*bp++ = htonl(op->nr_files);
1943e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vid);
1944e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.vnode);
1945e49c7b2fSDavid Howells 	*bp++ = htonl(dvp->fid.unique);
1946e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vid);
1947e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.vnode);
1948e49c7b2fSDavid Howells 	*bp++ = htonl(vp->fid.unique);
1949e49c7b2fSDavid Howells 	for (i = 0; i < op->nr_files - 2; i++) {
1950e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vid);
1951e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.vnode);
1952e49c7b2fSDavid Howells 		*bp++ = htonl(op->more_files[i].fid.unique);
19535cf9dd55SDavid Howells 	}
19545cf9dd55SDavid Howells 
1955e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
1956e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_NOFS);
19575cf9dd55SDavid Howells }
1958260f082bSDavid Howells 
1959260f082bSDavid Howells /*
1960260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
1961260f082bSDavid Howells  */
1962260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
1963260f082bSDavid Howells {
1964e49c7b2fSDavid Howells 	struct afs_operation *op = call->op;
1965e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
1966260f082bSDavid Howells 	struct afs_acl *acl;
1967260f082bSDavid Howells 	const __be32 *bp;
1968260f082bSDavid Howells 	unsigned int size;
1969260f082bSDavid Howells 	int ret;
1970260f082bSDavid Howells 
1971260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
1972260f082bSDavid Howells 
1973260f082bSDavid Howells 	switch (call->unmarshall) {
1974260f082bSDavid Howells 	case 0:
1975260f082bSDavid Howells 		afs_extract_to_tmp(call);
1976260f082bSDavid Howells 		call->unmarshall++;
1977df561f66SGustavo A. R. Silva 		fallthrough;
1978260f082bSDavid Howells 
1979260f082bSDavid Howells 		/* extract the returned data length */
1980260f082bSDavid Howells 	case 1:
1981260f082bSDavid Howells 		ret = afs_extract_data(call, true);
1982260f082bSDavid Howells 		if (ret < 0)
1983260f082bSDavid Howells 			return ret;
1984260f082bSDavid Howells 
1985260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
1986260f082bSDavid Howells 		size = round_up(size, 4);
1987260f082bSDavid Howells 
1988260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
1989260f082bSDavid Howells 		if (!acl)
1990260f082bSDavid Howells 			return -ENOMEM;
1991e49c7b2fSDavid Howells 		op->acl = acl;
1992260f082bSDavid Howells 		acl->size = call->count2;
1993260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
1994260f082bSDavid Howells 		call->unmarshall++;
1995df561f66SGustavo A. R. Silva 		fallthrough;
1996260f082bSDavid Howells 
1997260f082bSDavid Howells 		/* extract the returned data */
1998260f082bSDavid Howells 	case 2:
1999260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2000260f082bSDavid Howells 		if (ret < 0)
2001260f082bSDavid Howells 			return ret;
2002260f082bSDavid Howells 
2003260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
2004260f082bSDavid Howells 		call->unmarshall++;
2005df561f66SGustavo A. R. Silva 		fallthrough;
2006260f082bSDavid Howells 
2007260f082bSDavid Howells 		/* extract the metadata */
2008260f082bSDavid Howells 	case 3:
2009260f082bSDavid Howells 		ret = afs_extract_data(call, false);
2010260f082bSDavid Howells 		if (ret < 0)
2011260f082bSDavid Howells 			return ret;
2012260f082bSDavid Howells 
2013260f082bSDavid Howells 		bp = call->buffer;
2014e49c7b2fSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, call, &vp->scb);
2015e49c7b2fSDavid Howells 		xdr_decode_AFSVolSync(&bp, &op->volsync);
2016260f082bSDavid Howells 
2017260f082bSDavid Howells 		call->unmarshall++;
2018260f082bSDavid Howells 
2019260f082bSDavid Howells 	case 4:
2020260f082bSDavid Howells 		break;
2021260f082bSDavid Howells 	}
2022260f082bSDavid Howells 
2023260f082bSDavid Howells 	_leave(" = 0 [done]");
2024260f082bSDavid Howells 	return 0;
2025260f082bSDavid Howells }
2026260f082bSDavid Howells 
2027260f082bSDavid Howells /*
2028260f082bSDavid Howells  * FS.FetchACL operation type
2029260f082bSDavid Howells  */
2030260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2031260f082bSDavid Howells 	.name		= "FS.FetchACL",
2032260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2033260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2034260f082bSDavid Howells };
2035260f082bSDavid Howells 
2036260f082bSDavid Howells /*
2037260f082bSDavid Howells  * Fetch the ACL for a file.
2038260f082bSDavid Howells  */
2039e49c7b2fSDavid Howells void afs_fs_fetch_acl(struct afs_operation *op)
2040260f082bSDavid Howells {
2041e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2042260f082bSDavid Howells 	struct afs_call *call;
2043260f082bSDavid Howells 	__be32 *bp;
2044260f082bSDavid Howells 
2045260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2046e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2047260f082bSDavid Howells 
2048e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2049e49c7b2fSDavid Howells 	if (!call)
2050e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2051260f082bSDavid Howells 
2052260f082bSDavid Howells 	/* marshall the parameters */
2053260f082bSDavid Howells 	bp = call->request;
2054260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2055e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2056e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2057e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2058260f082bSDavid Howells 
2059e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2060e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
2061ffba718eSDavid Howells }
2062ffba718eSDavid Howells 
2063ffba718eSDavid Howells /*
2064b10494afSJoe Gorse  * FS.StoreACL operation type
2065b10494afSJoe Gorse  */
2066b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2067b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2068b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2069ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2070b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2071b10494afSJoe Gorse };
2072b10494afSJoe Gorse 
2073b10494afSJoe Gorse /*
2074b10494afSJoe Gorse  * Fetch the ACL for a file.
2075b10494afSJoe Gorse  */
2076e49c7b2fSDavid Howells void afs_fs_store_acl(struct afs_operation *op)
2077b10494afSJoe Gorse {
2078e49c7b2fSDavid Howells 	struct afs_vnode_param *vp = &op->file[0];
2079b10494afSJoe Gorse 	struct afs_call *call;
2080e49c7b2fSDavid Howells 	const struct afs_acl *acl = op->acl;
2081b10494afSJoe Gorse 	size_t size;
2082b10494afSJoe Gorse 	__be32 *bp;
2083b10494afSJoe Gorse 
2084b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2085e49c7b2fSDavid Howells 	       key_serial(op->key), vp->fid.vid, vp->fid.vnode);
2086b10494afSJoe Gorse 
2087b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2088e49c7b2fSDavid Howells 	call = afs_alloc_flat_call(op->net, &afs_RXFSStoreACL,
2089b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2090e49c7b2fSDavid Howells 	if (!call)
2091e49c7b2fSDavid Howells 		return afs_op_nomem(op);
2092b10494afSJoe Gorse 
2093b10494afSJoe Gorse 	/* marshall the parameters */
2094b10494afSJoe Gorse 	bp = call->request;
2095b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2096e49c7b2fSDavid Howells 	bp[1] = htonl(vp->fid.vid);
2097e49c7b2fSDavid Howells 	bp[2] = htonl(vp->fid.vnode);
2098e49c7b2fSDavid Howells 	bp[3] = htonl(vp->fid.unique);
2099b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2100b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2101b10494afSJoe Gorse 	if (acl->size != size)
2102b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2103b10494afSJoe Gorse 
2104e49c7b2fSDavid Howells 	trace_afs_make_fs_call(call, &vp->fid);
2105e49c7b2fSDavid Howells 	afs_make_op_call(op, call, GFP_KERNEL);
21061da177e4SLinus Torvalds }
2107