xref: /openbmc/linux/fs/afs/fsclient.c (revision 2874c5fd)
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 
18025db80cSDavid Howells static const struct afs_fid afs_zero_fid;
19025db80cSDavid Howells 
20d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
21c435ee34SDavid Howells {
22d2ddc776SDavid Howells 	call->cbi = afs_get_cb_interest(cbi);
23c435ee34SDavid Howells }
24c435ee34SDavid Howells 
256db3ac3cSDavid Howells /*
26260a9803SDavid Howells  * decode an AFSFid block
27260a9803SDavid Howells  */
28260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
29260a9803SDavid Howells {
30260a9803SDavid Howells 	const __be32 *bp = *_bp;
31260a9803SDavid Howells 
32260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
33260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
34260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
35260a9803SDavid Howells 	*_bp = bp;
36260a9803SDavid Howells }
37260a9803SDavid Howells 
38260a9803SDavid Howells /*
39888b3384SDavid Howells  * Dump a bad file status record.
40888b3384SDavid Howells  */
41888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
42888b3384SDavid Howells {
43888b3384SDavid Howells 	__be32 x[4];
44888b3384SDavid Howells 	int i;
45888b3384SDavid Howells 
46888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
47888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
48888b3384SDavid Howells 		memcpy(x, bp, 16);
49888b3384SDavid Howells 		bp += 4;
50888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
51888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
52888b3384SDavid Howells 	}
53888b3384SDavid Howells 
54888b3384SDavid Howells 	memcpy(x, bp, 4);
55888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
56888b3384SDavid Howells }
57888b3384SDavid Howells 
58888b3384SDavid Howells /*
59dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
60dd9fbcb8SDavid Howells  */
61a58823acSDavid Howells static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
62a58823acSDavid Howells 				     struct afs_call *call,
63a58823acSDavid Howells 				     struct afs_status_cb *scb)
64dd9fbcb8SDavid Howells {
65dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
66a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
67684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
68dd9fbcb8SDavid Howells 	u64 data_version, size;
69dd9fbcb8SDavid Howells 	u32 type, abort_code;
70dd9fbcb8SDavid Howells 
71684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
72684b0f68SDavid Howells 
73dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
74684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
75684b0f68SDavid Howells 		    abort_code != 0 &&
76684b0f68SDavid Howells 		    inline_error) {
77684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
78684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
79684b0f68SDavid Howells 			 * case.
80684b0f68SDavid Howells 			 */
81684b0f68SDavid Howells 			status->abort_code = abort_code;
82a38a7558SDavid Howells 			scb->have_error = true;
83de52cf92SAl Viro 			return 0;
84684b0f68SDavid Howells 		}
85684b0f68SDavid Howells 
86dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
87dd9fbcb8SDavid Howells 		goto bad;
88dd9fbcb8SDavid Howells 	}
89dd9fbcb8SDavid Howells 
90684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
91684b0f68SDavid Howells 		status->abort_code = abort_code;
92de52cf92SAl Viro 		return 0;
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;
128dd9fbcb8SDavid Howells 
129dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
130c875c76aSDavid Howells 	return 0;
131dd9fbcb8SDavid Howells 
132dd9fbcb8SDavid Howells bad:
133dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
134160cb957SDavid Howells 	return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
135c875c76aSDavid Howells }
136c875c76aSDavid Howells 
13778107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
13878107055SDavid Howells {
13978107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
14078107055SDavid Howells }
14178107055SDavid Howells 
142a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
143a58823acSDavid Howells 				   struct afs_call *call,
144a58823acSDavid Howells 				   struct afs_status_cb *scb)
14578107055SDavid Howells {
146a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
14778107055SDavid Howells 	const __be32 *bp = *_bp;
14878107055SDavid Howells 
1497c712458SDavid Howells 	bp++; /* version */
15078107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1517c712458SDavid Howells 	bp++; /* type */
152a58823acSDavid Howells 	scb->have_cb	= true;
15378107055SDavid Howells 	*_bp = bp;
15478107055SDavid Howells }
15578107055SDavid Howells 
1561da177e4SLinus Torvalds /*
15708e0e7c8SDavid Howells  * decode an AFSVolSync block
1581da177e4SLinus Torvalds  */
15908e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
16008e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1611da177e4SLinus Torvalds {
16208e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
16330062bd1SDavid Howells 	u32 creation;
1641da177e4SLinus Torvalds 
16530062bd1SDavid Howells 	creation = ntohl(*bp++);
16608e0e7c8SDavid Howells 	bp++; /* spare2 */
16708e0e7c8SDavid Howells 	bp++; /* spare3 */
16808e0e7c8SDavid Howells 	bp++; /* spare4 */
16908e0e7c8SDavid Howells 	bp++; /* spare5 */
17008e0e7c8SDavid Howells 	bp++; /* spare6 */
17108e0e7c8SDavid Howells 	*_bp = bp;
17230062bd1SDavid Howells 
17330062bd1SDavid Howells 	if (volsync)
17430062bd1SDavid Howells 		volsync->creation = creation;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
17708e0e7c8SDavid Howells /*
17831143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
17931143d5dSDavid Howells  */
18031143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
18131143d5dSDavid Howells {
18231143d5dSDavid Howells 	__be32 *bp = *_bp;
18331143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
18431143d5dSDavid Howells 
18531143d5dSDavid Howells 	mask = 0;
18631143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18731143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
18831143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
18931143d5dSDavid Howells 	}
19031143d5dSDavid Howells 
19131143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
19231143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
193a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
19431143d5dSDavid Howells 	}
19531143d5dSDavid Howells 
19631143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19731143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
198a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
19931143d5dSDavid Howells 	}
20031143d5dSDavid Howells 
20131143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
20231143d5dSDavid Howells 		mask |= AFS_SET_MODE;
20331143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
20431143d5dSDavid Howells 	}
20531143d5dSDavid Howells 
20631143d5dSDavid Howells 	*bp++ = htonl(mask);
20731143d5dSDavid Howells 	*bp++ = htonl(mtime);
20831143d5dSDavid Howells 	*bp++ = htonl(owner);
20931143d5dSDavid Howells 	*bp++ = htonl(group);
21031143d5dSDavid Howells 	*bp++ = htonl(mode);
21131143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
21231143d5dSDavid Howells 	*_bp = bp;
21331143d5dSDavid Howells }
21431143d5dSDavid Howells 
21531143d5dSDavid Howells /*
21645222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21745222b9eSDavid Howells  */
21845222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
21945222b9eSDavid Howells 					    struct afs_volume_status *vs)
22045222b9eSDavid Howells {
22145222b9eSDavid Howells 	const __be32 *bp = *_bp;
22245222b9eSDavid Howells 
22345222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
22445222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22545222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
23045222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
23145222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
23245222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
23345222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
23445222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23530062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23630062bd1SDavid Howells 	vs->vol_backup_date	= 0;
23745222b9eSDavid Howells 	*_bp = bp;
23845222b9eSDavid Howells }
23945222b9eSDavid Howells 
24045222b9eSDavid Howells /*
24108e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
24208e0e7c8SDavid Howells  */
2435cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
24408e0e7c8SDavid Howells {
24508e0e7c8SDavid Howells 	const __be32 *bp;
246372ee163SDavid Howells 	int ret;
2471da177e4SLinus Torvalds 
248d001648eSDavid Howells 	ret = afs_transfer_reply(call);
249372ee163SDavid Howells 	if (ret < 0)
250372ee163SDavid Howells 		return ret;
2511da177e4SLinus Torvalds 
25208e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25308e0e7c8SDavid Howells 	bp = call->buffer;
254a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
255160cb957SDavid Howells 	if (ret < 0)
256160cb957SDavid Howells 		return ret;
257a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
258ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2591da177e4SLinus Torvalds 
26008e0e7c8SDavid Howells 	_leave(" = 0 [done]");
26108e0e7c8SDavid Howells 	return 0;
262ec26815aSDavid Howells }
26308e0e7c8SDavid Howells 
26408e0e7c8SDavid Howells /*
26508e0e7c8SDavid Howells  * FS.FetchStatus operation type
26608e0e7c8SDavid Howells  */
2675cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
2685cf9dd55SDavid Howells 	.name		= "FS.FetchStatus(vnode)",
269025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
2705cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status_vnode,
27108e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
27208e0e7c8SDavid Howells };
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds /*
2751da177e4SLinus Torvalds  * fetch the status information for a file
2761da177e4SLinus Torvalds  */
277a58823acSDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
278a58823acSDavid Howells 			     struct afs_volsync *volsync)
2791da177e4SLinus Torvalds {
280d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
28108e0e7c8SDavid Howells 	struct afs_call *call;
282f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2831da177e4SLinus Torvalds 	__be32 *bp;
2841da177e4SLinus Torvalds 
28530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
286a58823acSDavid Howells 		return yfs_fs_fetch_file_status(fc, scb, volsync);
28730062bd1SDavid Howells 
2883b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
289d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2901da177e4SLinus Torvalds 
2915cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
2925cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
293d2ddc776SDavid Howells 	if (!call) {
294d2ddc776SDavid Howells 		fc->ac.error = -ENOMEM;
29508e0e7c8SDavid Howells 		return -ENOMEM;
296d2ddc776SDavid Howells 	}
2971da177e4SLinus Torvalds 
298d2ddc776SDavid Howells 	call->key = fc->key;
299a58823acSDavid Howells 	call->out_scb = scb;
300ffba718eSDavid Howells 	call->out_volsync = volsync;
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 	/* marshall the parameters */
30308e0e7c8SDavid Howells 	bp = call->request;
3041da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
3051da177e4SLinus Torvalds 	bp[1] = htonl(vnode->fid.vid);
3061da177e4SLinus Torvalds 	bp[2] = htonl(vnode->fid.vnode);
3071da177e4SLinus Torvalds 	bp[3] = htonl(vnode->fid.unique);
3081da177e4SLinus Torvalds 
309d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
310025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
3110b9bf381SDavid Howells 
31220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
3130b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
3140b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
315ec26815aSDavid Howells }
3161da177e4SLinus Torvalds 
3171da177e4SLinus Torvalds /*
31808e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
3191da177e4SLinus Torvalds  */
320d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3211da177e4SLinus Torvalds {
322ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
32308e0e7c8SDavid Howells 	const __be32 *bp;
324196ee9cdSDavid Howells 	unsigned int size;
3251da177e4SLinus Torvalds 	int ret;
3261da177e4SLinus Torvalds 
32712bdcf33SDavid Howells 	_enter("{%u,%zu/%llu}",
32812bdcf33SDavid Howells 	       call->unmarshall, iov_iter_count(&call->iter), req->actual_len);
3291da177e4SLinus Torvalds 
33008e0e7c8SDavid Howells 	switch (call->unmarshall) {
33108e0e7c8SDavid Howells 	case 0:
332196ee9cdSDavid Howells 		req->actual_len = 0;
33312bdcf33SDavid Howells 		req->index = 0;
33412bdcf33SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
33508e0e7c8SDavid Howells 		call->unmarshall++;
33612bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
33712bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
33812bdcf33SDavid Howells 		} else {
33912bdcf33SDavid Howells 			call->tmp_u = htonl(0);
34012bdcf33SDavid Howells 			afs_extract_to_tmp(call);
341b9b1f8d5SDavid Howells 		}
3421da177e4SLinus Torvalds 
343e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the returned data length */
34412bdcf33SDavid Howells 	case 1:
34508e0e7c8SDavid Howells 		_debug("extract data length");
34612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
347372ee163SDavid Howells 		if (ret < 0)
348372ee163SDavid Howells 			return ret;
3491da177e4SLinus Torvalds 
35012bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
351196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
35212bdcf33SDavid Howells 		req->remain = min(req->len, req->actual_len);
35312bdcf33SDavid Howells 		if (req->remain == 0)
354196ee9cdSDavid Howells 			goto no_more_data;
35512bdcf33SDavid Howells 
35608e0e7c8SDavid Howells 		call->unmarshall++;
3571da177e4SLinus Torvalds 
358196ee9cdSDavid Howells 	begin_page:
3596db3ac3cSDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
36012bdcf33SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
36112bdcf33SDavid Howells 			size = PAGE_SIZE - req->offset;
362196ee9cdSDavid Howells 		else
363196ee9cdSDavid Howells 			size = req->remain;
36412bdcf33SDavid Howells 		call->bvec[0].bv_len = size;
36512bdcf33SDavid Howells 		call->bvec[0].bv_offset = req->offset;
36612bdcf33SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
36712bdcf33SDavid Howells 		iov_iter_bvec(&call->iter, READ, call->bvec, 1, size);
36812bdcf33SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
369196ee9cdSDavid Howells 
370e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the returned data */
37112bdcf33SDavid Howells 	case 2:
37212bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
37312bdcf33SDavid Howells 		       iov_iter_count(&call->iter), req->remain);
374196ee9cdSDavid Howells 
37512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
376372ee163SDavid Howells 		if (ret < 0)
377372ee163SDavid Howells 			return ret;
37812bdcf33SDavid Howells 		req->remain -= call->bvec[0].bv_len;
37912bdcf33SDavid Howells 		req->offset += call->bvec[0].bv_len;
38012bdcf33SDavid Howells 		ASSERTCMP(req->offset, <=, PAGE_SIZE);
38112bdcf33SDavid Howells 		if (req->offset == PAGE_SIZE) {
38212bdcf33SDavid Howells 			req->offset = 0;
383196ee9cdSDavid Howells 			if (req->page_done)
384a58823acSDavid Howells 				req->page_done(req);
38529f06985SDavid Howells 			req->index++;
38612bdcf33SDavid Howells 			if (req->remain > 0)
387196ee9cdSDavid Howells 				goto begin_page;
388196ee9cdSDavid Howells 		}
38912bdcf33SDavid Howells 
39012bdcf33SDavid Howells 		ASSERTCMP(req->remain, ==, 0);
39112bdcf33SDavid Howells 		if (req->actual_len <= req->len)
3926db3ac3cSDavid Howells 			goto no_more_data;
3936db3ac3cSDavid Howells 
3946db3ac3cSDavid Howells 		/* Discard any excess data the server gave us */
39512bdcf33SDavid Howells 		iov_iter_discard(&call->iter, READ, req->actual_len - req->len);
39612bdcf33SDavid Howells 		call->unmarshall = 3;
397e690c9e3SGustavo A. R. Silva 
398e690c9e3SGustavo A. R. Silva 		/* Fall through */
39912bdcf33SDavid Howells 	case 3:
40012bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
40112bdcf33SDavid Howells 		       iov_iter_count(&call->iter), req->actual_len - req->len);
4026db3ac3cSDavid Howells 
40312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
4046db3ac3cSDavid Howells 		if (ret < 0)
4056db3ac3cSDavid Howells 			return ret;
4061da177e4SLinus Torvalds 
407196ee9cdSDavid Howells 	no_more_data:
40812bdcf33SDavid Howells 		call->unmarshall = 4;
40912bdcf33SDavid Howells 		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
41008e0e7c8SDavid Howells 
411e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the metadata */
41212bdcf33SDavid Howells 	case 4:
41312bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
414372ee163SDavid Howells 		if (ret < 0)
415372ee163SDavid Howells 			return ret;
4161da177e4SLinus Torvalds 
41708e0e7c8SDavid Howells 		bp = call->buffer;
418a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
419160cb957SDavid Howells 		if (ret < 0)
420160cb957SDavid Howells 			return ret;
421a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, call->out_scb);
422ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
4231da177e4SLinus Torvalds 
424a58823acSDavid Howells 		req->data_version = call->out_scb->status.data_version;
425a58823acSDavid Howells 		req->file_size = call->out_scb->status.size;
426a58823acSDavid Howells 
42708e0e7c8SDavid Howells 		call->unmarshall++;
4281da177e4SLinus Torvalds 
42912bdcf33SDavid Howells 	case 5:
4301da177e4SLinus Torvalds 		break;
4311da177e4SLinus Torvalds 	}
4321da177e4SLinus Torvalds 
4336db3ac3cSDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
43412bdcf33SDavid Howells 		if (req->offset < PAGE_SIZE)
4356db3ac3cSDavid Howells 			zero_user_segment(req->pages[req->index],
43612bdcf33SDavid Howells 					  req->offset, PAGE_SIZE);
437196ee9cdSDavid Howells 		if (req->page_done)
438a58823acSDavid Howells 			req->page_done(req);
43912bdcf33SDavid Howells 		req->offset = 0;
440416351f2SDavid Howells 	}
441416351f2SDavid Howells 
44208e0e7c8SDavid Howells 	_leave(" = 0 [done]");
44308e0e7c8SDavid Howells 	return 0;
444ec26815aSDavid Howells }
4451da177e4SLinus Torvalds 
446196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call)
447196ee9cdSDavid Howells {
448ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
449196ee9cdSDavid Howells 
450196ee9cdSDavid Howells 	afs_put_read(req);
451196ee9cdSDavid Howells 	afs_flat_call_destructor(call);
452196ee9cdSDavid Howells }
453196ee9cdSDavid Howells 
4541da177e4SLinus Torvalds /*
45508e0e7c8SDavid Howells  * FS.FetchData operation type
4561da177e4SLinus Torvalds  */
45708e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
45800d3b7a4SDavid Howells 	.name		= "FS.FetchData",
459025db80cSDavid Howells 	.op		= afs_FS_FetchData,
46008e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
461196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
46208e0e7c8SDavid Howells };
46308e0e7c8SDavid Howells 
464b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
465b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
466025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
467b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
468196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
469b9b1f8d5SDavid Howells };
470b9b1f8d5SDavid Howells 
471b9b1f8d5SDavid Howells /*
472b9b1f8d5SDavid Howells  * fetch data from a very large file
473b9b1f8d5SDavid Howells  */
474a58823acSDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc,
475a58823acSDavid Howells 			       struct afs_status_cb *scb,
476a58823acSDavid Howells 			       struct afs_read *req)
477b9b1f8d5SDavid Howells {
478d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
479b9b1f8d5SDavid Howells 	struct afs_call *call;
480f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
481b9b1f8d5SDavid Howells 	__be32 *bp;
482b9b1f8d5SDavid Howells 
483b9b1f8d5SDavid Howells 	_enter("");
484b9b1f8d5SDavid Howells 
485f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
486b9b1f8d5SDavid Howells 	if (!call)
487b9b1f8d5SDavid Howells 		return -ENOMEM;
488b9b1f8d5SDavid Howells 
489d2ddc776SDavid Howells 	call->key = fc->key;
490a58823acSDavid Howells 	call->out_scb = scb;
491ffba718eSDavid Howells 	call->out_volsync = NULL;
492ffba718eSDavid Howells 	call->read_request = req;
493b9b1f8d5SDavid Howells 
494b9b1f8d5SDavid Howells 	/* marshall the parameters */
495b9b1f8d5SDavid Howells 	bp = call->request;
496b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
497b9b1f8d5SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
498b9b1f8d5SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
499b9b1f8d5SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
500196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
501196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
502b9b1f8d5SDavid Howells 	bp[6] = 0;
503196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
504b9b1f8d5SDavid Howells 
505f3ddee8dSDavid Howells 	refcount_inc(&req->usage);
506d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
507025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
50820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5090b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5100b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
511b9b1f8d5SDavid Howells }
512b9b1f8d5SDavid Howells 
51308e0e7c8SDavid Howells /*
51408e0e7c8SDavid Howells  * fetch data from a file
51508e0e7c8SDavid Howells  */
516a58823acSDavid Howells int afs_fs_fetch_data(struct afs_fs_cursor *fc,
517a58823acSDavid Howells 		      struct afs_status_cb *scb,
518a58823acSDavid Howells 		      struct afs_read *req)
5191da177e4SLinus Torvalds {
520d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
52108e0e7c8SDavid Howells 	struct afs_call *call;
522f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
52308e0e7c8SDavid Howells 	__be32 *bp;
5241da177e4SLinus Torvalds 
52530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
526a58823acSDavid Howells 		return yfs_fs_fetch_data(fc, scb, req);
52730062bd1SDavid Howells 
528196ee9cdSDavid Howells 	if (upper_32_bits(req->pos) ||
529196ee9cdSDavid Howells 	    upper_32_bits(req->len) ||
530196ee9cdSDavid Howells 	    upper_32_bits(req->pos + req->len))
531a58823acSDavid Howells 		return afs_fs_fetch_data64(fc, scb, req);
532b9b1f8d5SDavid Howells 
53308e0e7c8SDavid Howells 	_enter("");
5341da177e4SLinus Torvalds 
535f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
53608e0e7c8SDavid Howells 	if (!call)
53708e0e7c8SDavid Howells 		return -ENOMEM;
5381da177e4SLinus Torvalds 
539d2ddc776SDavid Howells 	call->key = fc->key;
540a58823acSDavid Howells 	call->out_scb = scb;
541ffba718eSDavid Howells 	call->out_volsync = NULL;
542ffba718eSDavid Howells 	call->read_request = req;
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 	/* marshall the parameters */
54508e0e7c8SDavid Howells 	bp = call->request;
54608e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
54708e0e7c8SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
54808e0e7c8SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
54908e0e7c8SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
550196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
551196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
5521da177e4SLinus Torvalds 
553f3ddee8dSDavid Howells 	refcount_inc(&req->usage);
554d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
555025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
55620b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5570b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5580b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
55908e0e7c8SDavid Howells }
560260a9803SDavid Howells 
561260a9803SDavid Howells /*
562260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
563260a9803SDavid Howells  */
564d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
565260a9803SDavid Howells {
566260a9803SDavid Howells 	const __be32 *bp;
567372ee163SDavid Howells 	int ret;
568260a9803SDavid Howells 
569d001648eSDavid Howells 	ret = afs_transfer_reply(call);
570372ee163SDavid Howells 	if (ret < 0)
571372ee163SDavid Howells 		return ret;
572260a9803SDavid Howells 
573260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
574260a9803SDavid Howells 	bp = call->buffer;
575ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
576a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
577160cb957SDavid Howells 	if (ret < 0)
578160cb957SDavid Howells 		return ret;
579a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
580160cb957SDavid Howells 	if (ret < 0)
581160cb957SDavid Howells 		return ret;
582a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
583ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
584260a9803SDavid Howells 
585260a9803SDavid Howells 	_leave(" = 0 [done]");
586260a9803SDavid Howells 	return 0;
587260a9803SDavid Howells }
588260a9803SDavid Howells 
589260a9803SDavid Howells /*
590260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
591260a9803SDavid Howells  */
592025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
593025db80cSDavid Howells 	.name		= "FS.CreateFile",
594025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
595025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
596025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
597025db80cSDavid Howells };
598025db80cSDavid Howells 
599025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
600025db80cSDavid Howells 	.name		= "FS.MakeDir",
601025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
602260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
603260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
604260a9803SDavid Howells };
605260a9803SDavid Howells 
606260a9803SDavid Howells /*
607260a9803SDavid Howells  * create a file or make a directory
608260a9803SDavid Howells  */
6098b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc,
610260a9803SDavid Howells 		  const char *name,
611260a9803SDavid Howells 		  umode_t mode,
612a58823acSDavid Howells 		  struct afs_status_cb *dvnode_scb,
613260a9803SDavid Howells 		  struct afs_fid *newfid,
614a58823acSDavid Howells 		  struct afs_status_cb *new_scb)
615260a9803SDavid Howells {
616ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
617260a9803SDavid Howells 	struct afs_call *call;
618ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
619260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
620260a9803SDavid Howells 	__be32 *bp;
621260a9803SDavid Howells 
62230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){
62330062bd1SDavid Howells 		if (S_ISDIR(mode))
624a58823acSDavid Howells 			return yfs_fs_make_dir(fc, name, mode, dvnode_scb,
625a58823acSDavid Howells 					       newfid, new_scb);
62630062bd1SDavid Howells 		else
627a58823acSDavid Howells 			return yfs_fs_create_file(fc, name, mode, dvnode_scb,
628a58823acSDavid Howells 						  newfid, new_scb);
62930062bd1SDavid Howells 	}
63030062bd1SDavid Howells 
631260a9803SDavid Howells 	_enter("");
632260a9803SDavid Howells 
633260a9803SDavid Howells 	namesz = strlen(name);
634260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
635260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
636260a9803SDavid Howells 
637025db80cSDavid Howells 	call = afs_alloc_flat_call(
638025db80cSDavid Howells 		net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
639025db80cSDavid Howells 		reqsz, (3 + 21 + 21 + 3 + 6) * 4);
640260a9803SDavid Howells 	if (!call)
641260a9803SDavid Howells 		return -ENOMEM;
642260a9803SDavid Howells 
643d2ddc776SDavid Howells 	call->key = fc->key;
644a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
645ffba718eSDavid Howells 	call->out_fid = newfid;
646a58823acSDavid Howells 	call->out_scb = new_scb;
647260a9803SDavid Howells 
648260a9803SDavid Howells 	/* marshall the parameters */
649260a9803SDavid Howells 	bp = call->request;
650260a9803SDavid Howells 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
651ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
652ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
653ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
654260a9803SDavid Howells 	*bp++ = htonl(namesz);
655260a9803SDavid Howells 	memcpy(bp, name, namesz);
656260a9803SDavid Howells 	bp = (void *) bp + namesz;
657260a9803SDavid Howells 	if (padsz > 0) {
658260a9803SDavid Howells 		memset(bp, 0, padsz);
659260a9803SDavid Howells 		bp = (void *) bp + padsz;
660260a9803SDavid Howells 	}
661ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
662ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
663260a9803SDavid Howells 	*bp++ = 0; /* owner */
664260a9803SDavid Howells 	*bp++ = 0; /* group */
665260a9803SDavid Howells 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
666260a9803SDavid Howells 	*bp++ = 0; /* segment size */
667260a9803SDavid Howells 
668d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
669ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
67020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
6710b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
6720b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
673260a9803SDavid Howells }
674260a9803SDavid Howells 
675260a9803SDavid Howells /*
676ffba718eSDavid Howells  * Deliver reply data to any operation that returns directory status and volume
677b10494afSJoe Gorse  * sync.
678260a9803SDavid Howells  */
679ffba718eSDavid Howells static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call)
680260a9803SDavid Howells {
681260a9803SDavid Howells 	const __be32 *bp;
682372ee163SDavid Howells 	int ret;
683260a9803SDavid Howells 
684d001648eSDavid Howells 	ret = afs_transfer_reply(call);
685372ee163SDavid Howells 	if (ret < 0)
686372ee163SDavid Howells 		return ret;
687260a9803SDavid Howells 
688260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
689260a9803SDavid Howells 	bp = call->buffer;
690a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
691160cb957SDavid Howells 	if (ret < 0)
692160cb957SDavid Howells 		return ret;
693ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
694260a9803SDavid Howells 
695260a9803SDavid Howells 	_leave(" = 0 [done]");
696260a9803SDavid Howells 	return 0;
697260a9803SDavid Howells }
698260a9803SDavid Howells 
699260a9803SDavid Howells /*
700260a9803SDavid Howells  * FS.RemoveDir/FS.RemoveFile operation type
701260a9803SDavid Howells  */
702025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
703025db80cSDavid Howells 	.name		= "FS.RemoveFile",
704025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
705ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
706025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
707025db80cSDavid Howells };
708025db80cSDavid Howells 
709025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
710025db80cSDavid Howells 	.name		= "FS.RemoveDir",
711025db80cSDavid Howells 	.op		= afs_FS_RemoveDir,
712ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
713260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
714260a9803SDavid Howells };
715260a9803SDavid Howells 
716260a9803SDavid Howells /*
717260a9803SDavid Howells  * remove a file or directory
718260a9803SDavid Howells  */
71930062bd1SDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
720a58823acSDavid Howells 		  const char *name, bool isdir, struct afs_status_cb *dvnode_scb)
721260a9803SDavid Howells {
72230062bd1SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
723260a9803SDavid Howells 	struct afs_call *call;
72430062bd1SDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
725260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
726260a9803SDavid Howells 	__be32 *bp;
727260a9803SDavid Howells 
72830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
729a58823acSDavid Howells 		return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb);
73030062bd1SDavid Howells 
731260a9803SDavid Howells 	_enter("");
732260a9803SDavid Howells 
733260a9803SDavid Howells 	namesz = strlen(name);
734260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
735260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
736260a9803SDavid Howells 
737025db80cSDavid Howells 	call = afs_alloc_flat_call(
738025db80cSDavid Howells 		net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
739025db80cSDavid Howells 		reqsz, (21 + 6) * 4);
740260a9803SDavid Howells 	if (!call)
741260a9803SDavid Howells 		return -ENOMEM;
742260a9803SDavid Howells 
743d2ddc776SDavid Howells 	call->key = fc->key;
744a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
745260a9803SDavid Howells 
746260a9803SDavid Howells 	/* marshall the parameters */
747260a9803SDavid Howells 	bp = call->request;
748260a9803SDavid Howells 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
74930062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
75030062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
75130062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
752260a9803SDavid Howells 	*bp++ = htonl(namesz);
753260a9803SDavid Howells 	memcpy(bp, name, namesz);
754260a9803SDavid Howells 	bp = (void *) bp + namesz;
755260a9803SDavid Howells 	if (padsz > 0) {
756260a9803SDavid Howells 		memset(bp, 0, padsz);
757260a9803SDavid Howells 		bp = (void *) bp + padsz;
758260a9803SDavid Howells 	}
759260a9803SDavid Howells 
760d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
76180548b03SDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
76220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
7630b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
7640b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
765260a9803SDavid Howells }
766260a9803SDavid Howells 
767260a9803SDavid Howells /*
768260a9803SDavid Howells  * deliver reply data to an FS.Link
769260a9803SDavid Howells  */
770d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
771260a9803SDavid Howells {
772260a9803SDavid Howells 	const __be32 *bp;
773372ee163SDavid Howells 	int ret;
774260a9803SDavid Howells 
775d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
776260a9803SDavid Howells 
777d001648eSDavid Howells 	ret = afs_transfer_reply(call);
778372ee163SDavid Howells 	if (ret < 0)
779372ee163SDavid Howells 		return ret;
780260a9803SDavid Howells 
781260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
782260a9803SDavid Howells 	bp = call->buffer;
783a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
784160cb957SDavid Howells 	if (ret < 0)
785160cb957SDavid Howells 		return ret;
786a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
787160cb957SDavid Howells 	if (ret < 0)
788160cb957SDavid Howells 		return ret;
789ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
790260a9803SDavid Howells 
791260a9803SDavid Howells 	_leave(" = 0 [done]");
792260a9803SDavid Howells 	return 0;
793260a9803SDavid Howells }
794260a9803SDavid Howells 
795260a9803SDavid Howells /*
796260a9803SDavid Howells  * FS.Link operation type
797260a9803SDavid Howells  */
798260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
799260a9803SDavid Howells 	.name		= "FS.Link",
800025db80cSDavid Howells 	.op		= afs_FS_Link,
801260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
802260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
803260a9803SDavid Howells };
804260a9803SDavid Howells 
805260a9803SDavid Howells /*
806260a9803SDavid Howells  * make a hard link
807260a9803SDavid Howells  */
808d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
809a58823acSDavid Howells 		const char *name,
810a58823acSDavid Howells 		struct afs_status_cb *dvnode_scb,
811a58823acSDavid Howells 		struct afs_status_cb *vnode_scb)
812260a9803SDavid Howells {
813d2ddc776SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
814260a9803SDavid Howells 	struct afs_call *call;
815f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
816260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
817260a9803SDavid Howells 	__be32 *bp;
818260a9803SDavid Howells 
81930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
820a58823acSDavid Howells 		return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb);
82130062bd1SDavid Howells 
822260a9803SDavid Howells 	_enter("");
823260a9803SDavid Howells 
824260a9803SDavid Howells 	namesz = strlen(name);
825260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
826260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
827260a9803SDavid Howells 
828f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
829260a9803SDavid Howells 	if (!call)
830260a9803SDavid Howells 		return -ENOMEM;
831260a9803SDavid Howells 
832d2ddc776SDavid Howells 	call->key = fc->key;
833a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
834a58823acSDavid Howells 	call->out_scb = vnode_scb;
835260a9803SDavid Howells 
836260a9803SDavid Howells 	/* marshall the parameters */
837260a9803SDavid Howells 	bp = call->request;
838260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
839260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
840260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
841260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
842260a9803SDavid Howells 	*bp++ = htonl(namesz);
843260a9803SDavid Howells 	memcpy(bp, name, namesz);
844260a9803SDavid Howells 	bp = (void *) bp + namesz;
845260a9803SDavid Howells 	if (padsz > 0) {
846260a9803SDavid Howells 		memset(bp, 0, padsz);
847260a9803SDavid Howells 		bp = (void *) bp + padsz;
848260a9803SDavid Howells 	}
849260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
850260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
851260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
852260a9803SDavid Howells 
853d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
85480548b03SDavid Howells 	trace_afs_make_fs_call1(call, &vnode->fid, name);
85520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
8560b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
8570b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
858260a9803SDavid Howells }
859260a9803SDavid Howells 
860260a9803SDavid Howells /*
861260a9803SDavid Howells  * deliver reply data to an FS.Symlink
862260a9803SDavid Howells  */
863d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
864260a9803SDavid Howells {
865260a9803SDavid Howells 	const __be32 *bp;
866372ee163SDavid Howells 	int ret;
867260a9803SDavid Howells 
868d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
869260a9803SDavid Howells 
870d001648eSDavid Howells 	ret = afs_transfer_reply(call);
871372ee163SDavid Howells 	if (ret < 0)
872372ee163SDavid Howells 		return ret;
873260a9803SDavid Howells 
874260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
875260a9803SDavid Howells 	bp = call->buffer;
876ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
877a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
878160cb957SDavid Howells 	if (ret < 0)
879160cb957SDavid Howells 		return ret;
880a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
881160cb957SDavid Howells 	if (ret < 0)
882160cb957SDavid Howells 		return ret;
883ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
884260a9803SDavid Howells 
885260a9803SDavid Howells 	_leave(" = 0 [done]");
886260a9803SDavid Howells 	return 0;
887260a9803SDavid Howells }
888260a9803SDavid Howells 
889260a9803SDavid Howells /*
890260a9803SDavid Howells  * FS.Symlink operation type
891260a9803SDavid Howells  */
892260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
893260a9803SDavid Howells 	.name		= "FS.Symlink",
894025db80cSDavid Howells 	.op		= afs_FS_Symlink,
895260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
896260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
897260a9803SDavid Howells };
898260a9803SDavid Howells 
899260a9803SDavid Howells /*
900260a9803SDavid Howells  * create a symbolic link
901260a9803SDavid Howells  */
9028b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc,
903260a9803SDavid Howells 		   const char *name,
904260a9803SDavid Howells 		   const char *contents,
905a58823acSDavid Howells 		   struct afs_status_cb *dvnode_scb,
906260a9803SDavid Howells 		   struct afs_fid *newfid,
907a58823acSDavid Howells 		   struct afs_status_cb *new_scb)
908260a9803SDavid Howells {
909ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
910260a9803SDavid Howells 	struct afs_call *call;
911ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
912260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
913260a9803SDavid Howells 	__be32 *bp;
914260a9803SDavid Howells 
91530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
916a58823acSDavid Howells 		return yfs_fs_symlink(fc, name, contents, dvnode_scb,
917a58823acSDavid Howells 				      newfid, new_scb);
91830062bd1SDavid Howells 
919260a9803SDavid Howells 	_enter("");
920260a9803SDavid Howells 
921260a9803SDavid Howells 	namesz = strlen(name);
922260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
923260a9803SDavid Howells 
924260a9803SDavid Howells 	c_namesz = strlen(contents);
925260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
926260a9803SDavid Howells 
927260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
928260a9803SDavid Howells 
929f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
930260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
931260a9803SDavid Howells 	if (!call)
932260a9803SDavid Howells 		return -ENOMEM;
933260a9803SDavid Howells 
934d2ddc776SDavid Howells 	call->key = fc->key;
935a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
936ffba718eSDavid Howells 	call->out_fid = newfid;
937a58823acSDavid Howells 	call->out_scb = new_scb;
938260a9803SDavid Howells 
939260a9803SDavid Howells 	/* marshall the parameters */
940260a9803SDavid Howells 	bp = call->request;
941260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
942ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
943ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
944ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
945260a9803SDavid Howells 	*bp++ = htonl(namesz);
946260a9803SDavid Howells 	memcpy(bp, name, namesz);
947260a9803SDavid Howells 	bp = (void *) bp + namesz;
948260a9803SDavid Howells 	if (padsz > 0) {
949260a9803SDavid Howells 		memset(bp, 0, padsz);
950260a9803SDavid Howells 		bp = (void *) bp + padsz;
951260a9803SDavid Howells 	}
952260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
953260a9803SDavid Howells 	memcpy(bp, contents, c_namesz);
954260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
955260a9803SDavid Howells 	if (c_padsz > 0) {
956260a9803SDavid Howells 		memset(bp, 0, c_padsz);
957260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
958260a9803SDavid Howells 	}
959ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
960ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
961260a9803SDavid Howells 	*bp++ = 0; /* owner */
962260a9803SDavid Howells 	*bp++ = 0; /* group */
963260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
964260a9803SDavid Howells 	*bp++ = 0; /* segment size */
965260a9803SDavid Howells 
966d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
967ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
96820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
9690b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
9700b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
971260a9803SDavid Howells }
972260a9803SDavid Howells 
973260a9803SDavid Howells /*
974260a9803SDavid Howells  * deliver reply data to an FS.Rename
975260a9803SDavid Howells  */
976d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
977260a9803SDavid Howells {
978260a9803SDavid Howells 	const __be32 *bp;
979372ee163SDavid Howells 	int ret;
980260a9803SDavid Howells 
981d001648eSDavid Howells 	ret = afs_transfer_reply(call);
982372ee163SDavid Howells 	if (ret < 0)
983372ee163SDavid Howells 		return ret;
984260a9803SDavid Howells 
985260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
986260a9803SDavid Howells 	bp = call->buffer;
987a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
988160cb957SDavid Howells 	if (ret < 0)
989160cb957SDavid Howells 		return ret;
990a58823acSDavid Howells 	if (call->out_dir_scb != call->out_scb) {
991a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
992160cb957SDavid Howells 		if (ret < 0)
993160cb957SDavid Howells 			return ret;
994160cb957SDavid Howells 	}
995ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
996260a9803SDavid Howells 
997260a9803SDavid Howells 	_leave(" = 0 [done]");
998260a9803SDavid Howells 	return 0;
999260a9803SDavid Howells }
1000260a9803SDavid Howells 
1001260a9803SDavid Howells /*
1002260a9803SDavid Howells  * FS.Rename operation type
1003260a9803SDavid Howells  */
1004260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
1005260a9803SDavid Howells 	.name		= "FS.Rename",
1006025db80cSDavid Howells 	.op		= afs_FS_Rename,
1007260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
1008260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
1009260a9803SDavid Howells };
1010260a9803SDavid Howells 
1011260a9803SDavid Howells /*
1012a58823acSDavid Howells  * Rename/move a file or directory.
1013260a9803SDavid Howells  */
10148b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc,
1015260a9803SDavid Howells 		  const char *orig_name,
1016260a9803SDavid Howells 		  struct afs_vnode *new_dvnode,
101763a4681fSDavid Howells 		  const char *new_name,
1018a58823acSDavid Howells 		  struct afs_status_cb *orig_dvnode_scb,
1019a58823acSDavid Howells 		  struct afs_status_cb *new_dvnode_scb)
1020260a9803SDavid Howells {
1021d2ddc776SDavid Howells 	struct afs_vnode *orig_dvnode = fc->vnode;
1022260a9803SDavid Howells 	struct afs_call *call;
1023f044c884SDavid Howells 	struct afs_net *net = afs_v2net(orig_dvnode);
1024260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1025260a9803SDavid Howells 	__be32 *bp;
1026260a9803SDavid Howells 
102730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
102830062bd1SDavid Howells 		return yfs_fs_rename(fc, orig_name,
102930062bd1SDavid Howells 				     new_dvnode, new_name,
1030a58823acSDavid Howells 				     orig_dvnode_scb,
1031a58823acSDavid Howells 				     new_dvnode_scb);
103230062bd1SDavid Howells 
1033260a9803SDavid Howells 	_enter("");
1034260a9803SDavid Howells 
1035260a9803SDavid Howells 	o_namesz = strlen(orig_name);
1036260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
1037260a9803SDavid Howells 
1038260a9803SDavid Howells 	n_namesz = strlen(new_name);
1039260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
1040260a9803SDavid Howells 
1041260a9803SDavid Howells 	reqsz = (4 * 4) +
1042260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1043260a9803SDavid Howells 		(3 * 4) +
1044260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1045260a9803SDavid Howells 
1046f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1047260a9803SDavid Howells 	if (!call)
1048260a9803SDavid Howells 		return -ENOMEM;
1049260a9803SDavid Howells 
1050d2ddc776SDavid Howells 	call->key = fc->key;
1051a58823acSDavid Howells 	call->out_dir_scb = orig_dvnode_scb;
1052a58823acSDavid Howells 	call->out_scb = new_dvnode_scb;
1053260a9803SDavid Howells 
1054260a9803SDavid Howells 	/* marshall the parameters */
1055260a9803SDavid Howells 	bp = call->request;
1056260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1057260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vid);
1058260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vnode);
1059260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.unique);
1060260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1061260a9803SDavid Howells 	memcpy(bp, orig_name, o_namesz);
1062260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1063260a9803SDavid Howells 	if (o_padsz > 0) {
1064260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1065260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1066260a9803SDavid Howells 	}
1067260a9803SDavid Howells 
1068260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vid);
1069260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vnode);
1070260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.unique);
1071260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1072260a9803SDavid Howells 	memcpy(bp, new_name, n_namesz);
1073260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1074260a9803SDavid Howells 	if (n_padsz > 0) {
1075260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1076260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1077260a9803SDavid Howells 	}
1078260a9803SDavid Howells 
1079d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
108080548b03SDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
108120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
10820b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
10830b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1084260a9803SDavid Howells }
108531143d5dSDavid Howells 
108631143d5dSDavid Howells /*
108731143d5dSDavid Howells  * deliver reply data to an FS.StoreData
108831143d5dSDavid Howells  */
1089d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
109031143d5dSDavid Howells {
109131143d5dSDavid Howells 	const __be32 *bp;
1092372ee163SDavid Howells 	int ret;
109331143d5dSDavid Howells 
1094d001648eSDavid Howells 	_enter("");
109531143d5dSDavid Howells 
1096d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1097372ee163SDavid Howells 	if (ret < 0)
1098372ee163SDavid Howells 		return ret;
109931143d5dSDavid Howells 
110031143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
110131143d5dSDavid Howells 	bp = call->buffer;
1102a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1103160cb957SDavid Howells 	if (ret < 0)
1104160cb957SDavid Howells 		return ret;
1105ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
110631143d5dSDavid Howells 
110731143d5dSDavid Howells 	_leave(" = 0 [done]");
110831143d5dSDavid Howells 	return 0;
110931143d5dSDavid Howells }
111031143d5dSDavid Howells 
111131143d5dSDavid Howells /*
111231143d5dSDavid Howells  * FS.StoreData operation type
111331143d5dSDavid Howells  */
111431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
111531143d5dSDavid Howells 	.name		= "FS.StoreData",
1116025db80cSDavid Howells 	.op		= afs_FS_StoreData,
111731143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
111831143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
111931143d5dSDavid Howells };
112031143d5dSDavid Howells 
1121b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1122b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1123025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1124b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1125b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1126b9b1f8d5SDavid Howells };
1127b9b1f8d5SDavid Howells 
1128b9b1f8d5SDavid Howells /*
1129b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1130b9b1f8d5SDavid Howells  */
11318b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc,
11324343d008SDavid Howells 			       struct address_space *mapping,
1133b9b1f8d5SDavid Howells 			       pgoff_t first, pgoff_t last,
1134b9b1f8d5SDavid Howells 			       unsigned offset, unsigned to,
1135a58823acSDavid Howells 			       loff_t size, loff_t pos, loff_t i_size,
1136a58823acSDavid Howells 			       struct afs_status_cb *scb)
1137b9b1f8d5SDavid Howells {
11384343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1139b9b1f8d5SDavid Howells 	struct afs_call *call;
1140f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1141b9b1f8d5SDavid Howells 	__be32 *bp;
1142b9b1f8d5SDavid Howells 
11433b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
11444343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1145b9b1f8d5SDavid Howells 
1146f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
1147b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1148b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1149b9b1f8d5SDavid Howells 	if (!call)
1150b9b1f8d5SDavid Howells 		return -ENOMEM;
1151b9b1f8d5SDavid Howells 
11524343d008SDavid Howells 	call->key = fc->key;
11534343d008SDavid Howells 	call->mapping = mapping;
1154b9b1f8d5SDavid Howells 	call->first = first;
1155b9b1f8d5SDavid Howells 	call->last = last;
1156b9b1f8d5SDavid Howells 	call->first_offset = offset;
1157b9b1f8d5SDavid Howells 	call->last_to = to;
1158b9b1f8d5SDavid Howells 	call->send_pages = true;
1159a58823acSDavid Howells 	call->out_scb = scb;
1160b9b1f8d5SDavid Howells 
1161b9b1f8d5SDavid Howells 	/* marshall the parameters */
1162b9b1f8d5SDavid Howells 	bp = call->request;
1163b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1164b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1165b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1166b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1167b9b1f8d5SDavid Howells 
1168ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1169ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1170b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1171b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1172b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1173b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1174b9b1f8d5SDavid Howells 
1175b9b1f8d5SDavid Howells 	*bp++ = htonl(pos >> 32);
1176b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) pos);
1177b9b1f8d5SDavid Howells 	*bp++ = htonl(size >> 32);
1178b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) size);
1179b9b1f8d5SDavid Howells 	*bp++ = htonl(i_size >> 32);
1180b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) i_size);
1181b9b1f8d5SDavid Howells 
1182025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
118320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
11840b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
11850b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1186b9b1f8d5SDavid Howells }
1187b9b1f8d5SDavid Howells 
118831143d5dSDavid Howells /*
118931143d5dSDavid Howells  * store a set of pages
119031143d5dSDavid Howells  */
11914343d008SDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
119231143d5dSDavid Howells 		      pgoff_t first, pgoff_t last,
1193a58823acSDavid Howells 		      unsigned offset, unsigned to,
1194a58823acSDavid Howells 		      struct afs_status_cb *scb)
119531143d5dSDavid Howells {
11964343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
119731143d5dSDavid Howells 	struct afs_call *call;
1198f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
119931143d5dSDavid Howells 	loff_t size, pos, i_size;
120031143d5dSDavid Howells 	__be32 *bp;
120131143d5dSDavid Howells 
120230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1203a58823acSDavid Howells 		return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb);
120430062bd1SDavid Howells 
12053b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
12064343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
120731143d5dSDavid Howells 
1208146a1192SDavid Howells 	size = (loff_t)to - (loff_t)offset;
120931143d5dSDavid Howells 	if (first != last)
121031143d5dSDavid Howells 		size += (loff_t)(last - first) << PAGE_SHIFT;
121131143d5dSDavid Howells 	pos = (loff_t)first << PAGE_SHIFT;
121231143d5dSDavid Howells 	pos += offset;
121331143d5dSDavid Howells 
121431143d5dSDavid Howells 	i_size = i_size_read(&vnode->vfs_inode);
121531143d5dSDavid Howells 	if (pos + size > i_size)
121631143d5dSDavid Howells 		i_size = size + pos;
121731143d5dSDavid Howells 
121831143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
121931143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
122031143d5dSDavid Howells 	       (unsigned long long) i_size);
122131143d5dSDavid Howells 
1222b9b1f8d5SDavid Howells 	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
12234343d008SDavid Howells 		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
1224a58823acSDavid Howells 					   size, pos, i_size, scb);
122531143d5dSDavid Howells 
1226f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
122731143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
122831143d5dSDavid Howells 				   (21 + 6) * 4);
122931143d5dSDavid Howells 	if (!call)
123031143d5dSDavid Howells 		return -ENOMEM;
123131143d5dSDavid Howells 
12324343d008SDavid Howells 	call->key = fc->key;
12334343d008SDavid Howells 	call->mapping = mapping;
123431143d5dSDavid Howells 	call->first = first;
123531143d5dSDavid Howells 	call->last = last;
123631143d5dSDavid Howells 	call->first_offset = offset;
123731143d5dSDavid Howells 	call->last_to = to;
123831143d5dSDavid Howells 	call->send_pages = true;
1239a58823acSDavid Howells 	call->out_scb = scb;
124031143d5dSDavid Howells 
124131143d5dSDavid Howells 	/* marshall the parameters */
124231143d5dSDavid Howells 	bp = call->request;
124331143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
124431143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
124531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
124631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
124731143d5dSDavid Howells 
1248ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1249ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
125031143d5dSDavid Howells 	*bp++ = 0; /* owner */
125131143d5dSDavid Howells 	*bp++ = 0; /* group */
125231143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
125331143d5dSDavid Howells 	*bp++ = 0; /* segment size */
125431143d5dSDavid Howells 
125531143d5dSDavid Howells 	*bp++ = htonl(pos);
125631143d5dSDavid Howells 	*bp++ = htonl(size);
125731143d5dSDavid Howells 	*bp++ = htonl(i_size);
125831143d5dSDavid Howells 
1259d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1260025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
126120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
12620b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
12630b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
126431143d5dSDavid Howells }
126531143d5dSDavid Howells 
126631143d5dSDavid Howells /*
126731143d5dSDavid Howells  * deliver reply data to an FS.StoreStatus
126831143d5dSDavid Howells  */
1269d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call)
127031143d5dSDavid Howells {
127131143d5dSDavid Howells 	const __be32 *bp;
1272372ee163SDavid Howells 	int ret;
127331143d5dSDavid Howells 
1274d001648eSDavid Howells 	_enter("");
127531143d5dSDavid Howells 
1276d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1277372ee163SDavid Howells 	if (ret < 0)
1278372ee163SDavid Howells 		return ret;
127931143d5dSDavid Howells 
128031143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
128131143d5dSDavid Howells 	bp = call->buffer;
1282a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1283160cb957SDavid Howells 	if (ret < 0)
1284160cb957SDavid Howells 		return ret;
1285ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
128631143d5dSDavid Howells 
128731143d5dSDavid Howells 	_leave(" = 0 [done]");
128831143d5dSDavid Howells 	return 0;
128931143d5dSDavid Howells }
129031143d5dSDavid Howells 
129131143d5dSDavid Howells /*
129231143d5dSDavid Howells  * FS.StoreStatus operation type
129331143d5dSDavid Howells  */
129431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
129531143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1296025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
129731143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
129831143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
129931143d5dSDavid Howells };
130031143d5dSDavid Howells 
130131143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
130231143d5dSDavid Howells 	.name		= "FS.StoreData",
1303025db80cSDavid Howells 	.op		= afs_FS_StoreData,
130431143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130531143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
130631143d5dSDavid Howells };
130731143d5dSDavid Howells 
1308b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1309b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1310025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1311b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_status,
1312b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1313b9b1f8d5SDavid Howells };
1314b9b1f8d5SDavid Howells 
1315b9b1f8d5SDavid Howells /*
1316b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1317b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1318b9b1f8d5SDavid Howells  */
1319a58823acSDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr,
1320a58823acSDavid Howells 				 struct afs_status_cb *scb)
1321b9b1f8d5SDavid Howells {
1322d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1323b9b1f8d5SDavid Howells 	struct afs_call *call;
1324f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1325b9b1f8d5SDavid Howells 	__be32 *bp;
1326b9b1f8d5SDavid Howells 
13273b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1328d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1329b9b1f8d5SDavid Howells 
1330b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1331b9b1f8d5SDavid Howells 
1332f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
1333b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1334b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1335b9b1f8d5SDavid Howells 	if (!call)
1336b9b1f8d5SDavid Howells 		return -ENOMEM;
1337b9b1f8d5SDavid Howells 
1338d2ddc776SDavid Howells 	call->key = fc->key;
1339a58823acSDavid Howells 	call->out_scb = scb;
1340b9b1f8d5SDavid Howells 
1341b9b1f8d5SDavid Howells 	/* marshall the parameters */
1342b9b1f8d5SDavid Howells 	bp = call->request;
1343b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1344b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1345b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1346b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1347b9b1f8d5SDavid Howells 
1348b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1349b9b1f8d5SDavid Howells 
13508c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* position of start of write */
13518c7ae38dSDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1352b9b1f8d5SDavid Howells 	*bp++ = 0;				/* size of write */
1353b9b1f8d5SDavid Howells 	*bp++ = 0;
1354b9b1f8d5SDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
1355b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1356b9b1f8d5SDavid Howells 
1357d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1358025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
135920b8391fSDavid Howells 	afs_set_fc_call(call, fc);
13600b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
13610b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1362b9b1f8d5SDavid Howells }
1363b9b1f8d5SDavid Howells 
136431143d5dSDavid Howells /*
136531143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
136631143d5dSDavid Howells  * so as to alter the file size also
136731143d5dSDavid Howells  */
1368a58823acSDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
1369a58823acSDavid Howells 			       struct afs_status_cb *scb)
137031143d5dSDavid Howells {
1371d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
137231143d5dSDavid Howells 	struct afs_call *call;
1373f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
137431143d5dSDavid Howells 	__be32 *bp;
137531143d5dSDavid Howells 
13763b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1377d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
137831143d5dSDavid Howells 
137931143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1380b9b1f8d5SDavid Howells 	if (attr->ia_size >> 32)
1381a58823acSDavid Howells 		return afs_fs_setattr_size64(fc, attr, scb);
138231143d5dSDavid Howells 
1383f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
138431143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
138531143d5dSDavid Howells 				   (21 + 6) * 4);
138631143d5dSDavid Howells 	if (!call)
138731143d5dSDavid Howells 		return -ENOMEM;
138831143d5dSDavid Howells 
1389d2ddc776SDavid Howells 	call->key = fc->key;
1390a58823acSDavid Howells 	call->out_scb = scb;
139131143d5dSDavid Howells 
139231143d5dSDavid Howells 	/* marshall the parameters */
139331143d5dSDavid Howells 	bp = call->request;
139431143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
139531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
139631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
139731143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
139831143d5dSDavid Howells 
139931143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
140031143d5dSDavid Howells 
14018c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
140231143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
140331143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
140431143d5dSDavid Howells 
1405d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1406025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
140720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14080b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14090b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
141031143d5dSDavid Howells }
141131143d5dSDavid Howells 
141231143d5dSDavid Howells /*
141331143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
141431143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
141531143d5dSDavid Howells  */
1416a58823acSDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
1417a58823acSDavid Howells 		   struct afs_status_cb *scb)
141831143d5dSDavid Howells {
1419d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
142031143d5dSDavid Howells 	struct afs_call *call;
1421f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
142231143d5dSDavid Howells 	__be32 *bp;
142331143d5dSDavid Howells 
142430062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1425a58823acSDavid Howells 		return yfs_fs_setattr(fc, attr, scb);
142630062bd1SDavid Howells 
142731143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1428a58823acSDavid Howells 		return afs_fs_setattr_size(fc, attr, scb);
142931143d5dSDavid Howells 
14303b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1431d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
143231143d5dSDavid Howells 
1433f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
143431143d5dSDavid Howells 				   (4 + 6) * 4,
143531143d5dSDavid Howells 				   (21 + 6) * 4);
143631143d5dSDavid Howells 	if (!call)
143731143d5dSDavid Howells 		return -ENOMEM;
143831143d5dSDavid Howells 
1439d2ddc776SDavid Howells 	call->key = fc->key;
1440a58823acSDavid Howells 	call->out_scb = scb;
144131143d5dSDavid Howells 
144231143d5dSDavid Howells 	/* marshall the parameters */
144331143d5dSDavid Howells 	bp = call->request;
144431143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
144531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
144631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
144731143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
144831143d5dSDavid Howells 
144931143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
145031143d5dSDavid Howells 
1451d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1452025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
145320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14540b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14550b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
145631143d5dSDavid Howells }
145745222b9eSDavid Howells 
145845222b9eSDavid Howells /*
145945222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
146045222b9eSDavid Howells  */
1461d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
146245222b9eSDavid Howells {
146345222b9eSDavid Howells 	const __be32 *bp;
146445222b9eSDavid Howells 	char *p;
146512bdcf33SDavid Howells 	u32 size;
146645222b9eSDavid Howells 	int ret;
146745222b9eSDavid Howells 
1468d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
146945222b9eSDavid Howells 
147045222b9eSDavid Howells 	switch (call->unmarshall) {
147145222b9eSDavid Howells 	case 0:
147245222b9eSDavid Howells 		call->unmarshall++;
147312bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
147445222b9eSDavid Howells 
1475e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the returned status record */
147645222b9eSDavid Howells 	case 1:
147745222b9eSDavid Howells 		_debug("extract status");
147812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1479372ee163SDavid Howells 		if (ret < 0)
1480372ee163SDavid Howells 			return ret;
148145222b9eSDavid Howells 
148245222b9eSDavid Howells 		bp = call->buffer;
1483ffba718eSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, call->out_volstatus);
148445222b9eSDavid Howells 		call->unmarshall++;
148512bdcf33SDavid Howells 		afs_extract_to_tmp(call);
148645222b9eSDavid Howells 
1487e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the volume name length */
148845222b9eSDavid Howells 	case 2:
148912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1490372ee163SDavid Howells 		if (ret < 0)
1491372ee163SDavid Howells 			return ret;
149245222b9eSDavid Howells 
149345222b9eSDavid Howells 		call->count = ntohl(call->tmp);
149445222b9eSDavid Howells 		_debug("volname length: %u", call->count);
149545222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1496160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1497160cb957SDavid Howells 						  afs_eproto_volname_len);
149812bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1499ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
150045222b9eSDavid Howells 		call->unmarshall++;
150145222b9eSDavid Howells 
1502e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the volume name */
150345222b9eSDavid Howells 	case 3:
150445222b9eSDavid Howells 		_debug("extract volname");
150512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1506372ee163SDavid Howells 		if (ret < 0)
1507372ee163SDavid Howells 			return ret;
150845222b9eSDavid Howells 
1509ffba718eSDavid Howells 		p = call->buffer;
151045222b9eSDavid Howells 		p[call->count] = 0;
151145222b9eSDavid Howells 		_debug("volname '%s'", p);
151212bdcf33SDavid Howells 		afs_extract_to_tmp(call);
151345222b9eSDavid Howells 		call->unmarshall++;
151445222b9eSDavid Howells 
1515e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the offline message length */
151612bdcf33SDavid Howells 	case 4:
151712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1518372ee163SDavid Howells 		if (ret < 0)
1519372ee163SDavid Howells 			return ret;
152045222b9eSDavid Howells 
152145222b9eSDavid Howells 		call->count = ntohl(call->tmp);
152245222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
152345222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1524160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1525160cb957SDavid Howells 						  afs_eproto_offline_msg_len);
152612bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1527ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
152845222b9eSDavid Howells 		call->unmarshall++;
152945222b9eSDavid Howells 
1530e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the offline message */
153112bdcf33SDavid Howells 	case 5:
153245222b9eSDavid Howells 		_debug("extract offline");
153312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1534372ee163SDavid Howells 		if (ret < 0)
1535372ee163SDavid Howells 			return ret;
153645222b9eSDavid Howells 
1537ffba718eSDavid Howells 		p = call->buffer;
153845222b9eSDavid Howells 		p[call->count] = 0;
153945222b9eSDavid Howells 		_debug("offline '%s'", p);
154045222b9eSDavid Howells 
154112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
154245222b9eSDavid Howells 		call->unmarshall++;
154345222b9eSDavid Howells 
1544e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the message of the day length */
154512bdcf33SDavid Howells 	case 6:
154612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1547372ee163SDavid Howells 		if (ret < 0)
1548372ee163SDavid Howells 			return ret;
154945222b9eSDavid Howells 
155045222b9eSDavid Howells 		call->count = ntohl(call->tmp);
155145222b9eSDavid Howells 		_debug("motd length: %u", call->count);
155245222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1553160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1554160cb957SDavid Howells 						  afs_eproto_motd_len);
155512bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1556ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
155745222b9eSDavid Howells 		call->unmarshall++;
155845222b9eSDavid Howells 
1559e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the message of the day */
156012bdcf33SDavid Howells 	case 7:
156145222b9eSDavid Howells 		_debug("extract motd");
156212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1563372ee163SDavid Howells 		if (ret < 0)
1564372ee163SDavid Howells 			return ret;
156545222b9eSDavid Howells 
1566ffba718eSDavid Howells 		p = call->buffer;
156745222b9eSDavid Howells 		p[call->count] = 0;
156845222b9eSDavid Howells 		_debug("motd '%s'", p);
156945222b9eSDavid Howells 
157045222b9eSDavid Howells 		call->unmarshall++;
157145222b9eSDavid Howells 
157212bdcf33SDavid Howells 	case 8:
157345222b9eSDavid Howells 		break;
157445222b9eSDavid Howells 	}
157545222b9eSDavid Howells 
157645222b9eSDavid Howells 	_leave(" = 0 [done]");
157745222b9eSDavid Howells 	return 0;
157845222b9eSDavid Howells }
157945222b9eSDavid Howells 
158045222b9eSDavid Howells /*
158145222b9eSDavid Howells  * FS.GetVolumeStatus operation type
158245222b9eSDavid Howells  */
158345222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
158445222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1585025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
158645222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1587ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
158845222b9eSDavid Howells };
158945222b9eSDavid Howells 
159045222b9eSDavid Howells /*
159145222b9eSDavid Howells  * fetch the status of a volume
159245222b9eSDavid Howells  */
15938b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
1594d2ddc776SDavid Howells 			     struct afs_volume_status *vs)
159545222b9eSDavid Howells {
1596d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
159745222b9eSDavid Howells 	struct afs_call *call;
1598f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
159945222b9eSDavid Howells 	__be32 *bp;
160045222b9eSDavid Howells 
160130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
160230062bd1SDavid Howells 		return yfs_fs_get_volume_status(fc, vs);
160330062bd1SDavid Howells 
160445222b9eSDavid Howells 	_enter("");
160545222b9eSDavid Howells 
1606ffba718eSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4,
1607ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1608ffba718eSDavid Howells 	if (!call)
160945222b9eSDavid Howells 		return -ENOMEM;
161045222b9eSDavid Howells 
1611d2ddc776SDavid Howells 	call->key = fc->key;
1612ffba718eSDavid Howells 	call->out_volstatus = vs;
161345222b9eSDavid Howells 
161445222b9eSDavid Howells 	/* marshall the parameters */
161545222b9eSDavid Howells 	bp = call->request;
161645222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
161745222b9eSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
161845222b9eSDavid Howells 
1619d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1620025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
162120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
16220b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
16230b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
162445222b9eSDavid Howells }
1625e8d6c554SDavid Howells 
1626e8d6c554SDavid Howells /*
1627e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1628e8d6c554SDavid Howells  */
1629d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1630e8d6c554SDavid Howells {
1631e8d6c554SDavid Howells 	const __be32 *bp;
1632372ee163SDavid Howells 	int ret;
1633e8d6c554SDavid Howells 
1634d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1635e8d6c554SDavid Howells 
1636d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1637372ee163SDavid Howells 	if (ret < 0)
1638372ee163SDavid Howells 		return ret;
1639e8d6c554SDavid Howells 
1640e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1641e8d6c554SDavid Howells 	bp = call->buffer;
1642ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
1643e8d6c554SDavid Howells 
1644e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1645e8d6c554SDavid Howells 	return 0;
1646e8d6c554SDavid Howells }
1647e8d6c554SDavid Howells 
1648e8d6c554SDavid Howells /*
1649e8d6c554SDavid Howells  * FS.SetLock operation type
1650e8d6c554SDavid Howells  */
1651e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1652e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1653025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1654e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1655a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1656e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1657e8d6c554SDavid Howells };
1658e8d6c554SDavid Howells 
1659e8d6c554SDavid Howells /*
1660e8d6c554SDavid Howells  * FS.ExtendLock operation type
1661e8d6c554SDavid Howells  */
1662e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1663e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1664025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
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.ReleaseLock operation type
1672e8d6c554SDavid Howells  */
1673e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1674e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1675025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1676e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1677e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1678e8d6c554SDavid Howells };
1679e8d6c554SDavid Howells 
1680e8d6c554SDavid Howells /*
1681d2ddc776SDavid Howells  * Set a lock on a file
1682e8d6c554SDavid Howells  */
1683a58823acSDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
1684a58823acSDavid Howells 		    struct afs_status_cb *scb)
1685e8d6c554SDavid Howells {
1686d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1687e8d6c554SDavid Howells 	struct afs_call *call;
1688f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1689e8d6c554SDavid Howells 	__be32 *bp;
1690e8d6c554SDavid Howells 
169130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1692a58823acSDavid Howells 		return yfs_fs_set_lock(fc, type, scb);
169330062bd1SDavid Howells 
1694e8d6c554SDavid Howells 	_enter("");
1695e8d6c554SDavid Howells 
1696f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1697e8d6c554SDavid Howells 	if (!call)
1698e8d6c554SDavid Howells 		return -ENOMEM;
1699e8d6c554SDavid Howells 
1700d2ddc776SDavid Howells 	call->key = fc->key;
1701a58823acSDavid Howells 	call->lvnode = vnode;
1702a58823acSDavid Howells 	call->out_scb = scb;
1703e8d6c554SDavid Howells 
1704e8d6c554SDavid Howells 	/* marshall the parameters */
1705e8d6c554SDavid Howells 	bp = call->request;
1706e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1707e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1708e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1709e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1710e8d6c554SDavid Howells 	*bp++ = htonl(type);
1711e8d6c554SDavid Howells 
1712d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
17136c6c1d63SDavid Howells 	trace_afs_make_fs_calli(call, &vnode->fid, type);
171420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17150b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17160b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1717e8d6c554SDavid Howells }
1718e8d6c554SDavid Howells 
1719e8d6c554SDavid Howells /*
1720e8d6c554SDavid Howells  * extend a lock on a file
1721e8d6c554SDavid Howells  */
1722a58823acSDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1723e8d6c554SDavid Howells {
1724d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1725e8d6c554SDavid Howells 	struct afs_call *call;
1726f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1727e8d6c554SDavid Howells 	__be32 *bp;
1728e8d6c554SDavid Howells 
172930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1730a58823acSDavid Howells 		return yfs_fs_extend_lock(fc, scb);
173130062bd1SDavid Howells 
1732e8d6c554SDavid Howells 	_enter("");
1733e8d6c554SDavid Howells 
1734f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1735e8d6c554SDavid Howells 	if (!call)
1736e8d6c554SDavid Howells 		return -ENOMEM;
1737e8d6c554SDavid Howells 
1738d2ddc776SDavid Howells 	call->key = fc->key;
1739a58823acSDavid Howells 	call->lvnode = vnode;
1740a58823acSDavid Howells 	call->out_scb = scb;
1741e8d6c554SDavid Howells 
1742e8d6c554SDavid Howells 	/* marshall the parameters */
1743e8d6c554SDavid Howells 	bp = call->request;
1744e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1745e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1746e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1747e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1748e8d6c554SDavid Howells 
1749d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1750025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
175120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17520b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17530b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1754e8d6c554SDavid Howells }
1755e8d6c554SDavid Howells 
1756e8d6c554SDavid Howells /*
1757e8d6c554SDavid Howells  * release a lock on a file
1758e8d6c554SDavid Howells  */
1759a58823acSDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1760e8d6c554SDavid Howells {
1761d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1762e8d6c554SDavid Howells 	struct afs_call *call;
1763f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1764e8d6c554SDavid Howells 	__be32 *bp;
1765e8d6c554SDavid Howells 
176630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1767a58823acSDavid Howells 		return yfs_fs_release_lock(fc, scb);
176830062bd1SDavid Howells 
1769e8d6c554SDavid Howells 	_enter("");
1770e8d6c554SDavid Howells 
1771f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1772e8d6c554SDavid Howells 	if (!call)
1773e8d6c554SDavid Howells 		return -ENOMEM;
1774e8d6c554SDavid Howells 
1775d2ddc776SDavid Howells 	call->key = fc->key;
1776a58823acSDavid Howells 	call->lvnode = vnode;
1777a58823acSDavid Howells 	call->out_scb = scb;
1778e8d6c554SDavid Howells 
1779e8d6c554SDavid Howells 	/* marshall the parameters */
1780e8d6c554SDavid Howells 	bp = call->request;
1781e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1782e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1783e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1784e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1785e8d6c554SDavid Howells 
1786d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1787025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
178820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17890b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17900b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1791c435ee34SDavid Howells }
1792c435ee34SDavid Howells 
1793c435ee34SDavid Howells /*
1794c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1795c435ee34SDavid Howells  */
1796c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1797c435ee34SDavid Howells {
1798c435ee34SDavid Howells 	return afs_transfer_reply(call);
1799c435ee34SDavid Howells }
1800c435ee34SDavid Howells 
1801c435ee34SDavid Howells /*
1802c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1803c435ee34SDavid Howells  */
1804c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1805c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1806025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1807c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1808c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1809c435ee34SDavid Howells };
1810c435ee34SDavid Howells 
1811c435ee34SDavid Howells /*
1812c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1813c435ee34SDavid Howells  */
1814d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1815d2ddc776SDavid Howells 				 struct afs_server *server,
18168b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1817d2ddc776SDavid Howells 				 struct key *key)
1818c435ee34SDavid Howells {
1819c435ee34SDavid Howells 	struct afs_call *call;
1820c435ee34SDavid Howells 	__be32 *bp;
1821c435ee34SDavid Howells 
1822c435ee34SDavid Howells 	_enter("");
1823c435ee34SDavid Howells 
1824d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1825c435ee34SDavid Howells 	if (!call)
1826c435ee34SDavid Howells 		return -ENOMEM;
1827c435ee34SDavid Howells 
1828c435ee34SDavid Howells 	call->key = key;
1829c435ee34SDavid Howells 
1830c435ee34SDavid Howells 	/* marshall the parameters */
1831c435ee34SDavid Howells 	bp = call->request;
1832c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1833c435ee34SDavid Howells 
1834c435ee34SDavid Howells 	/* Can't take a ref on server */
18350b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
18360b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1837d2ddc776SDavid Howells }
1838d2ddc776SDavid Howells 
1839d2ddc776SDavid Howells /*
1840d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1841d2ddc776SDavid Howells  */
1842d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1843d2ddc776SDavid Howells {
1844d2ddc776SDavid Howells 	u32 count;
1845d2ddc776SDavid Howells 	int ret;
1846d2ddc776SDavid Howells 
184712bdcf33SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(&call->iter));
1848d2ddc776SDavid Howells 
1849d2ddc776SDavid Howells 	switch (call->unmarshall) {
1850d2ddc776SDavid Howells 	case 0:
185112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1852d2ddc776SDavid Howells 		call->unmarshall++;
1853d2ddc776SDavid Howells 
1854e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract the capabilities word count */
1855d2ddc776SDavid Howells 	case 1:
185612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1857d2ddc776SDavid Howells 		if (ret < 0)
1858d2ddc776SDavid Howells 			return ret;
1859d2ddc776SDavid Howells 
1860d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1861d2ddc776SDavid Howells 
1862d2ddc776SDavid Howells 		call->count = count;
1863d2ddc776SDavid Howells 		call->count2 = count;
186412bdcf33SDavid Howells 		iov_iter_discard(&call->iter, READ, count * sizeof(__be32));
1865d2ddc776SDavid Howells 		call->unmarshall++;
1866d2ddc776SDavid Howells 
1867e690c9e3SGustavo A. R. Silva 		/* Fall through - and extract capabilities words */
1868d2ddc776SDavid Howells 	case 2:
186912bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1870d2ddc776SDavid Howells 		if (ret < 0)
1871d2ddc776SDavid Howells 			return ret;
1872d2ddc776SDavid Howells 
1873d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1874d2ddc776SDavid Howells 
1875d2ddc776SDavid Howells 		call->unmarshall++;
1876d2ddc776SDavid Howells 		break;
1877d2ddc776SDavid Howells 	}
1878d2ddc776SDavid Howells 
1879d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1880d2ddc776SDavid Howells 	return 0;
1881d2ddc776SDavid Howells }
1882d2ddc776SDavid Howells 
1883d2ddc776SDavid Howells /*
1884d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1885d2ddc776SDavid Howells  */
1886d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1887d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1888025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1889d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
18903bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1891ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1892d2ddc776SDavid Howells };
1893d2ddc776SDavid Howells 
1894d2ddc776SDavid Howells /*
1895d2ddc776SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This can
1896d2ddc776SDavid Howells  * return up to 196 words.
1897d2ddc776SDavid Howells  */
18980b9bf381SDavid Howells struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
1899d2ddc776SDavid Howells 					 struct afs_server *server,
1900d2ddc776SDavid Howells 					 struct afs_addr_cursor *ac,
19013bf0fb6fSDavid Howells 					 struct key *key,
19020b9bf381SDavid Howells 					 unsigned int server_index)
1903d2ddc776SDavid Howells {
1904d2ddc776SDavid Howells 	struct afs_call *call;
1905d2ddc776SDavid Howells 	__be32 *bp;
1906d2ddc776SDavid Howells 
1907d2ddc776SDavid Howells 	_enter("");
1908d2ddc776SDavid Howells 
1909d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1910d2ddc776SDavid Howells 	if (!call)
19110b9bf381SDavid Howells 		return ERR_PTR(-ENOMEM);
1912d2ddc776SDavid Howells 
1913d2ddc776SDavid Howells 	call->key = key;
1914ffba718eSDavid Howells 	call->server = afs_get_server(server);
1915ffba718eSDavid Howells 	call->server_index = server_index;
191630062bd1SDavid Howells 	call->upgrade = true;
19170b9bf381SDavid Howells 	call->async = true;
191894f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1919d2ddc776SDavid Howells 
1920d2ddc776SDavid Howells 	/* marshall the parameters */
1921d2ddc776SDavid Howells 	bp = call->request;
1922d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1923d2ddc776SDavid Howells 
1924d2ddc776SDavid Howells 	/* Can't take a ref on server */
1925025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
19260b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
19270b9bf381SDavid Howells 	return call;
1928e8d6c554SDavid Howells }
19295cf9dd55SDavid Howells 
19305cf9dd55SDavid Howells /*
19315cf9dd55SDavid Howells  * Deliver reply data to an FS.FetchStatus with no vnode.
19325cf9dd55SDavid Howells  */
19335cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
19345cf9dd55SDavid Howells {
19355cf9dd55SDavid Howells 	const __be32 *bp;
19365cf9dd55SDavid Howells 	int ret;
19375cf9dd55SDavid Howells 
19385cf9dd55SDavid Howells 	ret = afs_transfer_reply(call);
19395cf9dd55SDavid Howells 	if (ret < 0)
19405cf9dd55SDavid Howells 		return ret;
19415cf9dd55SDavid Howells 
19425cf9dd55SDavid Howells 	/* unmarshall the reply once we've received all of it */
19435cf9dd55SDavid Howells 	bp = call->buffer;
1944a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1945160cb957SDavid Howells 	if (ret < 0)
1946160cb957SDavid Howells 		return ret;
1947a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
1948a58823acSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
19495cf9dd55SDavid Howells 
19505cf9dd55SDavid Howells 	_leave(" = 0 [done]");
19515cf9dd55SDavid Howells 	return 0;
19525cf9dd55SDavid Howells }
19535cf9dd55SDavid Howells 
19545cf9dd55SDavid Howells /*
19555cf9dd55SDavid Howells  * FS.FetchStatus operation type
19565cf9dd55SDavid Howells  */
19575cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
19585cf9dd55SDavid Howells 	.name		= "FS.FetchStatus",
19595cf9dd55SDavid Howells 	.op		= afs_FS_FetchStatus,
19605cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
19615cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
19625cf9dd55SDavid Howells };
19635cf9dd55SDavid Howells 
19645cf9dd55SDavid Howells /*
19655cf9dd55SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
19665cf9dd55SDavid Howells  */
19675cf9dd55SDavid Howells int afs_fs_fetch_status(struct afs_fs_cursor *fc,
19685cf9dd55SDavid Howells 			struct afs_net *net,
19695cf9dd55SDavid Howells 			struct afs_fid *fid,
1970a58823acSDavid Howells 			struct afs_status_cb *scb,
19715cf9dd55SDavid Howells 			struct afs_volsync *volsync)
19725cf9dd55SDavid Howells {
19735cf9dd55SDavid Howells 	struct afs_call *call;
19745cf9dd55SDavid Howells 	__be32 *bp;
19755cf9dd55SDavid Howells 
197630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1977a58823acSDavid Howells 		return yfs_fs_fetch_status(fc, net, fid, scb, volsync);
197830062bd1SDavid Howells 
19793b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
19805cf9dd55SDavid Howells 	       key_serial(fc->key), fid->vid, fid->vnode);
19815cf9dd55SDavid Howells 
19825cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
19835cf9dd55SDavid Howells 	if (!call) {
19845cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
19855cf9dd55SDavid Howells 		return -ENOMEM;
19865cf9dd55SDavid Howells 	}
19875cf9dd55SDavid Howells 
19885cf9dd55SDavid Howells 	call->key = fc->key;
1989ffba718eSDavid Howells 	call->out_fid = fid;
1990a58823acSDavid Howells 	call->out_scb = scb;
1991ffba718eSDavid Howells 	call->out_volsync = volsync;
19925cf9dd55SDavid Howells 
19935cf9dd55SDavid Howells 	/* marshall the parameters */
19945cf9dd55SDavid Howells 	bp = call->request;
19955cf9dd55SDavid Howells 	bp[0] = htonl(FSFETCHSTATUS);
19965cf9dd55SDavid Howells 	bp[1] = htonl(fid->vid);
19975cf9dd55SDavid Howells 	bp[2] = htonl(fid->vnode);
19985cf9dd55SDavid Howells 	bp[3] = htonl(fid->unique);
19995cf9dd55SDavid Howells 
20005cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
20015cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, fid);
200220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
20030b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
20040b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
20055cf9dd55SDavid Howells }
20065cf9dd55SDavid Howells 
20075cf9dd55SDavid Howells /*
20085cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
20095cf9dd55SDavid Howells  */
20105cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
20115cf9dd55SDavid Howells {
201287182759SDavid Howells 	struct afs_status_cb *scb;
20135cf9dd55SDavid Howells 	const __be32 *bp;
20145cf9dd55SDavid Howells 	u32 tmp;
20155cf9dd55SDavid Howells 	int ret;
20165cf9dd55SDavid Howells 
20175cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
20185cf9dd55SDavid Howells 
20195cf9dd55SDavid Howells 	switch (call->unmarshall) {
20205cf9dd55SDavid Howells 	case 0:
202112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
20225cf9dd55SDavid Howells 		call->unmarshall++;
20235cf9dd55SDavid Howells 
20245cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
2025e690c9e3SGustavo A. R. Silva 		/* Fall through */
20265cf9dd55SDavid Howells 	case 1:
20275cf9dd55SDavid Howells 		_debug("extract status count");
202812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20295cf9dd55SDavid Howells 		if (ret < 0)
20305cf9dd55SDavid Howells 			return ret;
20315cf9dd55SDavid Howells 
20325cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20335cf9dd55SDavid Howells 		_debug("status count: %u/%u", tmp, call->count2);
20345cf9dd55SDavid Howells 		if (tmp != call->count2)
2035160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2036160cb957SDavid Howells 						  afs_eproto_ibulkst_count);
20375cf9dd55SDavid Howells 
20385cf9dd55SDavid Howells 		call->count = 0;
20395cf9dd55SDavid Howells 		call->unmarshall++;
20405cf9dd55SDavid Howells 	more_counts:
204112bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
20425cf9dd55SDavid Howells 
2043e690c9e3SGustavo A. R. Silva 		/* Fall through */
20445cf9dd55SDavid Howells 	case 2:
20455cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
204612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20475cf9dd55SDavid Howells 		if (ret < 0)
20485cf9dd55SDavid Howells 			return ret;
20495cf9dd55SDavid Howells 
20505cf9dd55SDavid Howells 		bp = call->buffer;
205187182759SDavid Howells 		scb = &call->out_scb[call->count];
2052a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, scb);
2053160cb957SDavid Howells 		if (ret < 0)
2054160cb957SDavid Howells 			return ret;
20555cf9dd55SDavid Howells 
20565cf9dd55SDavid Howells 		call->count++;
20575cf9dd55SDavid Howells 		if (call->count < call->count2)
20585cf9dd55SDavid Howells 			goto more_counts;
20595cf9dd55SDavid Howells 
20605cf9dd55SDavid Howells 		call->count = 0;
20615cf9dd55SDavid Howells 		call->unmarshall++;
206212bdcf33SDavid Howells 		afs_extract_to_tmp(call);
20635cf9dd55SDavid Howells 
20645cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
2065e690c9e3SGustavo A. R. Silva 		/* Fall through */
20665cf9dd55SDavid Howells 	case 3:
20675cf9dd55SDavid Howells 		_debug("extract CB count");
206812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20695cf9dd55SDavid Howells 		if (ret < 0)
20705cf9dd55SDavid Howells 			return ret;
20715cf9dd55SDavid Howells 
20725cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20735cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
20745cf9dd55SDavid Howells 		if (tmp != call->count2)
2075160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2076160cb957SDavid Howells 						  afs_eproto_ibulkst_cb_count);
20775cf9dd55SDavid Howells 		call->count = 0;
20785cf9dd55SDavid Howells 		call->unmarshall++;
20795cf9dd55SDavid Howells 	more_cbs:
208012bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
20815cf9dd55SDavid Howells 
2082e690c9e3SGustavo A. R. Silva 		/* Fall through */
20835cf9dd55SDavid Howells 	case 4:
20845cf9dd55SDavid Howells 		_debug("extract CB array");
208512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20865cf9dd55SDavid Howells 		if (ret < 0)
20875cf9dd55SDavid Howells 			return ret;
20885cf9dd55SDavid Howells 
20895cf9dd55SDavid Howells 		_debug("unmarshall CB array");
20905cf9dd55SDavid Howells 		bp = call->buffer;
209187182759SDavid Howells 		scb = &call->out_scb[call->count];
2092a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
20935cf9dd55SDavid Howells 		call->count++;
20945cf9dd55SDavid Howells 		if (call->count < call->count2)
20955cf9dd55SDavid Howells 			goto more_cbs;
20965cf9dd55SDavid Howells 
209712bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
20985cf9dd55SDavid Howells 		call->unmarshall++;
20995cf9dd55SDavid Howells 
2100e690c9e3SGustavo A. R. Silva 		/* Fall through */
21015cf9dd55SDavid Howells 	case 5:
210212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
21035cf9dd55SDavid Howells 		if (ret < 0)
21045cf9dd55SDavid Howells 			return ret;
21055cf9dd55SDavid Howells 
21065cf9dd55SDavid Howells 		bp = call->buffer;
2107ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
21085cf9dd55SDavid Howells 
21095cf9dd55SDavid Howells 		call->unmarshall++;
21105cf9dd55SDavid Howells 
21115cf9dd55SDavid Howells 	case 6:
21125cf9dd55SDavid Howells 		break;
21135cf9dd55SDavid Howells 	}
21145cf9dd55SDavid Howells 
21155cf9dd55SDavid Howells 	_leave(" = 0 [done]");
21165cf9dd55SDavid Howells 	return 0;
21175cf9dd55SDavid Howells }
21185cf9dd55SDavid Howells 
21195cf9dd55SDavid Howells /*
21205cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
21215cf9dd55SDavid Howells  */
21225cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
21235cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
21245cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
21255cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
21265cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
21275cf9dd55SDavid Howells };
21285cf9dd55SDavid Howells 
21295cf9dd55SDavid Howells /*
21305cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
21315cf9dd55SDavid Howells  */
21325cf9dd55SDavid Howells int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
21335cf9dd55SDavid Howells 			      struct afs_net *net,
21345cf9dd55SDavid Howells 			      struct afs_fid *fids,
213587182759SDavid Howells 			      struct afs_status_cb *statuses,
21365cf9dd55SDavid Howells 			      unsigned int nr_fids,
21375cf9dd55SDavid Howells 			      struct afs_volsync *volsync)
21385cf9dd55SDavid Howells {
21395cf9dd55SDavid Howells 	struct afs_call *call;
21405cf9dd55SDavid Howells 	__be32 *bp;
21415cf9dd55SDavid Howells 	int i;
21425cf9dd55SDavid Howells 
214330062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
214487182759SDavid Howells 		return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
214530062bd1SDavid Howells 						 nr_fids, volsync);
214630062bd1SDavid Howells 
21473b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
21485cf9dd55SDavid Howells 	       key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
21495cf9dd55SDavid Howells 
21505cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
21515cf9dd55SDavid Howells 				   (2 + nr_fids * 3) * 4,
21525cf9dd55SDavid Howells 				   21 * 4);
21535cf9dd55SDavid Howells 	if (!call) {
21545cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
21555cf9dd55SDavid Howells 		return -ENOMEM;
21565cf9dd55SDavid Howells 	}
21575cf9dd55SDavid Howells 
21585cf9dd55SDavid Howells 	call->key = fc->key;
215987182759SDavid Howells 	call->out_scb = statuses;
2160ffba718eSDavid Howells 	call->out_volsync = volsync;
21615cf9dd55SDavid Howells 	call->count2 = nr_fids;
21625cf9dd55SDavid Howells 
21635cf9dd55SDavid Howells 	/* marshall the parameters */
21645cf9dd55SDavid Howells 	bp = call->request;
21655cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
21665cf9dd55SDavid Howells 	*bp++ = htonl(nr_fids);
21675cf9dd55SDavid Howells 	for (i = 0; i < nr_fids; i++) {
21685cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vid);
21695cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vnode);
21705cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].unique);
21715cf9dd55SDavid Howells 	}
21725cf9dd55SDavid Howells 
21735cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
21745cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, &fids[0]);
217520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
21760b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
21770b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
21785cf9dd55SDavid Howells }
2179260f082bSDavid Howells 
2180260f082bSDavid Howells /*
2181260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
2182260f082bSDavid Howells  */
2183260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
2184260f082bSDavid Howells {
2185260f082bSDavid Howells 	struct afs_acl *acl;
2186260f082bSDavid Howells 	const __be32 *bp;
2187260f082bSDavid Howells 	unsigned int size;
2188260f082bSDavid Howells 	int ret;
2189260f082bSDavid Howells 
2190260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
2191260f082bSDavid Howells 
2192260f082bSDavid Howells 	switch (call->unmarshall) {
2193260f082bSDavid Howells 	case 0:
2194260f082bSDavid Howells 		afs_extract_to_tmp(call);
2195260f082bSDavid Howells 		call->unmarshall++;
2196260f082bSDavid Howells 
2197260f082bSDavid Howells 		/* extract the returned data length */
2198260f082bSDavid Howells 	case 1:
2199260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2200260f082bSDavid Howells 		if (ret < 0)
2201260f082bSDavid Howells 			return ret;
2202260f082bSDavid Howells 
2203260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
2204260f082bSDavid Howells 		size = round_up(size, 4);
2205260f082bSDavid Howells 
2206260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
2207260f082bSDavid Howells 		if (!acl)
2208260f082bSDavid Howells 			return -ENOMEM;
2209ffba718eSDavid Howells 		call->ret_acl = acl;
2210260f082bSDavid Howells 		acl->size = call->count2;
2211260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
2212260f082bSDavid Howells 		call->unmarshall++;
2213260f082bSDavid Howells 
2214260f082bSDavid Howells 		/* extract the returned data */
2215260f082bSDavid Howells 	case 2:
2216260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2217260f082bSDavid Howells 		if (ret < 0)
2218260f082bSDavid Howells 			return ret;
2219260f082bSDavid Howells 
2220260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
2221260f082bSDavid Howells 		call->unmarshall++;
2222260f082bSDavid Howells 
2223260f082bSDavid Howells 		/* extract the metadata */
2224260f082bSDavid Howells 	case 3:
2225260f082bSDavid Howells 		ret = afs_extract_data(call, false);
2226260f082bSDavid Howells 		if (ret < 0)
2227260f082bSDavid Howells 			return ret;
2228260f082bSDavid Howells 
2229260f082bSDavid Howells 		bp = call->buffer;
2230a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2231260f082bSDavid Howells 		if (ret < 0)
2232260f082bSDavid Howells 			return ret;
2233ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
2234260f082bSDavid Howells 
2235260f082bSDavid Howells 		call->unmarshall++;
2236260f082bSDavid Howells 
2237260f082bSDavid Howells 	case 4:
2238260f082bSDavid Howells 		break;
2239260f082bSDavid Howells 	}
2240260f082bSDavid Howells 
2241260f082bSDavid Howells 	_leave(" = 0 [done]");
2242260f082bSDavid Howells 	return 0;
2243260f082bSDavid Howells }
2244260f082bSDavid Howells 
2245260f082bSDavid Howells static void afs_destroy_fs_fetch_acl(struct afs_call *call)
2246260f082bSDavid Howells {
2247ffba718eSDavid Howells 	kfree(call->ret_acl);
2248260f082bSDavid Howells 	afs_flat_call_destructor(call);
2249260f082bSDavid Howells }
2250260f082bSDavid Howells 
2251260f082bSDavid Howells /*
2252260f082bSDavid Howells  * FS.FetchACL operation type
2253260f082bSDavid Howells  */
2254260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2255260f082bSDavid Howells 	.name		= "FS.FetchACL",
2256260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2257260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2258260f082bSDavid Howells 	.destructor	= afs_destroy_fs_fetch_acl,
2259260f082bSDavid Howells };
2260260f082bSDavid Howells 
2261260f082bSDavid Howells /*
2262260f082bSDavid Howells  * Fetch the ACL for a file.
2263260f082bSDavid Howells  */
2264a58823acSDavid Howells struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc,
2265a58823acSDavid Howells 				 struct afs_status_cb *scb)
2266260f082bSDavid Howells {
2267260f082bSDavid Howells 	struct afs_vnode *vnode = fc->vnode;
2268260f082bSDavid Howells 	struct afs_call *call;
2269260f082bSDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2270260f082bSDavid Howells 	__be32 *bp;
2271260f082bSDavid Howells 
2272260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2273260f082bSDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2274260f082bSDavid Howells 
2275260f082bSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2276260f082bSDavid Howells 	if (!call) {
2277260f082bSDavid Howells 		fc->ac.error = -ENOMEM;
2278260f082bSDavid Howells 		return ERR_PTR(-ENOMEM);
2279260f082bSDavid Howells 	}
2280260f082bSDavid Howells 
2281260f082bSDavid Howells 	call->key = fc->key;
2282ffba718eSDavid Howells 	call->ret_acl = NULL;
2283a58823acSDavid Howells 	call->out_scb = scb;
2284ffba718eSDavid Howells 	call->out_volsync = NULL;
2285260f082bSDavid Howells 
2286260f082bSDavid Howells 	/* marshall the parameters */
2287260f082bSDavid Howells 	bp = call->request;
2288260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2289260f082bSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
2290260f082bSDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
2291260f082bSDavid Howells 	bp[3] = htonl(vnode->fid.unique);
2292260f082bSDavid Howells 
2293260f082bSDavid Howells 	afs_use_fs_server(call, fc->cbi);
2294260f082bSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
2295260f082bSDavid Howells 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2296260f082bSDavid Howells 	return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
2297260f082bSDavid Howells }
2298b10494afSJoe Gorse 
2299b10494afSJoe Gorse /*
2300ffba718eSDavid Howells  * Deliver reply data to any operation that returns file status and volume
2301ffba718eSDavid Howells  * sync.
2302ffba718eSDavid Howells  */
2303ffba718eSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
2304ffba718eSDavid Howells {
2305ffba718eSDavid Howells 	const __be32 *bp;
2306ffba718eSDavid Howells 	int ret;
2307ffba718eSDavid Howells 
2308ffba718eSDavid Howells 	ret = afs_transfer_reply(call);
2309ffba718eSDavid Howells 	if (ret < 0)
2310ffba718eSDavid Howells 		return ret;
2311ffba718eSDavid Howells 
2312ffba718eSDavid Howells 	bp = call->buffer;
2313a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2314ffba718eSDavid Howells 	if (ret < 0)
2315ffba718eSDavid Howells 		return ret;
2316ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2317ffba718eSDavid Howells 
2318ffba718eSDavid Howells 	_leave(" = 0 [done]");
2319ffba718eSDavid Howells 	return 0;
2320ffba718eSDavid Howells }
2321ffba718eSDavid Howells 
2322ffba718eSDavid Howells /*
2323b10494afSJoe Gorse  * FS.StoreACL operation type
2324b10494afSJoe Gorse  */
2325b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2326b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2327b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2328ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2329b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2330b10494afSJoe Gorse };
2331b10494afSJoe Gorse 
2332b10494afSJoe Gorse /*
2333b10494afSJoe Gorse  * Fetch the ACL for a file.
2334b10494afSJoe Gorse  */
2335a58823acSDavid Howells int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl,
2336a58823acSDavid Howells 		     struct afs_status_cb *scb)
2337b10494afSJoe Gorse {
2338b10494afSJoe Gorse 	struct afs_vnode *vnode = fc->vnode;
2339b10494afSJoe Gorse 	struct afs_call *call;
2340b10494afSJoe Gorse 	struct afs_net *net = afs_v2net(vnode);
2341b10494afSJoe Gorse 	size_t size;
2342b10494afSJoe Gorse 	__be32 *bp;
2343b10494afSJoe Gorse 
2344b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2345b10494afSJoe Gorse 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2346b10494afSJoe Gorse 
2347b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2348b10494afSJoe Gorse 	call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
2349b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2350b10494afSJoe Gorse 	if (!call) {
2351b10494afSJoe Gorse 		fc->ac.error = -ENOMEM;
2352b10494afSJoe Gorse 		return -ENOMEM;
2353b10494afSJoe Gorse 	}
2354b10494afSJoe Gorse 
2355b10494afSJoe Gorse 	call->key = fc->key;
2356a58823acSDavid Howells 	call->out_scb = scb;
2357ffba718eSDavid Howells 	call->out_volsync = NULL;
2358b10494afSJoe Gorse 
2359b10494afSJoe Gorse 	/* marshall the parameters */
2360b10494afSJoe Gorse 	bp = call->request;
2361b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2362b10494afSJoe Gorse 	bp[1] = htonl(vnode->fid.vid);
2363b10494afSJoe Gorse 	bp[2] = htonl(vnode->fid.vnode);
2364b10494afSJoe Gorse 	bp[3] = htonl(vnode->fid.unique);
2365b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2366b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2367b10494afSJoe Gorse 	if (acl->size != size)
2368b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2369b10494afSJoe Gorse 
2370b10494afSJoe Gorse 	trace_afs_make_fs_call(call, &vnode->fid);
2371b10494afSJoe Gorse 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2372b10494afSJoe Gorse 	return afs_wait_for_call_to_complete(call, &fc->ac);
23731da177e4SLinus Torvalds }
2374