xref: /openbmc/linux/fs/afs/fsclient.c (revision 3e0d9892)
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"
1630062bd1SDavid Howells #include "protocol_yfs.h"
171da177e4SLinus Torvalds 
18d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
19c435ee34SDavid Howells {
20d2ddc776SDavid Howells 	call->cbi = afs_get_cb_interest(cbi);
21c435ee34SDavid Howells }
22c435ee34SDavid Howells 
236db3ac3cSDavid Howells /*
24260a9803SDavid Howells  * decode an AFSFid block
25260a9803SDavid Howells  */
26260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
27260a9803SDavid Howells {
28260a9803SDavid Howells 	const __be32 *bp = *_bp;
29260a9803SDavid Howells 
30260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
31260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
32260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
33260a9803SDavid Howells 	*_bp = bp;
34260a9803SDavid Howells }
35260a9803SDavid Howells 
36260a9803SDavid Howells /*
37888b3384SDavid Howells  * Dump a bad file status record.
38888b3384SDavid Howells  */
39888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
40888b3384SDavid Howells {
41888b3384SDavid Howells 	__be32 x[4];
42888b3384SDavid Howells 	int i;
43888b3384SDavid Howells 
44888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
45888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
46888b3384SDavid Howells 		memcpy(x, bp, 16);
47888b3384SDavid Howells 		bp += 4;
48888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
49888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
50888b3384SDavid Howells 	}
51888b3384SDavid Howells 
52888b3384SDavid Howells 	memcpy(x, bp, 4);
53888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
54888b3384SDavid Howells }
55888b3384SDavid Howells 
56888b3384SDavid Howells /*
57dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
58dd9fbcb8SDavid Howells  */
59a58823acSDavid Howells static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
60a58823acSDavid Howells 				     struct afs_call *call,
61a58823acSDavid Howells 				     struct afs_status_cb *scb)
62dd9fbcb8SDavid Howells {
63dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
64a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
65684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
66dd9fbcb8SDavid Howells 	u64 data_version, size;
67dd9fbcb8SDavid Howells 	u32 type, abort_code;
68c72057b5SDavid Howells 	int ret;
69dd9fbcb8SDavid Howells 
70684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
71684b0f68SDavid Howells 
72dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
73684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
74684b0f68SDavid Howells 		    abort_code != 0 &&
75684b0f68SDavid Howells 		    inline_error) {
76684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
77684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
78684b0f68SDavid Howells 			 * case.
79684b0f68SDavid Howells 			 */
80684b0f68SDavid Howells 			status->abort_code = abort_code;
81a38a7558SDavid Howells 			scb->have_error = true;
82c72057b5SDavid Howells 			goto good;
83684b0f68SDavid Howells 		}
84684b0f68SDavid Howells 
85dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
86dd9fbcb8SDavid Howells 		goto bad;
87dd9fbcb8SDavid Howells 	}
88dd9fbcb8SDavid Howells 
89684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
90684b0f68SDavid Howells 		status->abort_code = abort_code;
913e0d9892SDavid Howells 		scb->have_error = true;
92c72057b5SDavid Howells 		goto good;
93684b0f68SDavid Howells 	}
94684b0f68SDavid Howells 
95dd9fbcb8SDavid Howells 	type = ntohl(xdr->type);
96dd9fbcb8SDavid Howells 	switch (type) {
97dd9fbcb8SDavid Howells 	case AFS_FTYPE_FILE:
98dd9fbcb8SDavid Howells 	case AFS_FTYPE_DIR:
99dd9fbcb8SDavid Howells 	case AFS_FTYPE_SYMLINK:
100dd9fbcb8SDavid Howells 		status->type = type;
101dd9fbcb8SDavid Howells 		break;
102dd9fbcb8SDavid Howells 	default:
103dd9fbcb8SDavid Howells 		goto bad;
104dd9fbcb8SDavid Howells 	}
105dd9fbcb8SDavid Howells 
106a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
107a58823acSDavid Howells 	status->author		= ntohl(xdr->author);
108a58823acSDavid Howells 	status->owner		= ntohl(xdr->owner);
109a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
110a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
111a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
112a58823acSDavid Howells 	status->group		= ntohl(xdr->group);
113a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
114dd9fbcb8SDavid Howells 
115d4936803SDavid Howells 	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
116d4936803SDavid Howells 	status->mtime_client.tv_nsec = 0;
117d4936803SDavid Howells 	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
118d4936803SDavid Howells 	status->mtime_server.tv_nsec = 0;
119dd9fbcb8SDavid Howells 
120dd9fbcb8SDavid Howells 	size  = (u64)ntohl(xdr->size_lo);
121dd9fbcb8SDavid Howells 	size |= (u64)ntohl(xdr->size_hi) << 32;
122dd9fbcb8SDavid Howells 	status->size = size;
123dd9fbcb8SDavid Howells 
124dd9fbcb8SDavid Howells 	data_version  = (u64)ntohl(xdr->data_version_lo);
125dd9fbcb8SDavid Howells 	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
126dd9fbcb8SDavid Howells 	status->data_version = data_version;
127a38a7558SDavid Howells 	scb->have_status = true;
128c72057b5SDavid Howells good:
129c72057b5SDavid Howells 	ret = 0;
130c72057b5SDavid Howells advance:
131dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
132c72057b5SDavid Howells 	return ret;
133dd9fbcb8SDavid Howells 
134dd9fbcb8SDavid Howells bad:
135dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
136c72057b5SDavid Howells 	ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
137c72057b5SDavid Howells 	goto advance;
138c875c76aSDavid Howells }
139c875c76aSDavid Howells 
14078107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
14178107055SDavid Howells {
14278107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
14378107055SDavid Howells }
14478107055SDavid Howells 
145a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
146a58823acSDavid Howells 				   struct afs_call *call,
147a58823acSDavid Howells 				   struct afs_status_cb *scb)
14878107055SDavid Howells {
149a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
15078107055SDavid Howells 	const __be32 *bp = *_bp;
15178107055SDavid Howells 
1527c712458SDavid Howells 	bp++; /* version */
15378107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1547c712458SDavid Howells 	bp++; /* type */
155a58823acSDavid Howells 	scb->have_cb	= true;
15678107055SDavid Howells 	*_bp = bp;
15778107055SDavid Howells }
15878107055SDavid Howells 
1591da177e4SLinus Torvalds /*
16008e0e7c8SDavid Howells  * decode an AFSVolSync block
1611da177e4SLinus Torvalds  */
16208e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
16308e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1641da177e4SLinus Torvalds {
16508e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
16630062bd1SDavid Howells 	u32 creation;
1671da177e4SLinus Torvalds 
16830062bd1SDavid Howells 	creation = ntohl(*bp++);
16908e0e7c8SDavid Howells 	bp++; /* spare2 */
17008e0e7c8SDavid Howells 	bp++; /* spare3 */
17108e0e7c8SDavid Howells 	bp++; /* spare4 */
17208e0e7c8SDavid Howells 	bp++; /* spare5 */
17308e0e7c8SDavid Howells 	bp++; /* spare6 */
17408e0e7c8SDavid Howells 	*_bp = bp;
17530062bd1SDavid Howells 
17630062bd1SDavid Howells 	if (volsync)
17730062bd1SDavid Howells 		volsync->creation = creation;
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds 
18008e0e7c8SDavid Howells /*
18131143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
18231143d5dSDavid Howells  */
18331143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
18431143d5dSDavid Howells {
18531143d5dSDavid Howells 	__be32 *bp = *_bp;
18631143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
18731143d5dSDavid Howells 
18831143d5dSDavid Howells 	mask = 0;
18931143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
19031143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
19131143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
19231143d5dSDavid Howells 	}
19331143d5dSDavid Howells 
19431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
19531143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
196a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
19731143d5dSDavid Howells 	}
19831143d5dSDavid Howells 
19931143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
20031143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
201a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
20231143d5dSDavid Howells 	}
20331143d5dSDavid Howells 
20431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
20531143d5dSDavid Howells 		mask |= AFS_SET_MODE;
20631143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
20731143d5dSDavid Howells 	}
20831143d5dSDavid Howells 
20931143d5dSDavid Howells 	*bp++ = htonl(mask);
21031143d5dSDavid Howells 	*bp++ = htonl(mtime);
21131143d5dSDavid Howells 	*bp++ = htonl(owner);
21231143d5dSDavid Howells 	*bp++ = htonl(group);
21331143d5dSDavid Howells 	*bp++ = htonl(mode);
21431143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
21531143d5dSDavid Howells 	*_bp = bp;
21631143d5dSDavid Howells }
21731143d5dSDavid Howells 
21831143d5dSDavid Howells /*
21945222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
22045222b9eSDavid Howells  */
22145222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
22245222b9eSDavid Howells 					    struct afs_volume_status *vs)
22345222b9eSDavid Howells {
22445222b9eSDavid Howells 	const __be32 *bp = *_bp;
22545222b9eSDavid Howells 
22645222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
23045222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
23145222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
23245222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
23345222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
23445222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
23545222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
23645222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
23745222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23830062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23930062bd1SDavid Howells 	vs->vol_backup_date	= 0;
24045222b9eSDavid Howells 	*_bp = bp;
24145222b9eSDavid Howells }
24245222b9eSDavid Howells 
24345222b9eSDavid Howells /*
24408e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
24508e0e7c8SDavid Howells  */
2465cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
24708e0e7c8SDavid Howells {
24808e0e7c8SDavid Howells 	const __be32 *bp;
249372ee163SDavid Howells 	int ret;
2501da177e4SLinus Torvalds 
251d001648eSDavid Howells 	ret = afs_transfer_reply(call);
252372ee163SDavid Howells 	if (ret < 0)
253372ee163SDavid Howells 		return ret;
2541da177e4SLinus Torvalds 
25508e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25608e0e7c8SDavid Howells 	bp = call->buffer;
257a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
258160cb957SDavid Howells 	if (ret < 0)
259160cb957SDavid Howells 		return ret;
260a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
261ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2621da177e4SLinus Torvalds 
26308e0e7c8SDavid Howells 	_leave(" = 0 [done]");
26408e0e7c8SDavid Howells 	return 0;
265ec26815aSDavid Howells }
26608e0e7c8SDavid Howells 
26708e0e7c8SDavid Howells /*
26808e0e7c8SDavid Howells  * FS.FetchStatus operation type
26908e0e7c8SDavid Howells  */
2705cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
2715cf9dd55SDavid Howells 	.name		= "FS.FetchStatus(vnode)",
272025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
2735cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status_vnode,
27408e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
27508e0e7c8SDavid Howells };
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds /*
2781da177e4SLinus Torvalds  * fetch the status information for a file
2791da177e4SLinus Torvalds  */
280a58823acSDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
281a58823acSDavid Howells 			     struct afs_volsync *volsync)
2821da177e4SLinus Torvalds {
283d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
28408e0e7c8SDavid Howells 	struct afs_call *call;
285f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2861da177e4SLinus Torvalds 	__be32 *bp;
2871da177e4SLinus Torvalds 
28830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
289a58823acSDavid Howells 		return yfs_fs_fetch_file_status(fc, scb, volsync);
29030062bd1SDavid Howells 
2913b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
292d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2931da177e4SLinus Torvalds 
2945cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
2955cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
296d2ddc776SDavid Howells 	if (!call) {
297d2ddc776SDavid Howells 		fc->ac.error = -ENOMEM;
29808e0e7c8SDavid Howells 		return -ENOMEM;
299d2ddc776SDavid Howells 	}
3001da177e4SLinus Torvalds 
301d2ddc776SDavid Howells 	call->key = fc->key;
302a58823acSDavid Howells 	call->out_scb = scb;
303ffba718eSDavid Howells 	call->out_volsync = volsync;
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	/* marshall the parameters */
30608e0e7c8SDavid Howells 	bp = call->request;
3071da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
3081da177e4SLinus Torvalds 	bp[1] = htonl(vnode->fid.vid);
3091da177e4SLinus Torvalds 	bp[2] = htonl(vnode->fid.vnode);
3101da177e4SLinus Torvalds 	bp[3] = htonl(vnode->fid.unique);
3111da177e4SLinus Torvalds 
312d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
313025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
3140b9bf381SDavid Howells 
31520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
3160b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
3170b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
318ec26815aSDavid Howells }
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds /*
32108e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
3221da177e4SLinus Torvalds  */
323d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3241da177e4SLinus Torvalds {
325ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
32608e0e7c8SDavid Howells 	const __be32 *bp;
327196ee9cdSDavid Howells 	unsigned int size;
3281da177e4SLinus Torvalds 	int ret;
3291da177e4SLinus Torvalds 
33012bdcf33SDavid Howells 	_enter("{%u,%zu/%llu}",
331fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
3321da177e4SLinus Torvalds 
33308e0e7c8SDavid Howells 	switch (call->unmarshall) {
33408e0e7c8SDavid Howells 	case 0:
335196ee9cdSDavid Howells 		req->actual_len = 0;
33612bdcf33SDavid Howells 		req->index = 0;
33712bdcf33SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
33808e0e7c8SDavid Howells 		call->unmarshall++;
33912bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
34012bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
34112bdcf33SDavid Howells 		} else {
34212bdcf33SDavid Howells 			call->tmp_u = htonl(0);
34312bdcf33SDavid Howells 			afs_extract_to_tmp(call);
344b9b1f8d5SDavid Howells 		}
34529881608SGustavo A. R. Silva 		/* Fall through */
3461da177e4SLinus Torvalds 
34729881608SGustavo A. R. Silva 		/* extract the returned data length */
34812bdcf33SDavid Howells 	case 1:
34908e0e7c8SDavid Howells 		_debug("extract data length");
35012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
351372ee163SDavid Howells 		if (ret < 0)
352372ee163SDavid Howells 			return ret;
3531da177e4SLinus Torvalds 
35412bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
355196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
35612bdcf33SDavid Howells 		req->remain = min(req->len, req->actual_len);
35712bdcf33SDavid Howells 		if (req->remain == 0)
358196ee9cdSDavid Howells 			goto no_more_data;
35912bdcf33SDavid Howells 
36008e0e7c8SDavid Howells 		call->unmarshall++;
3611da177e4SLinus Torvalds 
362196ee9cdSDavid Howells 	begin_page:
3636db3ac3cSDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
36412bdcf33SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
36512bdcf33SDavid Howells 			size = PAGE_SIZE - req->offset;
366196ee9cdSDavid Howells 		else
367196ee9cdSDavid Howells 			size = req->remain;
36812bdcf33SDavid Howells 		call->bvec[0].bv_len = size;
36912bdcf33SDavid Howells 		call->bvec[0].bv_offset = req->offset;
37012bdcf33SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
371fc276122SDavid Howells 		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
37212bdcf33SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
37329881608SGustavo A. R. Silva 		/* Fall through */
374196ee9cdSDavid Howells 
37529881608SGustavo A. R. Silva 		/* extract the returned data */
37612bdcf33SDavid Howells 	case 2:
37712bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
378fc276122SDavid Howells 		       iov_iter_count(call->iter), req->remain);
379196ee9cdSDavid Howells 
38012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
381372ee163SDavid Howells 		if (ret < 0)
382372ee163SDavid Howells 			return ret;
38312bdcf33SDavid Howells 		req->remain -= call->bvec[0].bv_len;
38412bdcf33SDavid Howells 		req->offset += call->bvec[0].bv_len;
38512bdcf33SDavid Howells 		ASSERTCMP(req->offset, <=, PAGE_SIZE);
38612bdcf33SDavid Howells 		if (req->offset == PAGE_SIZE) {
38712bdcf33SDavid Howells 			req->offset = 0;
388196ee9cdSDavid Howells 			if (req->page_done)
389a58823acSDavid Howells 				req->page_done(req);
39029f06985SDavid Howells 			req->index++;
39112bdcf33SDavid Howells 			if (req->remain > 0)
392196ee9cdSDavid Howells 				goto begin_page;
393196ee9cdSDavid Howells 		}
39412bdcf33SDavid Howells 
39512bdcf33SDavid Howells 		ASSERTCMP(req->remain, ==, 0);
39612bdcf33SDavid Howells 		if (req->actual_len <= req->len)
3976db3ac3cSDavid Howells 			goto no_more_data;
3986db3ac3cSDavid Howells 
3996db3ac3cSDavid Howells 		/* Discard any excess data the server gave us */
40023a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
40112bdcf33SDavid Howells 		call->unmarshall = 3;
402e690c9e3SGustavo A. R. Silva 		/* Fall through */
40329881608SGustavo A. R. Silva 
40412bdcf33SDavid Howells 	case 3:
40512bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
406fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
4076db3ac3cSDavid Howells 
40812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
4096db3ac3cSDavid Howells 		if (ret < 0)
4106db3ac3cSDavid Howells 			return ret;
4111da177e4SLinus Torvalds 
412196ee9cdSDavid Howells 	no_more_data:
41312bdcf33SDavid Howells 		call->unmarshall = 4;
41412bdcf33SDavid Howells 		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
41529881608SGustavo A. R. Silva 		/* Fall through */
41608e0e7c8SDavid Howells 
41729881608SGustavo A. R. Silva 		/* extract the metadata */
41812bdcf33SDavid Howells 	case 4:
41912bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
420372ee163SDavid Howells 		if (ret < 0)
421372ee163SDavid Howells 			return ret;
4221da177e4SLinus Torvalds 
42308e0e7c8SDavid Howells 		bp = call->buffer;
424a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
425160cb957SDavid Howells 		if (ret < 0)
426160cb957SDavid Howells 			return ret;
427a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, call->out_scb);
428ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
4291da177e4SLinus Torvalds 
430a58823acSDavid Howells 		req->data_version = call->out_scb->status.data_version;
431a58823acSDavid Howells 		req->file_size = call->out_scb->status.size;
432a58823acSDavid Howells 
43308e0e7c8SDavid Howells 		call->unmarshall++;
4341da177e4SLinus Torvalds 
43512bdcf33SDavid Howells 	case 5:
4361da177e4SLinus Torvalds 		break;
4371da177e4SLinus Torvalds 	}
4381da177e4SLinus Torvalds 
4396db3ac3cSDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
44012bdcf33SDavid Howells 		if (req->offset < PAGE_SIZE)
4416db3ac3cSDavid Howells 			zero_user_segment(req->pages[req->index],
44212bdcf33SDavid Howells 					  req->offset, PAGE_SIZE);
443196ee9cdSDavid Howells 		if (req->page_done)
444a58823acSDavid Howells 			req->page_done(req);
44512bdcf33SDavid Howells 		req->offset = 0;
446416351f2SDavid Howells 	}
447416351f2SDavid Howells 
44808e0e7c8SDavid Howells 	_leave(" = 0 [done]");
44908e0e7c8SDavid Howells 	return 0;
450ec26815aSDavid Howells }
4511da177e4SLinus Torvalds 
452196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call)
453196ee9cdSDavid Howells {
454ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
455196ee9cdSDavid Howells 
456196ee9cdSDavid Howells 	afs_put_read(req);
457196ee9cdSDavid Howells 	afs_flat_call_destructor(call);
458196ee9cdSDavid Howells }
459196ee9cdSDavid Howells 
4601da177e4SLinus Torvalds /*
46108e0e7c8SDavid Howells  * FS.FetchData operation type
4621da177e4SLinus Torvalds  */
46308e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
46400d3b7a4SDavid Howells 	.name		= "FS.FetchData",
465025db80cSDavid Howells 	.op		= afs_FS_FetchData,
46608e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
467196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
46808e0e7c8SDavid Howells };
46908e0e7c8SDavid Howells 
470b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
471b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
472025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
473b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
474196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
475b9b1f8d5SDavid Howells };
476b9b1f8d5SDavid Howells 
477b9b1f8d5SDavid Howells /*
478b9b1f8d5SDavid Howells  * fetch data from a very large file
479b9b1f8d5SDavid Howells  */
480a58823acSDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc,
481a58823acSDavid Howells 			       struct afs_status_cb *scb,
482a58823acSDavid Howells 			       struct afs_read *req)
483b9b1f8d5SDavid Howells {
484d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
485b9b1f8d5SDavid Howells 	struct afs_call *call;
486f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
487b9b1f8d5SDavid Howells 	__be32 *bp;
488b9b1f8d5SDavid Howells 
489b9b1f8d5SDavid Howells 	_enter("");
490b9b1f8d5SDavid Howells 
491f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
492b9b1f8d5SDavid Howells 	if (!call)
493b9b1f8d5SDavid Howells 		return -ENOMEM;
494b9b1f8d5SDavid Howells 
495d2ddc776SDavid Howells 	call->key = fc->key;
496a58823acSDavid Howells 	call->out_scb = scb;
497ffba718eSDavid Howells 	call->out_volsync = NULL;
498d4438a25SDavid Howells 	call->read_request = afs_get_read(req);
499b9b1f8d5SDavid Howells 
500b9b1f8d5SDavid Howells 	/* marshall the parameters */
501b9b1f8d5SDavid Howells 	bp = call->request;
502b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
503b9b1f8d5SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
504b9b1f8d5SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
505b9b1f8d5SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
506196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
507196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
508b9b1f8d5SDavid Howells 	bp[6] = 0;
509196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
510b9b1f8d5SDavid Howells 
511d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
512025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
51320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5140b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5150b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
516b9b1f8d5SDavid Howells }
517b9b1f8d5SDavid Howells 
51808e0e7c8SDavid Howells /*
51908e0e7c8SDavid Howells  * fetch data from a file
52008e0e7c8SDavid Howells  */
521a58823acSDavid Howells int afs_fs_fetch_data(struct afs_fs_cursor *fc,
522a58823acSDavid Howells 		      struct afs_status_cb *scb,
523a58823acSDavid Howells 		      struct afs_read *req)
5241da177e4SLinus Torvalds {
525d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
52608e0e7c8SDavid Howells 	struct afs_call *call;
527f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
52808e0e7c8SDavid Howells 	__be32 *bp;
5291da177e4SLinus Torvalds 
53030062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
531a58823acSDavid Howells 		return yfs_fs_fetch_data(fc, scb, req);
53230062bd1SDavid Howells 
533196ee9cdSDavid Howells 	if (upper_32_bits(req->pos) ||
534196ee9cdSDavid Howells 	    upper_32_bits(req->len) ||
535196ee9cdSDavid Howells 	    upper_32_bits(req->pos + req->len))
536a58823acSDavid Howells 		return afs_fs_fetch_data64(fc, scb, req);
537b9b1f8d5SDavid Howells 
53808e0e7c8SDavid Howells 	_enter("");
5391da177e4SLinus Torvalds 
540f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
54108e0e7c8SDavid Howells 	if (!call)
54208e0e7c8SDavid Howells 		return -ENOMEM;
5431da177e4SLinus Torvalds 
544d2ddc776SDavid Howells 	call->key = fc->key;
545a58823acSDavid Howells 	call->out_scb = scb;
546ffba718eSDavid Howells 	call->out_volsync = NULL;
547d4438a25SDavid Howells 	call->read_request = afs_get_read(req);
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	/* marshall the parameters */
55008e0e7c8SDavid Howells 	bp = call->request;
55108e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
55208e0e7c8SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
55308e0e7c8SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
55408e0e7c8SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
555196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
556196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
5571da177e4SLinus Torvalds 
558d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
559025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
56020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5610b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5620b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
56308e0e7c8SDavid Howells }
564260a9803SDavid Howells 
565260a9803SDavid Howells /*
566260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
567260a9803SDavid Howells  */
568d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
569260a9803SDavid Howells {
570260a9803SDavid Howells 	const __be32 *bp;
571372ee163SDavid Howells 	int ret;
572260a9803SDavid Howells 
573d001648eSDavid Howells 	ret = afs_transfer_reply(call);
574372ee163SDavid Howells 	if (ret < 0)
575372ee163SDavid Howells 		return ret;
576260a9803SDavid Howells 
577260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
578260a9803SDavid Howells 	bp = call->buffer;
579ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
580a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
581160cb957SDavid Howells 	if (ret < 0)
582160cb957SDavid Howells 		return ret;
583a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
584160cb957SDavid Howells 	if (ret < 0)
585160cb957SDavid Howells 		return ret;
586a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
587ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
588260a9803SDavid Howells 
589260a9803SDavid Howells 	_leave(" = 0 [done]");
590260a9803SDavid Howells 	return 0;
591260a9803SDavid Howells }
592260a9803SDavid Howells 
593260a9803SDavid Howells /*
594260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
595260a9803SDavid Howells  */
596025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
597025db80cSDavid Howells 	.name		= "FS.CreateFile",
598025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
599025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
600025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
601025db80cSDavid Howells };
602025db80cSDavid Howells 
603025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
604025db80cSDavid Howells 	.name		= "FS.MakeDir",
605025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
606260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
607260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
608260a9803SDavid Howells };
609260a9803SDavid Howells 
610260a9803SDavid Howells /*
611260a9803SDavid Howells  * create a file or make a directory
612260a9803SDavid Howells  */
6138b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc,
614260a9803SDavid Howells 		  const char *name,
615260a9803SDavid Howells 		  umode_t mode,
616a58823acSDavid Howells 		  struct afs_status_cb *dvnode_scb,
617260a9803SDavid Howells 		  struct afs_fid *newfid,
618a58823acSDavid Howells 		  struct afs_status_cb *new_scb)
619260a9803SDavid Howells {
620ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
621260a9803SDavid Howells 	struct afs_call *call;
622ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
623260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
624260a9803SDavid Howells 	__be32 *bp;
625260a9803SDavid Howells 
62630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){
62730062bd1SDavid Howells 		if (S_ISDIR(mode))
628a58823acSDavid Howells 			return yfs_fs_make_dir(fc, name, mode, dvnode_scb,
629a58823acSDavid Howells 					       newfid, new_scb);
63030062bd1SDavid Howells 		else
631a58823acSDavid Howells 			return yfs_fs_create_file(fc, name, mode, dvnode_scb,
632a58823acSDavid Howells 						  newfid, new_scb);
63330062bd1SDavid Howells 	}
63430062bd1SDavid Howells 
635260a9803SDavid Howells 	_enter("");
636260a9803SDavid Howells 
637260a9803SDavid Howells 	namesz = strlen(name);
638260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
639260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
640260a9803SDavid Howells 
641025db80cSDavid Howells 	call = afs_alloc_flat_call(
642025db80cSDavid Howells 		net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
643025db80cSDavid Howells 		reqsz, (3 + 21 + 21 + 3 + 6) * 4);
644260a9803SDavid Howells 	if (!call)
645260a9803SDavid Howells 		return -ENOMEM;
646260a9803SDavid Howells 
647d2ddc776SDavid Howells 	call->key = fc->key;
648a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
649ffba718eSDavid Howells 	call->out_fid = newfid;
650a58823acSDavid Howells 	call->out_scb = new_scb;
651260a9803SDavid Howells 
652260a9803SDavid Howells 	/* marshall the parameters */
653260a9803SDavid Howells 	bp = call->request;
654260a9803SDavid Howells 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
655ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
656ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
657ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
658260a9803SDavid Howells 	*bp++ = htonl(namesz);
659260a9803SDavid Howells 	memcpy(bp, name, namesz);
660260a9803SDavid Howells 	bp = (void *) bp + namesz;
661260a9803SDavid Howells 	if (padsz > 0) {
662260a9803SDavid Howells 		memset(bp, 0, padsz);
663260a9803SDavid Howells 		bp = (void *) bp + padsz;
664260a9803SDavid Howells 	}
665ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
666ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
667260a9803SDavid Howells 	*bp++ = 0; /* owner */
668260a9803SDavid Howells 	*bp++ = 0; /* group */
669260a9803SDavid Howells 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
670260a9803SDavid Howells 	*bp++ = 0; /* segment size */
671260a9803SDavid Howells 
672d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
673ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
67420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
6750b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
6760b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
677260a9803SDavid Howells }
678260a9803SDavid Howells 
679260a9803SDavid Howells /*
680ffba718eSDavid Howells  * Deliver reply data to any operation that returns directory status and volume
681b10494afSJoe Gorse  * sync.
682260a9803SDavid Howells  */
683ffba718eSDavid Howells static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call)
684260a9803SDavid Howells {
685260a9803SDavid Howells 	const __be32 *bp;
686372ee163SDavid Howells 	int ret;
687260a9803SDavid Howells 
688d001648eSDavid Howells 	ret = afs_transfer_reply(call);
689372ee163SDavid Howells 	if (ret < 0)
690372ee163SDavid Howells 		return ret;
691260a9803SDavid Howells 
692260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
693260a9803SDavid Howells 	bp = call->buffer;
694a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
695160cb957SDavid Howells 	if (ret < 0)
696160cb957SDavid Howells 		return ret;
697ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
698260a9803SDavid Howells 
699260a9803SDavid Howells 	_leave(" = 0 [done]");
700260a9803SDavid Howells 	return 0;
701260a9803SDavid Howells }
702260a9803SDavid Howells 
703260a9803SDavid Howells /*
704260a9803SDavid Howells  * FS.RemoveDir/FS.RemoveFile operation type
705260a9803SDavid Howells  */
706025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
707025db80cSDavid Howells 	.name		= "FS.RemoveFile",
708025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
709ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
710025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
711025db80cSDavid Howells };
712025db80cSDavid Howells 
713025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
714025db80cSDavid Howells 	.name		= "FS.RemoveDir",
715025db80cSDavid Howells 	.op		= afs_FS_RemoveDir,
716ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
717260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
718260a9803SDavid Howells };
719260a9803SDavid Howells 
720260a9803SDavid Howells /*
721260a9803SDavid Howells  * remove a file or directory
722260a9803SDavid Howells  */
72330062bd1SDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
724a58823acSDavid Howells 		  const char *name, bool isdir, struct afs_status_cb *dvnode_scb)
725260a9803SDavid Howells {
72630062bd1SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
727260a9803SDavid Howells 	struct afs_call *call;
72830062bd1SDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
729260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
730260a9803SDavid Howells 	__be32 *bp;
731260a9803SDavid Howells 
73230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
733a58823acSDavid Howells 		return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb);
73430062bd1SDavid Howells 
735260a9803SDavid Howells 	_enter("");
736260a9803SDavid Howells 
737260a9803SDavid Howells 	namesz = strlen(name);
738260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
739260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
740260a9803SDavid Howells 
741025db80cSDavid Howells 	call = afs_alloc_flat_call(
742025db80cSDavid Howells 		net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
743025db80cSDavid Howells 		reqsz, (21 + 6) * 4);
744260a9803SDavid Howells 	if (!call)
745260a9803SDavid Howells 		return -ENOMEM;
746260a9803SDavid Howells 
747d2ddc776SDavid Howells 	call->key = fc->key;
748a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
749260a9803SDavid Howells 
750260a9803SDavid Howells 	/* marshall the parameters */
751260a9803SDavid Howells 	bp = call->request;
752260a9803SDavid Howells 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
75330062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
75430062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
75530062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
756260a9803SDavid Howells 	*bp++ = htonl(namesz);
757260a9803SDavid Howells 	memcpy(bp, name, namesz);
758260a9803SDavid Howells 	bp = (void *) bp + namesz;
759260a9803SDavid Howells 	if (padsz > 0) {
760260a9803SDavid Howells 		memset(bp, 0, padsz);
761260a9803SDavid Howells 		bp = (void *) bp + padsz;
762260a9803SDavid Howells 	}
763260a9803SDavid Howells 
764d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
76580548b03SDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
76620b8391fSDavid Howells 	afs_set_fc_call(call, fc);
7670b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
7680b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
769260a9803SDavid Howells }
770260a9803SDavid Howells 
771260a9803SDavid Howells /*
772260a9803SDavid Howells  * deliver reply data to an FS.Link
773260a9803SDavid Howells  */
774d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
775260a9803SDavid Howells {
776260a9803SDavid Howells 	const __be32 *bp;
777372ee163SDavid Howells 	int ret;
778260a9803SDavid Howells 
779d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
780260a9803SDavid Howells 
781d001648eSDavid Howells 	ret = afs_transfer_reply(call);
782372ee163SDavid Howells 	if (ret < 0)
783372ee163SDavid Howells 		return ret;
784260a9803SDavid Howells 
785260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
786260a9803SDavid Howells 	bp = call->buffer;
787a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
788160cb957SDavid Howells 	if (ret < 0)
789160cb957SDavid Howells 		return ret;
790a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
791160cb957SDavid Howells 	if (ret < 0)
792160cb957SDavid Howells 		return ret;
793ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
794260a9803SDavid Howells 
795260a9803SDavid Howells 	_leave(" = 0 [done]");
796260a9803SDavid Howells 	return 0;
797260a9803SDavid Howells }
798260a9803SDavid Howells 
799260a9803SDavid Howells /*
800260a9803SDavid Howells  * FS.Link operation type
801260a9803SDavid Howells  */
802260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
803260a9803SDavid Howells 	.name		= "FS.Link",
804025db80cSDavid Howells 	.op		= afs_FS_Link,
805260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
806260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
807260a9803SDavid Howells };
808260a9803SDavid Howells 
809260a9803SDavid Howells /*
810260a9803SDavid Howells  * make a hard link
811260a9803SDavid Howells  */
812d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
813a58823acSDavid Howells 		const char *name,
814a58823acSDavid Howells 		struct afs_status_cb *dvnode_scb,
815a58823acSDavid Howells 		struct afs_status_cb *vnode_scb)
816260a9803SDavid Howells {
817d2ddc776SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
818260a9803SDavid Howells 	struct afs_call *call;
819f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
820260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
821260a9803SDavid Howells 	__be32 *bp;
822260a9803SDavid Howells 
82330062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
824a58823acSDavid Howells 		return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb);
82530062bd1SDavid Howells 
826260a9803SDavid Howells 	_enter("");
827260a9803SDavid Howells 
828260a9803SDavid Howells 	namesz = strlen(name);
829260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
830260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
831260a9803SDavid Howells 
832f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
833260a9803SDavid Howells 	if (!call)
834260a9803SDavid Howells 		return -ENOMEM;
835260a9803SDavid Howells 
836d2ddc776SDavid Howells 	call->key = fc->key;
837a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
838a58823acSDavid Howells 	call->out_scb = vnode_scb;
839260a9803SDavid Howells 
840260a9803SDavid Howells 	/* marshall the parameters */
841260a9803SDavid Howells 	bp = call->request;
842260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
843260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
844260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
845260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
846260a9803SDavid Howells 	*bp++ = htonl(namesz);
847260a9803SDavid Howells 	memcpy(bp, name, namesz);
848260a9803SDavid Howells 	bp = (void *) bp + namesz;
849260a9803SDavid Howells 	if (padsz > 0) {
850260a9803SDavid Howells 		memset(bp, 0, padsz);
851260a9803SDavid Howells 		bp = (void *) bp + padsz;
852260a9803SDavid Howells 	}
853260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
854260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
855260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
856260a9803SDavid Howells 
857d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
85880548b03SDavid Howells 	trace_afs_make_fs_call1(call, &vnode->fid, name);
85920b8391fSDavid Howells 	afs_set_fc_call(call, fc);
8600b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
8610b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
862260a9803SDavid Howells }
863260a9803SDavid Howells 
864260a9803SDavid Howells /*
865260a9803SDavid Howells  * deliver reply data to an FS.Symlink
866260a9803SDavid Howells  */
867d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
868260a9803SDavid Howells {
869260a9803SDavid Howells 	const __be32 *bp;
870372ee163SDavid Howells 	int ret;
871260a9803SDavid Howells 
872d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
873260a9803SDavid Howells 
874d001648eSDavid Howells 	ret = afs_transfer_reply(call);
875372ee163SDavid Howells 	if (ret < 0)
876372ee163SDavid Howells 		return ret;
877260a9803SDavid Howells 
878260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
879260a9803SDavid Howells 	bp = call->buffer;
880ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
881a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
882160cb957SDavid Howells 	if (ret < 0)
883160cb957SDavid Howells 		return ret;
884a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
885160cb957SDavid Howells 	if (ret < 0)
886160cb957SDavid Howells 		return ret;
887ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
888260a9803SDavid Howells 
889260a9803SDavid Howells 	_leave(" = 0 [done]");
890260a9803SDavid Howells 	return 0;
891260a9803SDavid Howells }
892260a9803SDavid Howells 
893260a9803SDavid Howells /*
894260a9803SDavid Howells  * FS.Symlink operation type
895260a9803SDavid Howells  */
896260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
897260a9803SDavid Howells 	.name		= "FS.Symlink",
898025db80cSDavid Howells 	.op		= afs_FS_Symlink,
899260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
900260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
901260a9803SDavid Howells };
902260a9803SDavid Howells 
903260a9803SDavid Howells /*
904260a9803SDavid Howells  * create a symbolic link
905260a9803SDavid Howells  */
9068b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc,
907260a9803SDavid Howells 		   const char *name,
908260a9803SDavid Howells 		   const char *contents,
909a58823acSDavid Howells 		   struct afs_status_cb *dvnode_scb,
910260a9803SDavid Howells 		   struct afs_fid *newfid,
911a58823acSDavid Howells 		   struct afs_status_cb *new_scb)
912260a9803SDavid Howells {
913ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
914260a9803SDavid Howells 	struct afs_call *call;
915ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
916260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
917260a9803SDavid Howells 	__be32 *bp;
918260a9803SDavid Howells 
91930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
920a58823acSDavid Howells 		return yfs_fs_symlink(fc, name, contents, dvnode_scb,
921a58823acSDavid Howells 				      newfid, new_scb);
92230062bd1SDavid Howells 
923260a9803SDavid Howells 	_enter("");
924260a9803SDavid Howells 
925260a9803SDavid Howells 	namesz = strlen(name);
926260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
927260a9803SDavid Howells 
928260a9803SDavid Howells 	c_namesz = strlen(contents);
929260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
930260a9803SDavid Howells 
931260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
932260a9803SDavid Howells 
933f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
934260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
935260a9803SDavid Howells 	if (!call)
936260a9803SDavid Howells 		return -ENOMEM;
937260a9803SDavid Howells 
938d2ddc776SDavid Howells 	call->key = fc->key;
939a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
940ffba718eSDavid Howells 	call->out_fid = newfid;
941a58823acSDavid Howells 	call->out_scb = new_scb;
942260a9803SDavid Howells 
943260a9803SDavid Howells 	/* marshall the parameters */
944260a9803SDavid Howells 	bp = call->request;
945260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
946ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
947ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
948ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
949260a9803SDavid Howells 	*bp++ = htonl(namesz);
950260a9803SDavid Howells 	memcpy(bp, name, namesz);
951260a9803SDavid Howells 	bp = (void *) bp + namesz;
952260a9803SDavid Howells 	if (padsz > 0) {
953260a9803SDavid Howells 		memset(bp, 0, padsz);
954260a9803SDavid Howells 		bp = (void *) bp + padsz;
955260a9803SDavid Howells 	}
956260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
957260a9803SDavid Howells 	memcpy(bp, contents, c_namesz);
958260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
959260a9803SDavid Howells 	if (c_padsz > 0) {
960260a9803SDavid Howells 		memset(bp, 0, c_padsz);
961260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
962260a9803SDavid Howells 	}
963ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
964ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
965260a9803SDavid Howells 	*bp++ = 0; /* owner */
966260a9803SDavid Howells 	*bp++ = 0; /* group */
967260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
968260a9803SDavid Howells 	*bp++ = 0; /* segment size */
969260a9803SDavid Howells 
970d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
971ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
97220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
9730b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
9740b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
975260a9803SDavid Howells }
976260a9803SDavid Howells 
977260a9803SDavid Howells /*
978260a9803SDavid Howells  * deliver reply data to an FS.Rename
979260a9803SDavid Howells  */
980d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
981260a9803SDavid Howells {
982260a9803SDavid Howells 	const __be32 *bp;
983372ee163SDavid Howells 	int ret;
984260a9803SDavid Howells 
985d001648eSDavid Howells 	ret = afs_transfer_reply(call);
986372ee163SDavid Howells 	if (ret < 0)
987372ee163SDavid Howells 		return ret;
988260a9803SDavid Howells 
989260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
990260a9803SDavid Howells 	bp = call->buffer;
991a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
992160cb957SDavid Howells 	if (ret < 0)
993160cb957SDavid Howells 		return ret;
994a58823acSDavid Howells 	if (call->out_dir_scb != call->out_scb) {
995a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
996160cb957SDavid Howells 		if (ret < 0)
997160cb957SDavid Howells 			return ret;
998160cb957SDavid Howells 	}
999ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
1000260a9803SDavid Howells 
1001260a9803SDavid Howells 	_leave(" = 0 [done]");
1002260a9803SDavid Howells 	return 0;
1003260a9803SDavid Howells }
1004260a9803SDavid Howells 
1005260a9803SDavid Howells /*
1006260a9803SDavid Howells  * FS.Rename operation type
1007260a9803SDavid Howells  */
1008260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
1009260a9803SDavid Howells 	.name		= "FS.Rename",
1010025db80cSDavid Howells 	.op		= afs_FS_Rename,
1011260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
1012260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
1013260a9803SDavid Howells };
1014260a9803SDavid Howells 
1015260a9803SDavid Howells /*
1016a58823acSDavid Howells  * Rename/move a file or directory.
1017260a9803SDavid Howells  */
10188b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc,
1019260a9803SDavid Howells 		  const char *orig_name,
1020260a9803SDavid Howells 		  struct afs_vnode *new_dvnode,
102163a4681fSDavid Howells 		  const char *new_name,
1022a58823acSDavid Howells 		  struct afs_status_cb *orig_dvnode_scb,
1023a58823acSDavid Howells 		  struct afs_status_cb *new_dvnode_scb)
1024260a9803SDavid Howells {
1025d2ddc776SDavid Howells 	struct afs_vnode *orig_dvnode = fc->vnode;
1026260a9803SDavid Howells 	struct afs_call *call;
1027f044c884SDavid Howells 	struct afs_net *net = afs_v2net(orig_dvnode);
1028260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1029260a9803SDavid Howells 	__be32 *bp;
1030260a9803SDavid Howells 
103130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
103230062bd1SDavid Howells 		return yfs_fs_rename(fc, orig_name,
103330062bd1SDavid Howells 				     new_dvnode, new_name,
1034a58823acSDavid Howells 				     orig_dvnode_scb,
1035a58823acSDavid Howells 				     new_dvnode_scb);
103630062bd1SDavid Howells 
1037260a9803SDavid Howells 	_enter("");
1038260a9803SDavid Howells 
1039260a9803SDavid Howells 	o_namesz = strlen(orig_name);
1040260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
1041260a9803SDavid Howells 
1042260a9803SDavid Howells 	n_namesz = strlen(new_name);
1043260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
1044260a9803SDavid Howells 
1045260a9803SDavid Howells 	reqsz = (4 * 4) +
1046260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1047260a9803SDavid Howells 		(3 * 4) +
1048260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1049260a9803SDavid Howells 
1050f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1051260a9803SDavid Howells 	if (!call)
1052260a9803SDavid Howells 		return -ENOMEM;
1053260a9803SDavid Howells 
1054d2ddc776SDavid Howells 	call->key = fc->key;
1055a58823acSDavid Howells 	call->out_dir_scb = orig_dvnode_scb;
1056a58823acSDavid Howells 	call->out_scb = new_dvnode_scb;
1057260a9803SDavid Howells 
1058260a9803SDavid Howells 	/* marshall the parameters */
1059260a9803SDavid Howells 	bp = call->request;
1060260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1061260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vid);
1062260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vnode);
1063260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.unique);
1064260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1065260a9803SDavid Howells 	memcpy(bp, orig_name, o_namesz);
1066260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1067260a9803SDavid Howells 	if (o_padsz > 0) {
1068260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1069260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1070260a9803SDavid Howells 	}
1071260a9803SDavid Howells 
1072260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vid);
1073260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vnode);
1074260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.unique);
1075260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1076260a9803SDavid Howells 	memcpy(bp, new_name, n_namesz);
1077260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1078260a9803SDavid Howells 	if (n_padsz > 0) {
1079260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1080260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1081260a9803SDavid Howells 	}
1082260a9803SDavid Howells 
1083d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
108480548b03SDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
108520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
10860b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
10870b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1088260a9803SDavid Howells }
108931143d5dSDavid Howells 
109031143d5dSDavid Howells /*
109131143d5dSDavid Howells  * deliver reply data to an FS.StoreData
109231143d5dSDavid Howells  */
1093d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
109431143d5dSDavid Howells {
109531143d5dSDavid Howells 	const __be32 *bp;
1096372ee163SDavid Howells 	int ret;
109731143d5dSDavid Howells 
1098d001648eSDavid Howells 	_enter("");
109931143d5dSDavid Howells 
1100d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1101372ee163SDavid Howells 	if (ret < 0)
1102372ee163SDavid Howells 		return ret;
110331143d5dSDavid Howells 
110431143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
110531143d5dSDavid Howells 	bp = call->buffer;
1106a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1107160cb957SDavid Howells 	if (ret < 0)
1108160cb957SDavid Howells 		return ret;
1109ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
111031143d5dSDavid Howells 
111131143d5dSDavid Howells 	_leave(" = 0 [done]");
111231143d5dSDavid Howells 	return 0;
111331143d5dSDavid Howells }
111431143d5dSDavid Howells 
111531143d5dSDavid Howells /*
111631143d5dSDavid Howells  * FS.StoreData operation type
111731143d5dSDavid Howells  */
111831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
111931143d5dSDavid Howells 	.name		= "FS.StoreData",
1120025db80cSDavid Howells 	.op		= afs_FS_StoreData,
112131143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
112231143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
112331143d5dSDavid Howells };
112431143d5dSDavid Howells 
1125b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1126b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1127025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1128b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1129b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1130b9b1f8d5SDavid Howells };
1131b9b1f8d5SDavid Howells 
1132b9b1f8d5SDavid Howells /*
1133b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1134b9b1f8d5SDavid Howells  */
11358b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc,
11364343d008SDavid Howells 			       struct address_space *mapping,
1137b9b1f8d5SDavid Howells 			       pgoff_t first, pgoff_t last,
1138b9b1f8d5SDavid Howells 			       unsigned offset, unsigned to,
1139a58823acSDavid Howells 			       loff_t size, loff_t pos, loff_t i_size,
1140a58823acSDavid Howells 			       struct afs_status_cb *scb)
1141b9b1f8d5SDavid Howells {
11424343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1143b9b1f8d5SDavid Howells 	struct afs_call *call;
1144f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1145b9b1f8d5SDavid Howells 	__be32 *bp;
1146b9b1f8d5SDavid Howells 
11473b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
11484343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1149b9b1f8d5SDavid Howells 
1150f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
1151b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1152b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1153b9b1f8d5SDavid Howells 	if (!call)
1154b9b1f8d5SDavid Howells 		return -ENOMEM;
1155b9b1f8d5SDavid Howells 
11564343d008SDavid Howells 	call->key = fc->key;
11574343d008SDavid Howells 	call->mapping = mapping;
1158b9b1f8d5SDavid Howells 	call->first = first;
1159b9b1f8d5SDavid Howells 	call->last = last;
1160b9b1f8d5SDavid Howells 	call->first_offset = offset;
1161b9b1f8d5SDavid Howells 	call->last_to = to;
1162b9b1f8d5SDavid Howells 	call->send_pages = true;
1163a58823acSDavid Howells 	call->out_scb = scb;
1164b9b1f8d5SDavid Howells 
1165b9b1f8d5SDavid Howells 	/* marshall the parameters */
1166b9b1f8d5SDavid Howells 	bp = call->request;
1167b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1168b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1169b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1170b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1171b9b1f8d5SDavid Howells 
1172ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1173ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1174b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1175b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1176b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1177b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1178b9b1f8d5SDavid Howells 
1179b9b1f8d5SDavid Howells 	*bp++ = htonl(pos >> 32);
1180b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) pos);
1181b9b1f8d5SDavid Howells 	*bp++ = htonl(size >> 32);
1182b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) size);
1183b9b1f8d5SDavid Howells 	*bp++ = htonl(i_size >> 32);
1184b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) i_size);
1185b9b1f8d5SDavid Howells 
1186025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
118720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
11880b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
11890b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1190b9b1f8d5SDavid Howells }
1191b9b1f8d5SDavid Howells 
119231143d5dSDavid Howells /*
119331143d5dSDavid Howells  * store a set of pages
119431143d5dSDavid Howells  */
11954343d008SDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
119631143d5dSDavid Howells 		      pgoff_t first, pgoff_t last,
1197a58823acSDavid Howells 		      unsigned offset, unsigned to,
1198a58823acSDavid Howells 		      struct afs_status_cb *scb)
119931143d5dSDavid Howells {
12004343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
120131143d5dSDavid Howells 	struct afs_call *call;
1202f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
120331143d5dSDavid Howells 	loff_t size, pos, i_size;
120431143d5dSDavid Howells 	__be32 *bp;
120531143d5dSDavid Howells 
120630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1207a58823acSDavid Howells 		return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb);
120830062bd1SDavid Howells 
12093b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
12104343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
121131143d5dSDavid Howells 
1212146a1192SDavid Howells 	size = (loff_t)to - (loff_t)offset;
121331143d5dSDavid Howells 	if (first != last)
121431143d5dSDavid Howells 		size += (loff_t)(last - first) << PAGE_SHIFT;
121531143d5dSDavid Howells 	pos = (loff_t)first << PAGE_SHIFT;
121631143d5dSDavid Howells 	pos += offset;
121731143d5dSDavid Howells 
121831143d5dSDavid Howells 	i_size = i_size_read(&vnode->vfs_inode);
121931143d5dSDavid Howells 	if (pos + size > i_size)
122031143d5dSDavid Howells 		i_size = size + pos;
122131143d5dSDavid Howells 
122231143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
122331143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
122431143d5dSDavid Howells 	       (unsigned long long) i_size);
122531143d5dSDavid Howells 
1226b9b1f8d5SDavid Howells 	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
12274343d008SDavid Howells 		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
1228a58823acSDavid Howells 					   size, pos, i_size, scb);
122931143d5dSDavid Howells 
1230f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
123131143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
123231143d5dSDavid Howells 				   (21 + 6) * 4);
123331143d5dSDavid Howells 	if (!call)
123431143d5dSDavid Howells 		return -ENOMEM;
123531143d5dSDavid Howells 
12364343d008SDavid Howells 	call->key = fc->key;
12374343d008SDavid Howells 	call->mapping = mapping;
123831143d5dSDavid Howells 	call->first = first;
123931143d5dSDavid Howells 	call->last = last;
124031143d5dSDavid Howells 	call->first_offset = offset;
124131143d5dSDavid Howells 	call->last_to = to;
124231143d5dSDavid Howells 	call->send_pages = true;
1243a58823acSDavid Howells 	call->out_scb = scb;
124431143d5dSDavid Howells 
124531143d5dSDavid Howells 	/* marshall the parameters */
124631143d5dSDavid Howells 	bp = call->request;
124731143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
124831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
124931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
125031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
125131143d5dSDavid Howells 
1252ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1253ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
125431143d5dSDavid Howells 	*bp++ = 0; /* owner */
125531143d5dSDavid Howells 	*bp++ = 0; /* group */
125631143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
125731143d5dSDavid Howells 	*bp++ = 0; /* segment size */
125831143d5dSDavid Howells 
125931143d5dSDavid Howells 	*bp++ = htonl(pos);
126031143d5dSDavid Howells 	*bp++ = htonl(size);
126131143d5dSDavid Howells 	*bp++ = htonl(i_size);
126231143d5dSDavid Howells 
1263d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1264025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
126520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
12660b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
12670b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
126831143d5dSDavid Howells }
126931143d5dSDavid Howells 
127031143d5dSDavid Howells /*
127131143d5dSDavid Howells  * deliver reply data to an FS.StoreStatus
127231143d5dSDavid Howells  */
1273d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call)
127431143d5dSDavid Howells {
127531143d5dSDavid Howells 	const __be32 *bp;
1276372ee163SDavid Howells 	int ret;
127731143d5dSDavid Howells 
1278d001648eSDavid Howells 	_enter("");
127931143d5dSDavid Howells 
1280d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1281372ee163SDavid Howells 	if (ret < 0)
1282372ee163SDavid Howells 		return ret;
128331143d5dSDavid Howells 
128431143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
128531143d5dSDavid Howells 	bp = call->buffer;
1286a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1287160cb957SDavid Howells 	if (ret < 0)
1288160cb957SDavid Howells 		return ret;
1289ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
129031143d5dSDavid Howells 
129131143d5dSDavid Howells 	_leave(" = 0 [done]");
129231143d5dSDavid Howells 	return 0;
129331143d5dSDavid Howells }
129431143d5dSDavid Howells 
129531143d5dSDavid Howells /*
129631143d5dSDavid Howells  * FS.StoreStatus operation type
129731143d5dSDavid Howells  */
129831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
129931143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1300025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
130131143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130231143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
130331143d5dSDavid Howells };
130431143d5dSDavid Howells 
130531143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
130631143d5dSDavid Howells 	.name		= "FS.StoreData",
1307025db80cSDavid Howells 	.op		= afs_FS_StoreData,
130831143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130931143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
131031143d5dSDavid Howells };
131131143d5dSDavid Howells 
1312b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1313b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1314025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1315b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_status,
1316b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1317b9b1f8d5SDavid Howells };
1318b9b1f8d5SDavid Howells 
1319b9b1f8d5SDavid Howells /*
1320b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1321b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1322b9b1f8d5SDavid Howells  */
1323a58823acSDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr,
1324a58823acSDavid Howells 				 struct afs_status_cb *scb)
1325b9b1f8d5SDavid Howells {
1326d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1327b9b1f8d5SDavid Howells 	struct afs_call *call;
1328f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1329b9b1f8d5SDavid Howells 	__be32 *bp;
1330b9b1f8d5SDavid Howells 
13313b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1332d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1333b9b1f8d5SDavid Howells 
1334b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1335b9b1f8d5SDavid Howells 
1336f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
1337b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1338b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1339b9b1f8d5SDavid Howells 	if (!call)
1340b9b1f8d5SDavid Howells 		return -ENOMEM;
1341b9b1f8d5SDavid Howells 
1342d2ddc776SDavid Howells 	call->key = fc->key;
1343a58823acSDavid Howells 	call->out_scb = scb;
1344b9b1f8d5SDavid Howells 
1345b9b1f8d5SDavid Howells 	/* marshall the parameters */
1346b9b1f8d5SDavid Howells 	bp = call->request;
1347b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1348b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1349b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1350b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1351b9b1f8d5SDavid Howells 
1352b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1353b9b1f8d5SDavid Howells 
13548c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* position of start of write */
13558c7ae38dSDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1356b9b1f8d5SDavid Howells 	*bp++ = 0;				/* size of write */
1357b9b1f8d5SDavid Howells 	*bp++ = 0;
1358b9b1f8d5SDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
1359b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1360b9b1f8d5SDavid Howells 
1361d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1362025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
136320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
13640b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
13650b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1366b9b1f8d5SDavid Howells }
1367b9b1f8d5SDavid Howells 
136831143d5dSDavid Howells /*
136931143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
137031143d5dSDavid Howells  * so as to alter the file size also
137131143d5dSDavid Howells  */
1372a58823acSDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
1373a58823acSDavid Howells 			       struct afs_status_cb *scb)
137431143d5dSDavid Howells {
1375d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
137631143d5dSDavid Howells 	struct afs_call *call;
1377f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
137831143d5dSDavid Howells 	__be32 *bp;
137931143d5dSDavid Howells 
13803b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1381d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
138231143d5dSDavid Howells 
138331143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1384b9b1f8d5SDavid Howells 	if (attr->ia_size >> 32)
1385a58823acSDavid Howells 		return afs_fs_setattr_size64(fc, attr, scb);
138631143d5dSDavid Howells 
1387f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
138831143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
138931143d5dSDavid Howells 				   (21 + 6) * 4);
139031143d5dSDavid Howells 	if (!call)
139131143d5dSDavid Howells 		return -ENOMEM;
139231143d5dSDavid Howells 
1393d2ddc776SDavid Howells 	call->key = fc->key;
1394a58823acSDavid Howells 	call->out_scb = scb;
139531143d5dSDavid Howells 
139631143d5dSDavid Howells 	/* marshall the parameters */
139731143d5dSDavid Howells 	bp = call->request;
139831143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
139931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
140031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
140131143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
140231143d5dSDavid Howells 
140331143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
140431143d5dSDavid Howells 
14058c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
140631143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
140731143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
140831143d5dSDavid Howells 
1409d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1410025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
141120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14120b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14130b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
141431143d5dSDavid Howells }
141531143d5dSDavid Howells 
141631143d5dSDavid Howells /*
141731143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
141831143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
141931143d5dSDavid Howells  */
1420a58823acSDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
1421a58823acSDavid Howells 		   struct afs_status_cb *scb)
142231143d5dSDavid Howells {
1423d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
142431143d5dSDavid Howells 	struct afs_call *call;
1425f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
142631143d5dSDavid Howells 	__be32 *bp;
142731143d5dSDavid Howells 
142830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1429a58823acSDavid Howells 		return yfs_fs_setattr(fc, attr, scb);
143030062bd1SDavid Howells 
143131143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1432a58823acSDavid Howells 		return afs_fs_setattr_size(fc, attr, scb);
143331143d5dSDavid Howells 
14343b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1435d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
143631143d5dSDavid Howells 
1437f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
143831143d5dSDavid Howells 				   (4 + 6) * 4,
143931143d5dSDavid Howells 				   (21 + 6) * 4);
144031143d5dSDavid Howells 	if (!call)
144131143d5dSDavid Howells 		return -ENOMEM;
144231143d5dSDavid Howells 
1443d2ddc776SDavid Howells 	call->key = fc->key;
1444a58823acSDavid Howells 	call->out_scb = scb;
144531143d5dSDavid Howells 
144631143d5dSDavid Howells 	/* marshall the parameters */
144731143d5dSDavid Howells 	bp = call->request;
144831143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
144931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
145031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
145131143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
145231143d5dSDavid Howells 
145331143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
145431143d5dSDavid Howells 
1455d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1456025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
145720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14580b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14590b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
146031143d5dSDavid Howells }
146145222b9eSDavid Howells 
146245222b9eSDavid Howells /*
146345222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
146445222b9eSDavid Howells  */
1465d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
146645222b9eSDavid Howells {
146745222b9eSDavid Howells 	const __be32 *bp;
146845222b9eSDavid Howells 	char *p;
146912bdcf33SDavid Howells 	u32 size;
147045222b9eSDavid Howells 	int ret;
147145222b9eSDavid Howells 
1472d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
147345222b9eSDavid Howells 
147445222b9eSDavid Howells 	switch (call->unmarshall) {
147545222b9eSDavid Howells 	case 0:
147645222b9eSDavid Howells 		call->unmarshall++;
147712bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
147829881608SGustavo A. R. Silva 		/* Fall through */
147945222b9eSDavid Howells 
148029881608SGustavo A. R. Silva 		/* extract the returned status record */
148145222b9eSDavid Howells 	case 1:
148245222b9eSDavid Howells 		_debug("extract status");
148312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1484372ee163SDavid Howells 		if (ret < 0)
1485372ee163SDavid Howells 			return ret;
148645222b9eSDavid Howells 
148745222b9eSDavid Howells 		bp = call->buffer;
1488ffba718eSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, call->out_volstatus);
148945222b9eSDavid Howells 		call->unmarshall++;
149012bdcf33SDavid Howells 		afs_extract_to_tmp(call);
149129881608SGustavo A. R. Silva 		/* Fall through */
149245222b9eSDavid Howells 
149329881608SGustavo A. R. Silva 		/* extract the volume name length */
149445222b9eSDavid Howells 	case 2:
149512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1496372ee163SDavid Howells 		if (ret < 0)
1497372ee163SDavid Howells 			return ret;
149845222b9eSDavid Howells 
149945222b9eSDavid Howells 		call->count = ntohl(call->tmp);
150045222b9eSDavid Howells 		_debug("volname length: %u", call->count);
150145222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1502160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1503160cb957SDavid Howells 						  afs_eproto_volname_len);
150412bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1505ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
150645222b9eSDavid Howells 		call->unmarshall++;
150729881608SGustavo A. R. Silva 		/* Fall through */
150845222b9eSDavid Howells 
150929881608SGustavo A. R. Silva 		/* extract the volume name */
151045222b9eSDavid Howells 	case 3:
151145222b9eSDavid Howells 		_debug("extract volname");
151212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1513372ee163SDavid Howells 		if (ret < 0)
1514372ee163SDavid Howells 			return ret;
151545222b9eSDavid Howells 
1516ffba718eSDavid Howells 		p = call->buffer;
151745222b9eSDavid Howells 		p[call->count] = 0;
151845222b9eSDavid Howells 		_debug("volname '%s'", p);
151912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
152045222b9eSDavid Howells 		call->unmarshall++;
152129881608SGustavo A. R. Silva 		/* Fall through */
152245222b9eSDavid Howells 
152329881608SGustavo A. R. Silva 		/* extract the offline message length */
152412bdcf33SDavid Howells 	case 4:
152512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1526372ee163SDavid Howells 		if (ret < 0)
1527372ee163SDavid Howells 			return ret;
152845222b9eSDavid Howells 
152945222b9eSDavid Howells 		call->count = ntohl(call->tmp);
153045222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
153145222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1532160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1533160cb957SDavid Howells 						  afs_eproto_offline_msg_len);
153412bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1535ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
153645222b9eSDavid Howells 		call->unmarshall++;
153729881608SGustavo A. R. Silva 		/* Fall through */
153845222b9eSDavid Howells 
153929881608SGustavo A. R. Silva 		/* extract the offline message */
154012bdcf33SDavid Howells 	case 5:
154145222b9eSDavid Howells 		_debug("extract offline");
154212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1543372ee163SDavid Howells 		if (ret < 0)
1544372ee163SDavid Howells 			return ret;
154545222b9eSDavid Howells 
1546ffba718eSDavid Howells 		p = call->buffer;
154745222b9eSDavid Howells 		p[call->count] = 0;
154845222b9eSDavid Howells 		_debug("offline '%s'", p);
154945222b9eSDavid Howells 
155012bdcf33SDavid Howells 		afs_extract_to_tmp(call);
155145222b9eSDavid Howells 		call->unmarshall++;
155229881608SGustavo A. R. Silva 		/* Fall through */
155345222b9eSDavid Howells 
155429881608SGustavo A. R. Silva 		/* extract the message of the day length */
155512bdcf33SDavid Howells 	case 6:
155612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1557372ee163SDavid Howells 		if (ret < 0)
1558372ee163SDavid Howells 			return ret;
155945222b9eSDavid Howells 
156045222b9eSDavid Howells 		call->count = ntohl(call->tmp);
156145222b9eSDavid Howells 		_debug("motd length: %u", call->count);
156245222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1563160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1564160cb957SDavid Howells 						  afs_eproto_motd_len);
156512bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1566ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
156745222b9eSDavid Howells 		call->unmarshall++;
156829881608SGustavo A. R. Silva 		/* Fall through */
156945222b9eSDavid Howells 
157029881608SGustavo A. R. Silva 		/* extract the message of the day */
157112bdcf33SDavid Howells 	case 7:
157245222b9eSDavid Howells 		_debug("extract motd");
157312bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1574372ee163SDavid Howells 		if (ret < 0)
1575372ee163SDavid Howells 			return ret;
157645222b9eSDavid Howells 
1577ffba718eSDavid Howells 		p = call->buffer;
157845222b9eSDavid Howells 		p[call->count] = 0;
157945222b9eSDavid Howells 		_debug("motd '%s'", p);
158045222b9eSDavid Howells 
158145222b9eSDavid Howells 		call->unmarshall++;
158245222b9eSDavid Howells 
158312bdcf33SDavid Howells 	case 8:
158445222b9eSDavid Howells 		break;
158545222b9eSDavid Howells 	}
158645222b9eSDavid Howells 
158745222b9eSDavid Howells 	_leave(" = 0 [done]");
158845222b9eSDavid Howells 	return 0;
158945222b9eSDavid Howells }
159045222b9eSDavid Howells 
159145222b9eSDavid Howells /*
159245222b9eSDavid Howells  * FS.GetVolumeStatus operation type
159345222b9eSDavid Howells  */
159445222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
159545222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1596025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
159745222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1598ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
159945222b9eSDavid Howells };
160045222b9eSDavid Howells 
160145222b9eSDavid Howells /*
160245222b9eSDavid Howells  * fetch the status of a volume
160345222b9eSDavid Howells  */
16048b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
1605d2ddc776SDavid Howells 			     struct afs_volume_status *vs)
160645222b9eSDavid Howells {
1607d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
160845222b9eSDavid Howells 	struct afs_call *call;
1609f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
161045222b9eSDavid Howells 	__be32 *bp;
161145222b9eSDavid Howells 
161230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
161330062bd1SDavid Howells 		return yfs_fs_get_volume_status(fc, vs);
161430062bd1SDavid Howells 
161545222b9eSDavid Howells 	_enter("");
161645222b9eSDavid Howells 
1617ffba718eSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4,
1618ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1619ffba718eSDavid Howells 	if (!call)
162045222b9eSDavid Howells 		return -ENOMEM;
162145222b9eSDavid Howells 
1622d2ddc776SDavid Howells 	call->key = fc->key;
1623ffba718eSDavid Howells 	call->out_volstatus = vs;
162445222b9eSDavid Howells 
162545222b9eSDavid Howells 	/* marshall the parameters */
162645222b9eSDavid Howells 	bp = call->request;
162745222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
162845222b9eSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
162945222b9eSDavid Howells 
1630d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1631025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
163220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
16330b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
16340b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
163545222b9eSDavid Howells }
1636e8d6c554SDavid Howells 
1637e8d6c554SDavid Howells /*
1638e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1639e8d6c554SDavid Howells  */
1640d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1641e8d6c554SDavid Howells {
1642e8d6c554SDavid Howells 	const __be32 *bp;
1643372ee163SDavid Howells 	int ret;
1644e8d6c554SDavid Howells 
1645d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1646e8d6c554SDavid Howells 
1647d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1648372ee163SDavid Howells 	if (ret < 0)
1649372ee163SDavid Howells 		return ret;
1650e8d6c554SDavid Howells 
1651e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1652e8d6c554SDavid Howells 	bp = call->buffer;
1653ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
1654e8d6c554SDavid Howells 
1655e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1656e8d6c554SDavid Howells 	return 0;
1657e8d6c554SDavid Howells }
1658e8d6c554SDavid Howells 
1659e8d6c554SDavid Howells /*
1660e8d6c554SDavid Howells  * FS.SetLock operation type
1661e8d6c554SDavid Howells  */
1662e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1663e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1664025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1665e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1666a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1667e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1668e8d6c554SDavid Howells };
1669e8d6c554SDavid Howells 
1670e8d6c554SDavid Howells /*
1671e8d6c554SDavid Howells  * FS.ExtendLock operation type
1672e8d6c554SDavid Howells  */
1673e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1674e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1675025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1676e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1677a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1678e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1679e8d6c554SDavid Howells };
1680e8d6c554SDavid Howells 
1681e8d6c554SDavid Howells /*
1682e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1683e8d6c554SDavid Howells  */
1684e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1685e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1686025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1687e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1688e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1689e8d6c554SDavid Howells };
1690e8d6c554SDavid Howells 
1691e8d6c554SDavid Howells /*
1692d2ddc776SDavid Howells  * Set a lock on a file
1693e8d6c554SDavid Howells  */
1694a58823acSDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
1695a58823acSDavid Howells 		    struct afs_status_cb *scb)
1696e8d6c554SDavid Howells {
1697d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1698e8d6c554SDavid Howells 	struct afs_call *call;
1699f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1700e8d6c554SDavid Howells 	__be32 *bp;
1701e8d6c554SDavid Howells 
170230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1703a58823acSDavid Howells 		return yfs_fs_set_lock(fc, type, scb);
170430062bd1SDavid Howells 
1705e8d6c554SDavid Howells 	_enter("");
1706e8d6c554SDavid Howells 
1707f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1708e8d6c554SDavid Howells 	if (!call)
1709e8d6c554SDavid Howells 		return -ENOMEM;
1710e8d6c554SDavid Howells 
1711d2ddc776SDavid Howells 	call->key = fc->key;
1712a58823acSDavid Howells 	call->lvnode = vnode;
1713a58823acSDavid Howells 	call->out_scb = scb;
1714e8d6c554SDavid Howells 
1715e8d6c554SDavid Howells 	/* marshall the parameters */
1716e8d6c554SDavid Howells 	bp = call->request;
1717e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1718e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1719e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1720e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1721e8d6c554SDavid Howells 	*bp++ = htonl(type);
1722e8d6c554SDavid Howells 
1723d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
17246c6c1d63SDavid Howells 	trace_afs_make_fs_calli(call, &vnode->fid, type);
172520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17260b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17270b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1728e8d6c554SDavid Howells }
1729e8d6c554SDavid Howells 
1730e8d6c554SDavid Howells /*
1731e8d6c554SDavid Howells  * extend a lock on a file
1732e8d6c554SDavid Howells  */
1733a58823acSDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1734e8d6c554SDavid Howells {
1735d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1736e8d6c554SDavid Howells 	struct afs_call *call;
1737f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1738e8d6c554SDavid Howells 	__be32 *bp;
1739e8d6c554SDavid Howells 
174030062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1741a58823acSDavid Howells 		return yfs_fs_extend_lock(fc, scb);
174230062bd1SDavid Howells 
1743e8d6c554SDavid Howells 	_enter("");
1744e8d6c554SDavid Howells 
1745f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1746e8d6c554SDavid Howells 	if (!call)
1747e8d6c554SDavid Howells 		return -ENOMEM;
1748e8d6c554SDavid Howells 
1749d2ddc776SDavid Howells 	call->key = fc->key;
1750a58823acSDavid Howells 	call->lvnode = vnode;
1751a58823acSDavid Howells 	call->out_scb = scb;
1752e8d6c554SDavid Howells 
1753e8d6c554SDavid Howells 	/* marshall the parameters */
1754e8d6c554SDavid Howells 	bp = call->request;
1755e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1756e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1757e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1758e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1759e8d6c554SDavid Howells 
1760d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1761025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
176220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17630b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17640b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1765e8d6c554SDavid Howells }
1766e8d6c554SDavid Howells 
1767e8d6c554SDavid Howells /*
1768e8d6c554SDavid Howells  * release a lock on a file
1769e8d6c554SDavid Howells  */
1770a58823acSDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1771e8d6c554SDavid Howells {
1772d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1773e8d6c554SDavid Howells 	struct afs_call *call;
1774f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1775e8d6c554SDavid Howells 	__be32 *bp;
1776e8d6c554SDavid Howells 
177730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1778a58823acSDavid Howells 		return yfs_fs_release_lock(fc, scb);
177930062bd1SDavid Howells 
1780e8d6c554SDavid Howells 	_enter("");
1781e8d6c554SDavid Howells 
1782f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1783e8d6c554SDavid Howells 	if (!call)
1784e8d6c554SDavid Howells 		return -ENOMEM;
1785e8d6c554SDavid Howells 
1786d2ddc776SDavid Howells 	call->key = fc->key;
1787a58823acSDavid Howells 	call->lvnode = vnode;
1788a58823acSDavid Howells 	call->out_scb = scb;
1789e8d6c554SDavid Howells 
1790e8d6c554SDavid Howells 	/* marshall the parameters */
1791e8d6c554SDavid Howells 	bp = call->request;
1792e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1793e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1794e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1795e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1796e8d6c554SDavid Howells 
1797d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1798025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
179920b8391fSDavid Howells 	afs_set_fc_call(call, fc);
18000b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
18010b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1802c435ee34SDavid Howells }
1803c435ee34SDavid Howells 
1804c435ee34SDavid Howells /*
1805c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1806c435ee34SDavid Howells  */
1807c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1808c435ee34SDavid Howells {
1809c435ee34SDavid Howells 	return afs_transfer_reply(call);
1810c435ee34SDavid Howells }
1811c435ee34SDavid Howells 
1812c435ee34SDavid Howells /*
1813c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1814c435ee34SDavid Howells  */
1815c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1816c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1817025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1818c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1819c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1820c435ee34SDavid Howells };
1821c435ee34SDavid Howells 
1822c435ee34SDavid Howells /*
1823c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1824c435ee34SDavid Howells  */
1825d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1826d2ddc776SDavid Howells 				 struct afs_server *server,
18278b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1828d2ddc776SDavid Howells 				 struct key *key)
1829c435ee34SDavid Howells {
1830c435ee34SDavid Howells 	struct afs_call *call;
1831c435ee34SDavid Howells 	__be32 *bp;
1832c435ee34SDavid Howells 
1833c435ee34SDavid Howells 	_enter("");
1834c435ee34SDavid Howells 
1835d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1836c435ee34SDavid Howells 	if (!call)
1837c435ee34SDavid Howells 		return -ENOMEM;
1838c435ee34SDavid Howells 
1839c435ee34SDavid Howells 	call->key = key;
1840c435ee34SDavid Howells 
1841c435ee34SDavid Howells 	/* marshall the parameters */
1842c435ee34SDavid Howells 	bp = call->request;
1843c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1844c435ee34SDavid Howells 
1845c435ee34SDavid Howells 	/* Can't take a ref on server */
18460b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
18470b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1848d2ddc776SDavid Howells }
1849d2ddc776SDavid Howells 
1850d2ddc776SDavid Howells /*
1851d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1852d2ddc776SDavid Howells  */
1853d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1854d2ddc776SDavid Howells {
1855d2ddc776SDavid Howells 	u32 count;
1856d2ddc776SDavid Howells 	int ret;
1857d2ddc776SDavid Howells 
1858fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1859d2ddc776SDavid Howells 
1860d2ddc776SDavid Howells 	switch (call->unmarshall) {
1861d2ddc776SDavid Howells 	case 0:
186212bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1863d2ddc776SDavid Howells 		call->unmarshall++;
186429881608SGustavo A. R. Silva 		/* Fall through */
1865d2ddc776SDavid Howells 
186629881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1867d2ddc776SDavid Howells 	case 1:
186812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1869d2ddc776SDavid Howells 		if (ret < 0)
1870d2ddc776SDavid Howells 			return ret;
1871d2ddc776SDavid Howells 
1872d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1873d2ddc776SDavid Howells 
1874d2ddc776SDavid Howells 		call->count = count;
1875d2ddc776SDavid Howells 		call->count2 = count;
187623a28913SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
1877d2ddc776SDavid Howells 		call->unmarshall++;
187829881608SGustavo A. R. Silva 		/* Fall through */
1879d2ddc776SDavid Howells 
188029881608SGustavo A. R. Silva 		/* Extract capabilities words */
1881d2ddc776SDavid Howells 	case 2:
188212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1883d2ddc776SDavid Howells 		if (ret < 0)
1884d2ddc776SDavid Howells 			return ret;
1885d2ddc776SDavid Howells 
1886d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1887d2ddc776SDavid Howells 
1888d2ddc776SDavid Howells 		call->unmarshall++;
1889d2ddc776SDavid Howells 		break;
1890d2ddc776SDavid Howells 	}
1891d2ddc776SDavid Howells 
1892d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1893d2ddc776SDavid Howells 	return 0;
1894d2ddc776SDavid Howells }
1895d2ddc776SDavid Howells 
1896d2ddc776SDavid Howells /*
1897d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1898d2ddc776SDavid Howells  */
1899d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1900d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1901025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1902d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
19033bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1904ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1905d2ddc776SDavid Howells };
1906d2ddc776SDavid Howells 
1907d2ddc776SDavid Howells /*
1908d2ddc776SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This can
1909d2ddc776SDavid Howells  * return up to 196 words.
1910d2ddc776SDavid Howells  */
19110b9bf381SDavid Howells struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
1912d2ddc776SDavid Howells 					 struct afs_server *server,
1913d2ddc776SDavid Howells 					 struct afs_addr_cursor *ac,
19143bf0fb6fSDavid Howells 					 struct key *key,
19150b9bf381SDavid Howells 					 unsigned int server_index)
1916d2ddc776SDavid Howells {
1917d2ddc776SDavid Howells 	struct afs_call *call;
1918d2ddc776SDavid Howells 	__be32 *bp;
1919d2ddc776SDavid Howells 
1920d2ddc776SDavid Howells 	_enter("");
1921d2ddc776SDavid Howells 
1922d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1923d2ddc776SDavid Howells 	if (!call)
19240b9bf381SDavid Howells 		return ERR_PTR(-ENOMEM);
1925d2ddc776SDavid Howells 
1926d2ddc776SDavid Howells 	call->key = key;
192745218193SDavid Howells 	call->server = afs_get_server(server, afs_server_trace_get_caps);
1928ffba718eSDavid Howells 	call->server_index = server_index;
192930062bd1SDavid Howells 	call->upgrade = true;
19300b9bf381SDavid Howells 	call->async = true;
193194f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1932d2ddc776SDavid Howells 
1933d2ddc776SDavid Howells 	/* marshall the parameters */
1934d2ddc776SDavid Howells 	bp = call->request;
1935d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1936d2ddc776SDavid Howells 
1937d2ddc776SDavid Howells 	/* Can't take a ref on server */
1938025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
19390b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
19400b9bf381SDavid Howells 	return call;
1941e8d6c554SDavid Howells }
19425cf9dd55SDavid Howells 
19435cf9dd55SDavid Howells /*
19445cf9dd55SDavid Howells  * Deliver reply data to an FS.FetchStatus with no vnode.
19455cf9dd55SDavid Howells  */
19465cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
19475cf9dd55SDavid Howells {
19485cf9dd55SDavid Howells 	const __be32 *bp;
19495cf9dd55SDavid Howells 	int ret;
19505cf9dd55SDavid Howells 
19515cf9dd55SDavid Howells 	ret = afs_transfer_reply(call);
19525cf9dd55SDavid Howells 	if (ret < 0)
19535cf9dd55SDavid Howells 		return ret;
19545cf9dd55SDavid Howells 
19555cf9dd55SDavid Howells 	/* unmarshall the reply once we've received all of it */
19565cf9dd55SDavid Howells 	bp = call->buffer;
1957a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1958160cb957SDavid Howells 	if (ret < 0)
1959160cb957SDavid Howells 		return ret;
1960a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
1961a58823acSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
19625cf9dd55SDavid Howells 
19635cf9dd55SDavid Howells 	_leave(" = 0 [done]");
19645cf9dd55SDavid Howells 	return 0;
19655cf9dd55SDavid Howells }
19665cf9dd55SDavid Howells 
19675cf9dd55SDavid Howells /*
19685cf9dd55SDavid Howells  * FS.FetchStatus operation type
19695cf9dd55SDavid Howells  */
19705cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
19715cf9dd55SDavid Howells 	.name		= "FS.FetchStatus",
19725cf9dd55SDavid Howells 	.op		= afs_FS_FetchStatus,
19735cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
19745cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
19755cf9dd55SDavid Howells };
19765cf9dd55SDavid Howells 
19775cf9dd55SDavid Howells /*
19785cf9dd55SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
19795cf9dd55SDavid Howells  */
19805cf9dd55SDavid Howells int afs_fs_fetch_status(struct afs_fs_cursor *fc,
19815cf9dd55SDavid Howells 			struct afs_net *net,
19825cf9dd55SDavid Howells 			struct afs_fid *fid,
1983a58823acSDavid Howells 			struct afs_status_cb *scb,
19845cf9dd55SDavid Howells 			struct afs_volsync *volsync)
19855cf9dd55SDavid Howells {
19865cf9dd55SDavid Howells 	struct afs_call *call;
19875cf9dd55SDavid Howells 	__be32 *bp;
19885cf9dd55SDavid Howells 
198930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1990a58823acSDavid Howells 		return yfs_fs_fetch_status(fc, net, fid, scb, volsync);
199130062bd1SDavid Howells 
19923b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
19935cf9dd55SDavid Howells 	       key_serial(fc->key), fid->vid, fid->vnode);
19945cf9dd55SDavid Howells 
19955cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
19965cf9dd55SDavid Howells 	if (!call) {
19975cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
19985cf9dd55SDavid Howells 		return -ENOMEM;
19995cf9dd55SDavid Howells 	}
20005cf9dd55SDavid Howells 
20015cf9dd55SDavid Howells 	call->key = fc->key;
2002ffba718eSDavid Howells 	call->out_fid = fid;
2003a58823acSDavid Howells 	call->out_scb = scb;
2004ffba718eSDavid Howells 	call->out_volsync = volsync;
20055cf9dd55SDavid Howells 
20065cf9dd55SDavid Howells 	/* marshall the parameters */
20075cf9dd55SDavid Howells 	bp = call->request;
20085cf9dd55SDavid Howells 	bp[0] = htonl(FSFETCHSTATUS);
20095cf9dd55SDavid Howells 	bp[1] = htonl(fid->vid);
20105cf9dd55SDavid Howells 	bp[2] = htonl(fid->vnode);
20115cf9dd55SDavid Howells 	bp[3] = htonl(fid->unique);
20125cf9dd55SDavid Howells 
20135cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
20145cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, fid);
201520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
20160b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
20170b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
20185cf9dd55SDavid Howells }
20195cf9dd55SDavid Howells 
20205cf9dd55SDavid Howells /*
20215cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
20225cf9dd55SDavid Howells  */
20235cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
20245cf9dd55SDavid Howells {
202587182759SDavid Howells 	struct afs_status_cb *scb;
20265cf9dd55SDavid Howells 	const __be32 *bp;
20275cf9dd55SDavid Howells 	u32 tmp;
20285cf9dd55SDavid Howells 	int ret;
20295cf9dd55SDavid Howells 
20305cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
20315cf9dd55SDavid Howells 
20325cf9dd55SDavid Howells 	switch (call->unmarshall) {
20335cf9dd55SDavid Howells 	case 0:
203412bdcf33SDavid Howells 		afs_extract_to_tmp(call);
20355cf9dd55SDavid Howells 		call->unmarshall++;
203629881608SGustavo A. R. Silva 		/* Fall through */
20375cf9dd55SDavid Howells 
20385cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
20395cf9dd55SDavid Howells 	case 1:
20405cf9dd55SDavid Howells 		_debug("extract status count");
204112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20425cf9dd55SDavid Howells 		if (ret < 0)
20435cf9dd55SDavid Howells 			return ret;
20445cf9dd55SDavid Howells 
20455cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20465cf9dd55SDavid Howells 		_debug("status count: %u/%u", tmp, call->count2);
20475cf9dd55SDavid Howells 		if (tmp != call->count2)
2048160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2049160cb957SDavid Howells 						  afs_eproto_ibulkst_count);
20505cf9dd55SDavid Howells 
20515cf9dd55SDavid Howells 		call->count = 0;
20525cf9dd55SDavid Howells 		call->unmarshall++;
20535cf9dd55SDavid Howells 	more_counts:
205412bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
2055e690c9e3SGustavo A. R. Silva 		/* Fall through */
205629881608SGustavo A. R. Silva 
20575cf9dd55SDavid Howells 	case 2:
20585cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
205912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20605cf9dd55SDavid Howells 		if (ret < 0)
20615cf9dd55SDavid Howells 			return ret;
20625cf9dd55SDavid Howells 
20635cf9dd55SDavid Howells 		bp = call->buffer;
206487182759SDavid Howells 		scb = &call->out_scb[call->count];
2065a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, scb);
2066160cb957SDavid Howells 		if (ret < 0)
2067160cb957SDavid Howells 			return ret;
20685cf9dd55SDavid Howells 
20695cf9dd55SDavid Howells 		call->count++;
20705cf9dd55SDavid Howells 		if (call->count < call->count2)
20715cf9dd55SDavid Howells 			goto more_counts;
20725cf9dd55SDavid Howells 
20735cf9dd55SDavid Howells 		call->count = 0;
20745cf9dd55SDavid Howells 		call->unmarshall++;
207512bdcf33SDavid Howells 		afs_extract_to_tmp(call);
207629881608SGustavo A. R. Silva 		/* Fall through */
20775cf9dd55SDavid Howells 
20785cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
20795cf9dd55SDavid Howells 	case 3:
20805cf9dd55SDavid Howells 		_debug("extract CB count");
208112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20825cf9dd55SDavid Howells 		if (ret < 0)
20835cf9dd55SDavid Howells 			return ret;
20845cf9dd55SDavid Howells 
20855cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20865cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
20875cf9dd55SDavid Howells 		if (tmp != call->count2)
2088160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2089160cb957SDavid Howells 						  afs_eproto_ibulkst_cb_count);
20905cf9dd55SDavid Howells 		call->count = 0;
20915cf9dd55SDavid Howells 		call->unmarshall++;
20925cf9dd55SDavid Howells 	more_cbs:
209312bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
2094e690c9e3SGustavo A. R. Silva 		/* Fall through */
209529881608SGustavo A. R. Silva 
20965cf9dd55SDavid Howells 	case 4:
20975cf9dd55SDavid Howells 		_debug("extract CB array");
209812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20995cf9dd55SDavid Howells 		if (ret < 0)
21005cf9dd55SDavid Howells 			return ret;
21015cf9dd55SDavid Howells 
21025cf9dd55SDavid Howells 		_debug("unmarshall CB array");
21035cf9dd55SDavid Howells 		bp = call->buffer;
210487182759SDavid Howells 		scb = &call->out_scb[call->count];
2105a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
21065cf9dd55SDavid Howells 		call->count++;
21075cf9dd55SDavid Howells 		if (call->count < call->count2)
21085cf9dd55SDavid Howells 			goto more_cbs;
21095cf9dd55SDavid Howells 
211012bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
21115cf9dd55SDavid Howells 		call->unmarshall++;
2112e690c9e3SGustavo A. R. Silva 		/* Fall through */
211329881608SGustavo A. R. Silva 
21145cf9dd55SDavid Howells 	case 5:
211512bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
21165cf9dd55SDavid Howells 		if (ret < 0)
21175cf9dd55SDavid Howells 			return ret;
21185cf9dd55SDavid Howells 
21195cf9dd55SDavid Howells 		bp = call->buffer;
2120ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
21215cf9dd55SDavid Howells 
21225cf9dd55SDavid Howells 		call->unmarshall++;
21235cf9dd55SDavid Howells 
21245cf9dd55SDavid Howells 	case 6:
21255cf9dd55SDavid Howells 		break;
21265cf9dd55SDavid Howells 	}
21275cf9dd55SDavid Howells 
21285cf9dd55SDavid Howells 	_leave(" = 0 [done]");
21295cf9dd55SDavid Howells 	return 0;
21305cf9dd55SDavid Howells }
21315cf9dd55SDavid Howells 
21325cf9dd55SDavid Howells /*
21335cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
21345cf9dd55SDavid Howells  */
21355cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
21365cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
21375cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
21385cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
21395cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
21405cf9dd55SDavid Howells };
21415cf9dd55SDavid Howells 
21425cf9dd55SDavid Howells /*
21435cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
21445cf9dd55SDavid Howells  */
21455cf9dd55SDavid Howells int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
21465cf9dd55SDavid Howells 			      struct afs_net *net,
21475cf9dd55SDavid Howells 			      struct afs_fid *fids,
214887182759SDavid Howells 			      struct afs_status_cb *statuses,
21495cf9dd55SDavid Howells 			      unsigned int nr_fids,
21505cf9dd55SDavid Howells 			      struct afs_volsync *volsync)
21515cf9dd55SDavid Howells {
21525cf9dd55SDavid Howells 	struct afs_call *call;
21535cf9dd55SDavid Howells 	__be32 *bp;
21545cf9dd55SDavid Howells 	int i;
21555cf9dd55SDavid Howells 
215630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
215787182759SDavid Howells 		return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
215830062bd1SDavid Howells 						 nr_fids, volsync);
215930062bd1SDavid Howells 
21603b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
21615cf9dd55SDavid Howells 	       key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
21625cf9dd55SDavid Howells 
21635cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
21645cf9dd55SDavid Howells 				   (2 + nr_fids * 3) * 4,
21655cf9dd55SDavid Howells 				   21 * 4);
21665cf9dd55SDavid Howells 	if (!call) {
21675cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
21685cf9dd55SDavid Howells 		return -ENOMEM;
21695cf9dd55SDavid Howells 	}
21705cf9dd55SDavid Howells 
21715cf9dd55SDavid Howells 	call->key = fc->key;
217287182759SDavid Howells 	call->out_scb = statuses;
2173ffba718eSDavid Howells 	call->out_volsync = volsync;
21745cf9dd55SDavid Howells 	call->count2 = nr_fids;
21755cf9dd55SDavid Howells 
21765cf9dd55SDavid Howells 	/* marshall the parameters */
21775cf9dd55SDavid Howells 	bp = call->request;
21785cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
21795cf9dd55SDavid Howells 	*bp++ = htonl(nr_fids);
21805cf9dd55SDavid Howells 	for (i = 0; i < nr_fids; i++) {
21815cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vid);
21825cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vnode);
21835cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].unique);
21845cf9dd55SDavid Howells 	}
21855cf9dd55SDavid Howells 
21865cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
21875cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, &fids[0]);
218820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
21890b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
21900b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
21915cf9dd55SDavid Howells }
2192260f082bSDavid Howells 
2193260f082bSDavid Howells /*
2194260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
2195260f082bSDavid Howells  */
2196260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
2197260f082bSDavid Howells {
2198260f082bSDavid Howells 	struct afs_acl *acl;
2199260f082bSDavid Howells 	const __be32 *bp;
2200260f082bSDavid Howells 	unsigned int size;
2201260f082bSDavid Howells 	int ret;
2202260f082bSDavid Howells 
2203260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
2204260f082bSDavid Howells 
2205260f082bSDavid Howells 	switch (call->unmarshall) {
2206260f082bSDavid Howells 	case 0:
2207260f082bSDavid Howells 		afs_extract_to_tmp(call);
2208260f082bSDavid Howells 		call->unmarshall++;
220929881608SGustavo A. R. Silva 		/* Fall through */
2210260f082bSDavid Howells 
2211260f082bSDavid Howells 		/* extract the returned data length */
2212260f082bSDavid Howells 	case 1:
2213260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2214260f082bSDavid Howells 		if (ret < 0)
2215260f082bSDavid Howells 			return ret;
2216260f082bSDavid Howells 
2217260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
2218260f082bSDavid Howells 		size = round_up(size, 4);
2219260f082bSDavid Howells 
2220260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
2221260f082bSDavid Howells 		if (!acl)
2222260f082bSDavid Howells 			return -ENOMEM;
2223ffba718eSDavid Howells 		call->ret_acl = acl;
2224260f082bSDavid Howells 		acl->size = call->count2;
2225260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
2226260f082bSDavid Howells 		call->unmarshall++;
222729881608SGustavo A. R. Silva 		/* Fall through */
2228260f082bSDavid Howells 
2229260f082bSDavid Howells 		/* extract the returned data */
2230260f082bSDavid Howells 	case 2:
2231260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2232260f082bSDavid Howells 		if (ret < 0)
2233260f082bSDavid Howells 			return ret;
2234260f082bSDavid Howells 
2235260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
2236260f082bSDavid Howells 		call->unmarshall++;
223729881608SGustavo A. R. Silva 		/* Fall through */
2238260f082bSDavid Howells 
2239260f082bSDavid Howells 		/* extract the metadata */
2240260f082bSDavid Howells 	case 3:
2241260f082bSDavid Howells 		ret = afs_extract_data(call, false);
2242260f082bSDavid Howells 		if (ret < 0)
2243260f082bSDavid Howells 			return ret;
2244260f082bSDavid Howells 
2245260f082bSDavid Howells 		bp = call->buffer;
2246a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2247260f082bSDavid Howells 		if (ret < 0)
2248260f082bSDavid Howells 			return ret;
2249ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
2250260f082bSDavid Howells 
2251260f082bSDavid Howells 		call->unmarshall++;
2252260f082bSDavid Howells 
2253260f082bSDavid Howells 	case 4:
2254260f082bSDavid Howells 		break;
2255260f082bSDavid Howells 	}
2256260f082bSDavid Howells 
2257260f082bSDavid Howells 	_leave(" = 0 [done]");
2258260f082bSDavid Howells 	return 0;
2259260f082bSDavid Howells }
2260260f082bSDavid Howells 
2261260f082bSDavid Howells static void afs_destroy_fs_fetch_acl(struct afs_call *call)
2262260f082bSDavid Howells {
2263ffba718eSDavid Howells 	kfree(call->ret_acl);
2264260f082bSDavid Howells 	afs_flat_call_destructor(call);
2265260f082bSDavid Howells }
2266260f082bSDavid Howells 
2267260f082bSDavid Howells /*
2268260f082bSDavid Howells  * FS.FetchACL operation type
2269260f082bSDavid Howells  */
2270260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2271260f082bSDavid Howells 	.name		= "FS.FetchACL",
2272260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2273260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2274260f082bSDavid Howells 	.destructor	= afs_destroy_fs_fetch_acl,
2275260f082bSDavid Howells };
2276260f082bSDavid Howells 
2277260f082bSDavid Howells /*
2278260f082bSDavid Howells  * Fetch the ACL for a file.
2279260f082bSDavid Howells  */
2280a58823acSDavid Howells struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc,
2281a58823acSDavid Howells 				 struct afs_status_cb *scb)
2282260f082bSDavid Howells {
2283260f082bSDavid Howells 	struct afs_vnode *vnode = fc->vnode;
2284260f082bSDavid Howells 	struct afs_call *call;
2285260f082bSDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2286260f082bSDavid Howells 	__be32 *bp;
2287260f082bSDavid Howells 
2288260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2289260f082bSDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2290260f082bSDavid Howells 
2291260f082bSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2292260f082bSDavid Howells 	if (!call) {
2293260f082bSDavid Howells 		fc->ac.error = -ENOMEM;
2294260f082bSDavid Howells 		return ERR_PTR(-ENOMEM);
2295260f082bSDavid Howells 	}
2296260f082bSDavid Howells 
2297260f082bSDavid Howells 	call->key = fc->key;
2298ffba718eSDavid Howells 	call->ret_acl = NULL;
2299a58823acSDavid Howells 	call->out_scb = scb;
2300ffba718eSDavid Howells 	call->out_volsync = NULL;
2301260f082bSDavid Howells 
2302260f082bSDavid Howells 	/* marshall the parameters */
2303260f082bSDavid Howells 	bp = call->request;
2304260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2305260f082bSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
2306260f082bSDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
2307260f082bSDavid Howells 	bp[3] = htonl(vnode->fid.unique);
2308260f082bSDavid Howells 
2309260f082bSDavid Howells 	afs_use_fs_server(call, fc->cbi);
2310260f082bSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
2311260f082bSDavid Howells 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2312260f082bSDavid Howells 	return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
2313260f082bSDavid Howells }
2314b10494afSJoe Gorse 
2315b10494afSJoe Gorse /*
2316ffba718eSDavid Howells  * Deliver reply data to any operation that returns file status and volume
2317ffba718eSDavid Howells  * sync.
2318ffba718eSDavid Howells  */
2319ffba718eSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
2320ffba718eSDavid Howells {
2321ffba718eSDavid Howells 	const __be32 *bp;
2322ffba718eSDavid Howells 	int ret;
2323ffba718eSDavid Howells 
2324ffba718eSDavid Howells 	ret = afs_transfer_reply(call);
2325ffba718eSDavid Howells 	if (ret < 0)
2326ffba718eSDavid Howells 		return ret;
2327ffba718eSDavid Howells 
2328ffba718eSDavid Howells 	bp = call->buffer;
2329a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2330ffba718eSDavid Howells 	if (ret < 0)
2331ffba718eSDavid Howells 		return ret;
2332ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2333ffba718eSDavid Howells 
2334ffba718eSDavid Howells 	_leave(" = 0 [done]");
2335ffba718eSDavid Howells 	return 0;
2336ffba718eSDavid Howells }
2337ffba718eSDavid Howells 
2338ffba718eSDavid Howells /*
2339b10494afSJoe Gorse  * FS.StoreACL operation type
2340b10494afSJoe Gorse  */
2341b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2342b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2343b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2344ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2345b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2346b10494afSJoe Gorse };
2347b10494afSJoe Gorse 
2348b10494afSJoe Gorse /*
2349b10494afSJoe Gorse  * Fetch the ACL for a file.
2350b10494afSJoe Gorse  */
2351a58823acSDavid Howells int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl,
2352a58823acSDavid Howells 		     struct afs_status_cb *scb)
2353b10494afSJoe Gorse {
2354b10494afSJoe Gorse 	struct afs_vnode *vnode = fc->vnode;
2355b10494afSJoe Gorse 	struct afs_call *call;
2356b10494afSJoe Gorse 	struct afs_net *net = afs_v2net(vnode);
2357b10494afSJoe Gorse 	size_t size;
2358b10494afSJoe Gorse 	__be32 *bp;
2359b10494afSJoe Gorse 
2360b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2361b10494afSJoe Gorse 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2362b10494afSJoe Gorse 
2363b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2364b10494afSJoe Gorse 	call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
2365b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2366b10494afSJoe Gorse 	if (!call) {
2367b10494afSJoe Gorse 		fc->ac.error = -ENOMEM;
2368b10494afSJoe Gorse 		return -ENOMEM;
2369b10494afSJoe Gorse 	}
2370b10494afSJoe Gorse 
2371b10494afSJoe Gorse 	call->key = fc->key;
2372a58823acSDavid Howells 	call->out_scb = scb;
2373ffba718eSDavid Howells 	call->out_volsync = NULL;
2374b10494afSJoe Gorse 
2375b10494afSJoe Gorse 	/* marshall the parameters */
2376b10494afSJoe Gorse 	bp = call->request;
2377b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2378b10494afSJoe Gorse 	bp[1] = htonl(vnode->fid.vid);
2379b10494afSJoe Gorse 	bp[2] = htonl(vnode->fid.vnode);
2380b10494afSJoe Gorse 	bp[3] = htonl(vnode->fid.unique);
2381b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2382b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2383b10494afSJoe Gorse 	if (acl->size != size)
2384b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2385b10494afSJoe Gorse 
2386b10494afSJoe Gorse 	trace_afs_make_fs_call(call, &vnode->fid);
2387b10494afSJoe Gorse 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2388b10494afSJoe Gorse 	return afs_wait_for_call_to_complete(call, &fc->ac);
23891da177e4SLinus Torvalds }
2390