xref: /openbmc/linux/fs/afs/fsclient.c (revision d4438a25)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
208e0e7c8SDavid Howells /* AFS File Server client stubs
31da177e4SLinus Torvalds  *
408e0e7c8SDavid Howells  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/init.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
101da177e4SLinus Torvalds #include <linux/sched.h>
1108e0e7c8SDavid Howells #include <linux/circ_buf.h>
12a01179e6SJeff Layton #include <linux/iversion.h>
131da177e4SLinus Torvalds #include "internal.h"
1408e0e7c8SDavid Howells #include "afs_fs.h"
15dd9fbcb8SDavid Howells #include "xdr_fs.h"
1630062bd1SDavid Howells #include "protocol_yfs.h"
171da177e4SLinus Torvalds 
18d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
19c435ee34SDavid Howells {
20d2ddc776SDavid Howells 	call->cbi = afs_get_cb_interest(cbi);
21c435ee34SDavid Howells }
22c435ee34SDavid Howells 
236db3ac3cSDavid Howells /*
24260a9803SDavid Howells  * decode an AFSFid block
25260a9803SDavid Howells  */
26260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
27260a9803SDavid Howells {
28260a9803SDavid Howells 	const __be32 *bp = *_bp;
29260a9803SDavid Howells 
30260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
31260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
32260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
33260a9803SDavid Howells 	*_bp = bp;
34260a9803SDavid Howells }
35260a9803SDavid Howells 
36260a9803SDavid Howells /*
37888b3384SDavid Howells  * Dump a bad file status record.
38888b3384SDavid Howells  */
39888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
40888b3384SDavid Howells {
41888b3384SDavid Howells 	__be32 x[4];
42888b3384SDavid Howells 	int i;
43888b3384SDavid Howells 
44888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
45888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
46888b3384SDavid Howells 		memcpy(x, bp, 16);
47888b3384SDavid Howells 		bp += 4;
48888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
49888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
50888b3384SDavid Howells 	}
51888b3384SDavid Howells 
52888b3384SDavid Howells 	memcpy(x, bp, 4);
53888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
54888b3384SDavid Howells }
55888b3384SDavid Howells 
56888b3384SDavid Howells /*
57dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
58dd9fbcb8SDavid Howells  */
59a58823acSDavid Howells static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
60a58823acSDavid Howells 				     struct afs_call *call,
61a58823acSDavid Howells 				     struct afs_status_cb *scb)
62dd9fbcb8SDavid Howells {
63dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
64a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
65684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
66dd9fbcb8SDavid Howells 	u64 data_version, size;
67dd9fbcb8SDavid Howells 	u32 type, abort_code;
68dd9fbcb8SDavid Howells 
69684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
70684b0f68SDavid Howells 
71dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
72684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
73684b0f68SDavid Howells 		    abort_code != 0 &&
74684b0f68SDavid Howells 		    inline_error) {
75684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
76684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
77684b0f68SDavid Howells 			 * case.
78684b0f68SDavid Howells 			 */
79684b0f68SDavid Howells 			status->abort_code = abort_code;
80a38a7558SDavid Howells 			scb->have_error = true;
81de52cf92SAl Viro 			return 0;
82684b0f68SDavid Howells 		}
83684b0f68SDavid Howells 
84dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
85dd9fbcb8SDavid Howells 		goto bad;
86dd9fbcb8SDavid Howells 	}
87dd9fbcb8SDavid Howells 
88684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
89684b0f68SDavid Howells 		status->abort_code = abort_code;
90de52cf92SAl Viro 		return 0;
91684b0f68SDavid Howells 	}
92684b0f68SDavid Howells 
93dd9fbcb8SDavid Howells 	type = ntohl(xdr->type);
94dd9fbcb8SDavid Howells 	switch (type) {
95dd9fbcb8SDavid Howells 	case AFS_FTYPE_FILE:
96dd9fbcb8SDavid Howells 	case AFS_FTYPE_DIR:
97dd9fbcb8SDavid Howells 	case AFS_FTYPE_SYMLINK:
98dd9fbcb8SDavid Howells 		status->type = type;
99dd9fbcb8SDavid Howells 		break;
100dd9fbcb8SDavid Howells 	default:
101dd9fbcb8SDavid Howells 		goto bad;
102dd9fbcb8SDavid Howells 	}
103dd9fbcb8SDavid Howells 
104a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
105a58823acSDavid Howells 	status->author		= ntohl(xdr->author);
106a58823acSDavid Howells 	status->owner		= ntohl(xdr->owner);
107a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
108a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
109a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
110a58823acSDavid Howells 	status->group		= ntohl(xdr->group);
111a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
112dd9fbcb8SDavid Howells 
113d4936803SDavid Howells 	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
114d4936803SDavid Howells 	status->mtime_client.tv_nsec = 0;
115d4936803SDavid Howells 	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
116d4936803SDavid Howells 	status->mtime_server.tv_nsec = 0;
117dd9fbcb8SDavid Howells 
118dd9fbcb8SDavid Howells 	size  = (u64)ntohl(xdr->size_lo);
119dd9fbcb8SDavid Howells 	size |= (u64)ntohl(xdr->size_hi) << 32;
120dd9fbcb8SDavid Howells 	status->size = size;
121dd9fbcb8SDavid Howells 
122dd9fbcb8SDavid Howells 	data_version  = (u64)ntohl(xdr->data_version_lo);
123dd9fbcb8SDavid Howells 	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
124dd9fbcb8SDavid Howells 	status->data_version = data_version;
125a38a7558SDavid Howells 	scb->have_status = true;
126dd9fbcb8SDavid Howells 
127dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
128c875c76aSDavid Howells 	return 0;
129dd9fbcb8SDavid Howells 
130dd9fbcb8SDavid Howells bad:
131dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
132160cb957SDavid Howells 	return afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
133c875c76aSDavid Howells }
134c875c76aSDavid Howells 
13578107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
13678107055SDavid Howells {
13778107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
13878107055SDavid Howells }
13978107055SDavid Howells 
140a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
141a58823acSDavid Howells 				   struct afs_call *call,
142a58823acSDavid Howells 				   struct afs_status_cb *scb)
14378107055SDavid Howells {
144a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
14578107055SDavid Howells 	const __be32 *bp = *_bp;
14678107055SDavid Howells 
1477c712458SDavid Howells 	bp++; /* version */
14878107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1497c712458SDavid Howells 	bp++; /* type */
150a58823acSDavid Howells 	scb->have_cb	= true;
15178107055SDavid Howells 	*_bp = bp;
15278107055SDavid Howells }
15378107055SDavid Howells 
1541da177e4SLinus Torvalds /*
15508e0e7c8SDavid Howells  * decode an AFSVolSync block
1561da177e4SLinus Torvalds  */
15708e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
15808e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1591da177e4SLinus Torvalds {
16008e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
16130062bd1SDavid Howells 	u32 creation;
1621da177e4SLinus Torvalds 
16330062bd1SDavid Howells 	creation = ntohl(*bp++);
16408e0e7c8SDavid Howells 	bp++; /* spare2 */
16508e0e7c8SDavid Howells 	bp++; /* spare3 */
16608e0e7c8SDavid Howells 	bp++; /* spare4 */
16708e0e7c8SDavid Howells 	bp++; /* spare5 */
16808e0e7c8SDavid Howells 	bp++; /* spare6 */
16908e0e7c8SDavid Howells 	*_bp = bp;
17030062bd1SDavid Howells 
17130062bd1SDavid Howells 	if (volsync)
17230062bd1SDavid Howells 		volsync->creation = creation;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
17508e0e7c8SDavid Howells /*
17631143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
17731143d5dSDavid Howells  */
17831143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
17931143d5dSDavid Howells {
18031143d5dSDavid Howells 	__be32 *bp = *_bp;
18131143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
18231143d5dSDavid Howells 
18331143d5dSDavid Howells 	mask = 0;
18431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18531143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
18631143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
18731143d5dSDavid Howells 	}
18831143d5dSDavid Howells 
18931143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
19031143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
191a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
19231143d5dSDavid Howells 	}
19331143d5dSDavid Howells 
19431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19531143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
196a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
19731143d5dSDavid Howells 	}
19831143d5dSDavid Howells 
19931143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
20031143d5dSDavid Howells 		mask |= AFS_SET_MODE;
20131143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
20231143d5dSDavid Howells 	}
20331143d5dSDavid Howells 
20431143d5dSDavid Howells 	*bp++ = htonl(mask);
20531143d5dSDavid Howells 	*bp++ = htonl(mtime);
20631143d5dSDavid Howells 	*bp++ = htonl(owner);
20731143d5dSDavid Howells 	*bp++ = htonl(group);
20831143d5dSDavid Howells 	*bp++ = htonl(mode);
20931143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
21031143d5dSDavid Howells 	*_bp = bp;
21131143d5dSDavid Howells }
21231143d5dSDavid Howells 
21331143d5dSDavid Howells /*
21445222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21545222b9eSDavid Howells  */
21645222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
21745222b9eSDavid Howells 					    struct afs_volume_status *vs)
21845222b9eSDavid Howells {
21945222b9eSDavid Howells 	const __be32 *bp = *_bp;
22045222b9eSDavid Howells 
22145222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
22245222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22345222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22445222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22545222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
23045222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
23145222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
23245222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23330062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23430062bd1SDavid Howells 	vs->vol_backup_date	= 0;
23545222b9eSDavid Howells 	*_bp = bp;
23645222b9eSDavid Howells }
23745222b9eSDavid Howells 
23845222b9eSDavid Howells /*
23908e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
24008e0e7c8SDavid Howells  */
2415cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
24208e0e7c8SDavid Howells {
24308e0e7c8SDavid Howells 	const __be32 *bp;
244372ee163SDavid Howells 	int ret;
2451da177e4SLinus Torvalds 
246d001648eSDavid Howells 	ret = afs_transfer_reply(call);
247372ee163SDavid Howells 	if (ret < 0)
248372ee163SDavid Howells 		return ret;
2491da177e4SLinus Torvalds 
25008e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25108e0e7c8SDavid Howells 	bp = call->buffer;
252a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
253160cb957SDavid Howells 	if (ret < 0)
254160cb957SDavid Howells 		return ret;
255a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
256ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2571da177e4SLinus Torvalds 
25808e0e7c8SDavid Howells 	_leave(" = 0 [done]");
25908e0e7c8SDavid Howells 	return 0;
260ec26815aSDavid Howells }
26108e0e7c8SDavid Howells 
26208e0e7c8SDavid Howells /*
26308e0e7c8SDavid Howells  * FS.FetchStatus operation type
26408e0e7c8SDavid Howells  */
2655cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
2665cf9dd55SDavid Howells 	.name		= "FS.FetchStatus(vnode)",
267025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
2685cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status_vnode,
26908e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
27008e0e7c8SDavid Howells };
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds /*
2731da177e4SLinus Torvalds  * fetch the status information for a file
2741da177e4SLinus Torvalds  */
275a58823acSDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
276a58823acSDavid Howells 			     struct afs_volsync *volsync)
2771da177e4SLinus Torvalds {
278d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
27908e0e7c8SDavid Howells 	struct afs_call *call;
280f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2811da177e4SLinus Torvalds 	__be32 *bp;
2821da177e4SLinus Torvalds 
28330062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
284a58823acSDavid Howells 		return yfs_fs_fetch_file_status(fc, scb, volsync);
28530062bd1SDavid Howells 
2863b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
287d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2881da177e4SLinus Torvalds 
2895cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
2905cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
291d2ddc776SDavid Howells 	if (!call) {
292d2ddc776SDavid Howells 		fc->ac.error = -ENOMEM;
29308e0e7c8SDavid Howells 		return -ENOMEM;
294d2ddc776SDavid Howells 	}
2951da177e4SLinus Torvalds 
296d2ddc776SDavid Howells 	call->key = fc->key;
297a58823acSDavid Howells 	call->out_scb = scb;
298ffba718eSDavid Howells 	call->out_volsync = volsync;
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	/* marshall the parameters */
30108e0e7c8SDavid Howells 	bp = call->request;
3021da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
3031da177e4SLinus Torvalds 	bp[1] = htonl(vnode->fid.vid);
3041da177e4SLinus Torvalds 	bp[2] = htonl(vnode->fid.vnode);
3051da177e4SLinus Torvalds 	bp[3] = htonl(vnode->fid.unique);
3061da177e4SLinus Torvalds 
307d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
308025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
3090b9bf381SDavid Howells 
31020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
3110b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
3120b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
313ec26815aSDavid Howells }
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds /*
31608e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
3171da177e4SLinus Torvalds  */
318d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3191da177e4SLinus Torvalds {
320ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
32108e0e7c8SDavid Howells 	const __be32 *bp;
322196ee9cdSDavid Howells 	unsigned int size;
3231da177e4SLinus Torvalds 	int ret;
3241da177e4SLinus Torvalds 
32512bdcf33SDavid Howells 	_enter("{%u,%zu/%llu}",
326fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
3271da177e4SLinus Torvalds 
32808e0e7c8SDavid Howells 	switch (call->unmarshall) {
32908e0e7c8SDavid Howells 	case 0:
330196ee9cdSDavid Howells 		req->actual_len = 0;
33112bdcf33SDavid Howells 		req->index = 0;
33212bdcf33SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
33308e0e7c8SDavid Howells 		call->unmarshall++;
33412bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
33512bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
33612bdcf33SDavid Howells 		} else {
33712bdcf33SDavid Howells 			call->tmp_u = htonl(0);
33812bdcf33SDavid Howells 			afs_extract_to_tmp(call);
339b9b1f8d5SDavid Howells 		}
34029881608SGustavo A. R. Silva 		/* Fall through */
3411da177e4SLinus Torvalds 
34229881608SGustavo A. R. Silva 		/* extract the returned data length */
34312bdcf33SDavid Howells 	case 1:
34408e0e7c8SDavid Howells 		_debug("extract data length");
34512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
346372ee163SDavid Howells 		if (ret < 0)
347372ee163SDavid Howells 			return ret;
3481da177e4SLinus Torvalds 
34912bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
350196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
35112bdcf33SDavid Howells 		req->remain = min(req->len, req->actual_len);
35212bdcf33SDavid Howells 		if (req->remain == 0)
353196ee9cdSDavid Howells 			goto no_more_data;
35412bdcf33SDavid Howells 
35508e0e7c8SDavid Howells 		call->unmarshall++;
3561da177e4SLinus Torvalds 
357196ee9cdSDavid Howells 	begin_page:
3586db3ac3cSDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
35912bdcf33SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
36012bdcf33SDavid Howells 			size = PAGE_SIZE - req->offset;
361196ee9cdSDavid Howells 		else
362196ee9cdSDavid Howells 			size = req->remain;
36312bdcf33SDavid Howells 		call->bvec[0].bv_len = size;
36412bdcf33SDavid Howells 		call->bvec[0].bv_offset = req->offset;
36512bdcf33SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
366fc276122SDavid Howells 		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
36712bdcf33SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
36829881608SGustavo A. R. Silva 		/* Fall through */
369196ee9cdSDavid Howells 
37029881608SGustavo A. R. Silva 		/* extract the returned data */
37112bdcf33SDavid Howells 	case 2:
37212bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
373fc276122SDavid 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 */
39523a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
39612bdcf33SDavid Howells 		call->unmarshall = 3;
397e690c9e3SGustavo A. R. Silva 		/* Fall through */
39829881608SGustavo A. R. Silva 
39912bdcf33SDavid Howells 	case 3:
40012bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
401fc276122SDavid 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);
41029881608SGustavo A. R. Silva 		/* Fall through */
41108e0e7c8SDavid Howells 
41229881608SGustavo A. R. Silva 		/* extract the metadata */
41312bdcf33SDavid Howells 	case 4:
41412bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
415372ee163SDavid Howells 		if (ret < 0)
416372ee163SDavid Howells 			return ret;
4171da177e4SLinus Torvalds 
41808e0e7c8SDavid Howells 		bp = call->buffer;
419a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
420160cb957SDavid Howells 		if (ret < 0)
421160cb957SDavid Howells 			return ret;
422a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, call->out_scb);
423ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
4241da177e4SLinus Torvalds 
425a58823acSDavid Howells 		req->data_version = call->out_scb->status.data_version;
426a58823acSDavid Howells 		req->file_size = call->out_scb->status.size;
427a58823acSDavid Howells 
42808e0e7c8SDavid Howells 		call->unmarshall++;
4291da177e4SLinus Torvalds 
43012bdcf33SDavid Howells 	case 5:
4311da177e4SLinus Torvalds 		break;
4321da177e4SLinus Torvalds 	}
4331da177e4SLinus Torvalds 
4346db3ac3cSDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
43512bdcf33SDavid Howells 		if (req->offset < PAGE_SIZE)
4366db3ac3cSDavid Howells 			zero_user_segment(req->pages[req->index],
43712bdcf33SDavid Howells 					  req->offset, PAGE_SIZE);
438196ee9cdSDavid Howells 		if (req->page_done)
439a58823acSDavid Howells 			req->page_done(req);
44012bdcf33SDavid Howells 		req->offset = 0;
441416351f2SDavid Howells 	}
442416351f2SDavid Howells 
44308e0e7c8SDavid Howells 	_leave(" = 0 [done]");
44408e0e7c8SDavid Howells 	return 0;
445ec26815aSDavid Howells }
4461da177e4SLinus Torvalds 
447196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call)
448196ee9cdSDavid Howells {
449ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
450196ee9cdSDavid Howells 
451196ee9cdSDavid Howells 	afs_put_read(req);
452196ee9cdSDavid Howells 	afs_flat_call_destructor(call);
453196ee9cdSDavid Howells }
454196ee9cdSDavid Howells 
4551da177e4SLinus Torvalds /*
45608e0e7c8SDavid Howells  * FS.FetchData operation type
4571da177e4SLinus Torvalds  */
45808e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
45900d3b7a4SDavid Howells 	.name		= "FS.FetchData",
460025db80cSDavid Howells 	.op		= afs_FS_FetchData,
46108e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
462196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
46308e0e7c8SDavid Howells };
46408e0e7c8SDavid Howells 
465b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
466b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
467025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
468b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
469196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
470b9b1f8d5SDavid Howells };
471b9b1f8d5SDavid Howells 
472b9b1f8d5SDavid Howells /*
473b9b1f8d5SDavid Howells  * fetch data from a very large file
474b9b1f8d5SDavid Howells  */
475a58823acSDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc,
476a58823acSDavid Howells 			       struct afs_status_cb *scb,
477a58823acSDavid Howells 			       struct afs_read *req)
478b9b1f8d5SDavid Howells {
479d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
480b9b1f8d5SDavid Howells 	struct afs_call *call;
481f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
482b9b1f8d5SDavid Howells 	__be32 *bp;
483b9b1f8d5SDavid Howells 
484b9b1f8d5SDavid Howells 	_enter("");
485b9b1f8d5SDavid Howells 
486f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
487b9b1f8d5SDavid Howells 	if (!call)
488b9b1f8d5SDavid Howells 		return -ENOMEM;
489b9b1f8d5SDavid Howells 
490d2ddc776SDavid Howells 	call->key = fc->key;
491a58823acSDavid Howells 	call->out_scb = scb;
492ffba718eSDavid Howells 	call->out_volsync = NULL;
493d4438a25SDavid Howells 	call->read_request = afs_get_read(req);
494b9b1f8d5SDavid Howells 
495b9b1f8d5SDavid Howells 	/* marshall the parameters */
496b9b1f8d5SDavid Howells 	bp = call->request;
497b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
498b9b1f8d5SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
499b9b1f8d5SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
500b9b1f8d5SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
501196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
502196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
503b9b1f8d5SDavid Howells 	bp[6] = 0;
504196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
505b9b1f8d5SDavid Howells 
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;
542d4438a25SDavid Howells 	call->read_request = afs_get_read(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 
553d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
554025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
55520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5560b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5570b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
55808e0e7c8SDavid Howells }
559260a9803SDavid Howells 
560260a9803SDavid Howells /*
561260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
562260a9803SDavid Howells  */
563d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
564260a9803SDavid Howells {
565260a9803SDavid Howells 	const __be32 *bp;
566372ee163SDavid Howells 	int ret;
567260a9803SDavid Howells 
568d001648eSDavid Howells 	ret = afs_transfer_reply(call);
569372ee163SDavid Howells 	if (ret < 0)
570372ee163SDavid Howells 		return ret;
571260a9803SDavid Howells 
572260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
573260a9803SDavid Howells 	bp = call->buffer;
574ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
575a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
576160cb957SDavid Howells 	if (ret < 0)
577160cb957SDavid Howells 		return ret;
578a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
579160cb957SDavid Howells 	if (ret < 0)
580160cb957SDavid Howells 		return ret;
581a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
582ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
583260a9803SDavid Howells 
584260a9803SDavid Howells 	_leave(" = 0 [done]");
585260a9803SDavid Howells 	return 0;
586260a9803SDavid Howells }
587260a9803SDavid Howells 
588260a9803SDavid Howells /*
589260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
590260a9803SDavid Howells  */
591025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
592025db80cSDavid Howells 	.name		= "FS.CreateFile",
593025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
594025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
595025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
596025db80cSDavid Howells };
597025db80cSDavid Howells 
598025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
599025db80cSDavid Howells 	.name		= "FS.MakeDir",
600025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
601260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
602260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
603260a9803SDavid Howells };
604260a9803SDavid Howells 
605260a9803SDavid Howells /*
606260a9803SDavid Howells  * create a file or make a directory
607260a9803SDavid Howells  */
6088b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc,
609260a9803SDavid Howells 		  const char *name,
610260a9803SDavid Howells 		  umode_t mode,
611a58823acSDavid Howells 		  struct afs_status_cb *dvnode_scb,
612260a9803SDavid Howells 		  struct afs_fid *newfid,
613a58823acSDavid Howells 		  struct afs_status_cb *new_scb)
614260a9803SDavid Howells {
615ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
616260a9803SDavid Howells 	struct afs_call *call;
617ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
618260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
619260a9803SDavid Howells 	__be32 *bp;
620260a9803SDavid Howells 
62130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){
62230062bd1SDavid Howells 		if (S_ISDIR(mode))
623a58823acSDavid Howells 			return yfs_fs_make_dir(fc, name, mode, dvnode_scb,
624a58823acSDavid Howells 					       newfid, new_scb);
62530062bd1SDavid Howells 		else
626a58823acSDavid Howells 			return yfs_fs_create_file(fc, name, mode, dvnode_scb,
627a58823acSDavid Howells 						  newfid, new_scb);
62830062bd1SDavid Howells 	}
62930062bd1SDavid Howells 
630260a9803SDavid Howells 	_enter("");
631260a9803SDavid Howells 
632260a9803SDavid Howells 	namesz = strlen(name);
633260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
634260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
635260a9803SDavid Howells 
636025db80cSDavid Howells 	call = afs_alloc_flat_call(
637025db80cSDavid Howells 		net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
638025db80cSDavid Howells 		reqsz, (3 + 21 + 21 + 3 + 6) * 4);
639260a9803SDavid Howells 	if (!call)
640260a9803SDavid Howells 		return -ENOMEM;
641260a9803SDavid Howells 
642d2ddc776SDavid Howells 	call->key = fc->key;
643a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
644ffba718eSDavid Howells 	call->out_fid = newfid;
645a58823acSDavid Howells 	call->out_scb = new_scb;
646260a9803SDavid Howells 
647260a9803SDavid Howells 	/* marshall the parameters */
648260a9803SDavid Howells 	bp = call->request;
649260a9803SDavid Howells 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
650ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
651ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
652ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
653260a9803SDavid Howells 	*bp++ = htonl(namesz);
654260a9803SDavid Howells 	memcpy(bp, name, namesz);
655260a9803SDavid Howells 	bp = (void *) bp + namesz;
656260a9803SDavid Howells 	if (padsz > 0) {
657260a9803SDavid Howells 		memset(bp, 0, padsz);
658260a9803SDavid Howells 		bp = (void *) bp + padsz;
659260a9803SDavid Howells 	}
660ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
661ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
662260a9803SDavid Howells 	*bp++ = 0; /* owner */
663260a9803SDavid Howells 	*bp++ = 0; /* group */
664260a9803SDavid Howells 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
665260a9803SDavid Howells 	*bp++ = 0; /* segment size */
666260a9803SDavid Howells 
667d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
668ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
66920b8391fSDavid Howells 	afs_set_fc_call(call, fc);
6700b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
6710b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
672260a9803SDavid Howells }
673260a9803SDavid Howells 
674260a9803SDavid Howells /*
675ffba718eSDavid Howells  * Deliver reply data to any operation that returns directory status and volume
676b10494afSJoe Gorse  * sync.
677260a9803SDavid Howells  */
678ffba718eSDavid Howells static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call)
679260a9803SDavid Howells {
680260a9803SDavid Howells 	const __be32 *bp;
681372ee163SDavid Howells 	int ret;
682260a9803SDavid Howells 
683d001648eSDavid Howells 	ret = afs_transfer_reply(call);
684372ee163SDavid Howells 	if (ret < 0)
685372ee163SDavid Howells 		return ret;
686260a9803SDavid Howells 
687260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
688260a9803SDavid Howells 	bp = call->buffer;
689a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
690160cb957SDavid Howells 	if (ret < 0)
691160cb957SDavid Howells 		return ret;
692ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
693260a9803SDavid Howells 
694260a9803SDavid Howells 	_leave(" = 0 [done]");
695260a9803SDavid Howells 	return 0;
696260a9803SDavid Howells }
697260a9803SDavid Howells 
698260a9803SDavid Howells /*
699260a9803SDavid Howells  * FS.RemoveDir/FS.RemoveFile operation type
700260a9803SDavid Howells  */
701025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
702025db80cSDavid Howells 	.name		= "FS.RemoveFile",
703025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
704ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
705025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
706025db80cSDavid Howells };
707025db80cSDavid Howells 
708025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
709025db80cSDavid Howells 	.name		= "FS.RemoveDir",
710025db80cSDavid Howells 	.op		= afs_FS_RemoveDir,
711ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
712260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
713260a9803SDavid Howells };
714260a9803SDavid Howells 
715260a9803SDavid Howells /*
716260a9803SDavid Howells  * remove a file or directory
717260a9803SDavid Howells  */
71830062bd1SDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
719a58823acSDavid Howells 		  const char *name, bool isdir, struct afs_status_cb *dvnode_scb)
720260a9803SDavid Howells {
72130062bd1SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
722260a9803SDavid Howells 	struct afs_call *call;
72330062bd1SDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
724260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
725260a9803SDavid Howells 	__be32 *bp;
726260a9803SDavid Howells 
72730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
728a58823acSDavid Howells 		return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb);
72930062bd1SDavid Howells 
730260a9803SDavid Howells 	_enter("");
731260a9803SDavid Howells 
732260a9803SDavid Howells 	namesz = strlen(name);
733260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
734260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
735260a9803SDavid Howells 
736025db80cSDavid Howells 	call = afs_alloc_flat_call(
737025db80cSDavid Howells 		net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
738025db80cSDavid Howells 		reqsz, (21 + 6) * 4);
739260a9803SDavid Howells 	if (!call)
740260a9803SDavid Howells 		return -ENOMEM;
741260a9803SDavid Howells 
742d2ddc776SDavid Howells 	call->key = fc->key;
743a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
744260a9803SDavid Howells 
745260a9803SDavid Howells 	/* marshall the parameters */
746260a9803SDavid Howells 	bp = call->request;
747260a9803SDavid Howells 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
74830062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
74930062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
75030062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
751260a9803SDavid Howells 	*bp++ = htonl(namesz);
752260a9803SDavid Howells 	memcpy(bp, name, namesz);
753260a9803SDavid Howells 	bp = (void *) bp + namesz;
754260a9803SDavid Howells 	if (padsz > 0) {
755260a9803SDavid Howells 		memset(bp, 0, padsz);
756260a9803SDavid Howells 		bp = (void *) bp + padsz;
757260a9803SDavid Howells 	}
758260a9803SDavid Howells 
759d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
76080548b03SDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
76120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
7620b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
7630b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
764260a9803SDavid Howells }
765260a9803SDavid Howells 
766260a9803SDavid Howells /*
767260a9803SDavid Howells  * deliver reply data to an FS.Link
768260a9803SDavid Howells  */
769d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
770260a9803SDavid Howells {
771260a9803SDavid Howells 	const __be32 *bp;
772372ee163SDavid Howells 	int ret;
773260a9803SDavid Howells 
774d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
775260a9803SDavid Howells 
776d001648eSDavid Howells 	ret = afs_transfer_reply(call);
777372ee163SDavid Howells 	if (ret < 0)
778372ee163SDavid Howells 		return ret;
779260a9803SDavid Howells 
780260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
781260a9803SDavid Howells 	bp = call->buffer;
782a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
783160cb957SDavid Howells 	if (ret < 0)
784160cb957SDavid Howells 		return ret;
785a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
786160cb957SDavid Howells 	if (ret < 0)
787160cb957SDavid Howells 		return ret;
788ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
789260a9803SDavid Howells 
790260a9803SDavid Howells 	_leave(" = 0 [done]");
791260a9803SDavid Howells 	return 0;
792260a9803SDavid Howells }
793260a9803SDavid Howells 
794260a9803SDavid Howells /*
795260a9803SDavid Howells  * FS.Link operation type
796260a9803SDavid Howells  */
797260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
798260a9803SDavid Howells 	.name		= "FS.Link",
799025db80cSDavid Howells 	.op		= afs_FS_Link,
800260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
801260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
802260a9803SDavid Howells };
803260a9803SDavid Howells 
804260a9803SDavid Howells /*
805260a9803SDavid Howells  * make a hard link
806260a9803SDavid Howells  */
807d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
808a58823acSDavid Howells 		const char *name,
809a58823acSDavid Howells 		struct afs_status_cb *dvnode_scb,
810a58823acSDavid Howells 		struct afs_status_cb *vnode_scb)
811260a9803SDavid Howells {
812d2ddc776SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
813260a9803SDavid Howells 	struct afs_call *call;
814f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
815260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
816260a9803SDavid Howells 	__be32 *bp;
817260a9803SDavid Howells 
81830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
819a58823acSDavid Howells 		return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb);
82030062bd1SDavid Howells 
821260a9803SDavid Howells 	_enter("");
822260a9803SDavid Howells 
823260a9803SDavid Howells 	namesz = strlen(name);
824260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
825260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
826260a9803SDavid Howells 
827f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
828260a9803SDavid Howells 	if (!call)
829260a9803SDavid Howells 		return -ENOMEM;
830260a9803SDavid Howells 
831d2ddc776SDavid Howells 	call->key = fc->key;
832a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
833a58823acSDavid Howells 	call->out_scb = vnode_scb;
834260a9803SDavid Howells 
835260a9803SDavid Howells 	/* marshall the parameters */
836260a9803SDavid Howells 	bp = call->request;
837260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
838260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
839260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
840260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
841260a9803SDavid Howells 	*bp++ = htonl(namesz);
842260a9803SDavid Howells 	memcpy(bp, name, namesz);
843260a9803SDavid Howells 	bp = (void *) bp + namesz;
844260a9803SDavid Howells 	if (padsz > 0) {
845260a9803SDavid Howells 		memset(bp, 0, padsz);
846260a9803SDavid Howells 		bp = (void *) bp + padsz;
847260a9803SDavid Howells 	}
848260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
849260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
850260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
851260a9803SDavid Howells 
852d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
85380548b03SDavid Howells 	trace_afs_make_fs_call1(call, &vnode->fid, name);
85420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
8550b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
8560b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
857260a9803SDavid Howells }
858260a9803SDavid Howells 
859260a9803SDavid Howells /*
860260a9803SDavid Howells  * deliver reply data to an FS.Symlink
861260a9803SDavid Howells  */
862d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
863260a9803SDavid Howells {
864260a9803SDavid Howells 	const __be32 *bp;
865372ee163SDavid Howells 	int ret;
866260a9803SDavid Howells 
867d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
868260a9803SDavid Howells 
869d001648eSDavid Howells 	ret = afs_transfer_reply(call);
870372ee163SDavid Howells 	if (ret < 0)
871372ee163SDavid Howells 		return ret;
872260a9803SDavid Howells 
873260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
874260a9803SDavid Howells 	bp = call->buffer;
875ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
876a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
877160cb957SDavid Howells 	if (ret < 0)
878160cb957SDavid Howells 		return ret;
879a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
880160cb957SDavid Howells 	if (ret < 0)
881160cb957SDavid Howells 		return ret;
882ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
883260a9803SDavid Howells 
884260a9803SDavid Howells 	_leave(" = 0 [done]");
885260a9803SDavid Howells 	return 0;
886260a9803SDavid Howells }
887260a9803SDavid Howells 
888260a9803SDavid Howells /*
889260a9803SDavid Howells  * FS.Symlink operation type
890260a9803SDavid Howells  */
891260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
892260a9803SDavid Howells 	.name		= "FS.Symlink",
893025db80cSDavid Howells 	.op		= afs_FS_Symlink,
894260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
895260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
896260a9803SDavid Howells };
897260a9803SDavid Howells 
898260a9803SDavid Howells /*
899260a9803SDavid Howells  * create a symbolic link
900260a9803SDavid Howells  */
9018b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc,
902260a9803SDavid Howells 		   const char *name,
903260a9803SDavid Howells 		   const char *contents,
904a58823acSDavid Howells 		   struct afs_status_cb *dvnode_scb,
905260a9803SDavid Howells 		   struct afs_fid *newfid,
906a58823acSDavid Howells 		   struct afs_status_cb *new_scb)
907260a9803SDavid Howells {
908ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
909260a9803SDavid Howells 	struct afs_call *call;
910ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
911260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
912260a9803SDavid Howells 	__be32 *bp;
913260a9803SDavid Howells 
91430062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
915a58823acSDavid Howells 		return yfs_fs_symlink(fc, name, contents, dvnode_scb,
916a58823acSDavid Howells 				      newfid, new_scb);
91730062bd1SDavid Howells 
918260a9803SDavid Howells 	_enter("");
919260a9803SDavid Howells 
920260a9803SDavid Howells 	namesz = strlen(name);
921260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
922260a9803SDavid Howells 
923260a9803SDavid Howells 	c_namesz = strlen(contents);
924260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
925260a9803SDavid Howells 
926260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
927260a9803SDavid Howells 
928f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
929260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
930260a9803SDavid Howells 	if (!call)
931260a9803SDavid Howells 		return -ENOMEM;
932260a9803SDavid Howells 
933d2ddc776SDavid Howells 	call->key = fc->key;
934a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
935ffba718eSDavid Howells 	call->out_fid = newfid;
936a58823acSDavid Howells 	call->out_scb = new_scb;
937260a9803SDavid Howells 
938260a9803SDavid Howells 	/* marshall the parameters */
939260a9803SDavid Howells 	bp = call->request;
940260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
941ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
942ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
943ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
944260a9803SDavid Howells 	*bp++ = htonl(namesz);
945260a9803SDavid Howells 	memcpy(bp, name, namesz);
946260a9803SDavid Howells 	bp = (void *) bp + namesz;
947260a9803SDavid Howells 	if (padsz > 0) {
948260a9803SDavid Howells 		memset(bp, 0, padsz);
949260a9803SDavid Howells 		bp = (void *) bp + padsz;
950260a9803SDavid Howells 	}
951260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
952260a9803SDavid Howells 	memcpy(bp, contents, c_namesz);
953260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
954260a9803SDavid Howells 	if (c_padsz > 0) {
955260a9803SDavid Howells 		memset(bp, 0, c_padsz);
956260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
957260a9803SDavid Howells 	}
958ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
959ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
960260a9803SDavid Howells 	*bp++ = 0; /* owner */
961260a9803SDavid Howells 	*bp++ = 0; /* group */
962260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
963260a9803SDavid Howells 	*bp++ = 0; /* segment size */
964260a9803SDavid Howells 
965d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
966ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
96720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
9680b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
9690b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
970260a9803SDavid Howells }
971260a9803SDavid Howells 
972260a9803SDavid Howells /*
973260a9803SDavid Howells  * deliver reply data to an FS.Rename
974260a9803SDavid Howells  */
975d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
976260a9803SDavid Howells {
977260a9803SDavid Howells 	const __be32 *bp;
978372ee163SDavid Howells 	int ret;
979260a9803SDavid Howells 
980d001648eSDavid Howells 	ret = afs_transfer_reply(call);
981372ee163SDavid Howells 	if (ret < 0)
982372ee163SDavid Howells 		return ret;
983260a9803SDavid Howells 
984260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
985260a9803SDavid Howells 	bp = call->buffer;
986a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
987160cb957SDavid Howells 	if (ret < 0)
988160cb957SDavid Howells 		return ret;
989a58823acSDavid Howells 	if (call->out_dir_scb != call->out_scb) {
990a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
991160cb957SDavid Howells 		if (ret < 0)
992160cb957SDavid Howells 			return ret;
993160cb957SDavid Howells 	}
994ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
995260a9803SDavid Howells 
996260a9803SDavid Howells 	_leave(" = 0 [done]");
997260a9803SDavid Howells 	return 0;
998260a9803SDavid Howells }
999260a9803SDavid Howells 
1000260a9803SDavid Howells /*
1001260a9803SDavid Howells  * FS.Rename operation type
1002260a9803SDavid Howells  */
1003260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
1004260a9803SDavid Howells 	.name		= "FS.Rename",
1005025db80cSDavid Howells 	.op		= afs_FS_Rename,
1006260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
1007260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
1008260a9803SDavid Howells };
1009260a9803SDavid Howells 
1010260a9803SDavid Howells /*
1011a58823acSDavid Howells  * Rename/move a file or directory.
1012260a9803SDavid Howells  */
10138b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc,
1014260a9803SDavid Howells 		  const char *orig_name,
1015260a9803SDavid Howells 		  struct afs_vnode *new_dvnode,
101663a4681fSDavid Howells 		  const char *new_name,
1017a58823acSDavid Howells 		  struct afs_status_cb *orig_dvnode_scb,
1018a58823acSDavid Howells 		  struct afs_status_cb *new_dvnode_scb)
1019260a9803SDavid Howells {
1020d2ddc776SDavid Howells 	struct afs_vnode *orig_dvnode = fc->vnode;
1021260a9803SDavid Howells 	struct afs_call *call;
1022f044c884SDavid Howells 	struct afs_net *net = afs_v2net(orig_dvnode);
1023260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1024260a9803SDavid Howells 	__be32 *bp;
1025260a9803SDavid Howells 
102630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
102730062bd1SDavid Howells 		return yfs_fs_rename(fc, orig_name,
102830062bd1SDavid Howells 				     new_dvnode, new_name,
1029a58823acSDavid Howells 				     orig_dvnode_scb,
1030a58823acSDavid Howells 				     new_dvnode_scb);
103130062bd1SDavid Howells 
1032260a9803SDavid Howells 	_enter("");
1033260a9803SDavid Howells 
1034260a9803SDavid Howells 	o_namesz = strlen(orig_name);
1035260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
1036260a9803SDavid Howells 
1037260a9803SDavid Howells 	n_namesz = strlen(new_name);
1038260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
1039260a9803SDavid Howells 
1040260a9803SDavid Howells 	reqsz = (4 * 4) +
1041260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1042260a9803SDavid Howells 		(3 * 4) +
1043260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1044260a9803SDavid Howells 
1045f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1046260a9803SDavid Howells 	if (!call)
1047260a9803SDavid Howells 		return -ENOMEM;
1048260a9803SDavid Howells 
1049d2ddc776SDavid Howells 	call->key = fc->key;
1050a58823acSDavid Howells 	call->out_dir_scb = orig_dvnode_scb;
1051a58823acSDavid Howells 	call->out_scb = new_dvnode_scb;
1052260a9803SDavid Howells 
1053260a9803SDavid Howells 	/* marshall the parameters */
1054260a9803SDavid Howells 	bp = call->request;
1055260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1056260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vid);
1057260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vnode);
1058260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.unique);
1059260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1060260a9803SDavid Howells 	memcpy(bp, orig_name, o_namesz);
1061260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1062260a9803SDavid Howells 	if (o_padsz > 0) {
1063260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1064260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1065260a9803SDavid Howells 	}
1066260a9803SDavid Howells 
1067260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vid);
1068260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vnode);
1069260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.unique);
1070260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1071260a9803SDavid Howells 	memcpy(bp, new_name, n_namesz);
1072260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1073260a9803SDavid Howells 	if (n_padsz > 0) {
1074260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1075260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1076260a9803SDavid Howells 	}
1077260a9803SDavid Howells 
1078d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
107980548b03SDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
108020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
10810b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
10820b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1083260a9803SDavid Howells }
108431143d5dSDavid Howells 
108531143d5dSDavid Howells /*
108631143d5dSDavid Howells  * deliver reply data to an FS.StoreData
108731143d5dSDavid Howells  */
1088d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
108931143d5dSDavid Howells {
109031143d5dSDavid Howells 	const __be32 *bp;
1091372ee163SDavid Howells 	int ret;
109231143d5dSDavid Howells 
1093d001648eSDavid Howells 	_enter("");
109431143d5dSDavid Howells 
1095d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1096372ee163SDavid Howells 	if (ret < 0)
1097372ee163SDavid Howells 		return ret;
109831143d5dSDavid Howells 
109931143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
110031143d5dSDavid Howells 	bp = call->buffer;
1101a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1102160cb957SDavid Howells 	if (ret < 0)
1103160cb957SDavid Howells 		return ret;
1104ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
110531143d5dSDavid Howells 
110631143d5dSDavid Howells 	_leave(" = 0 [done]");
110731143d5dSDavid Howells 	return 0;
110831143d5dSDavid Howells }
110931143d5dSDavid Howells 
111031143d5dSDavid Howells /*
111131143d5dSDavid Howells  * FS.StoreData operation type
111231143d5dSDavid Howells  */
111331143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
111431143d5dSDavid Howells 	.name		= "FS.StoreData",
1115025db80cSDavid Howells 	.op		= afs_FS_StoreData,
111631143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
111731143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
111831143d5dSDavid Howells };
111931143d5dSDavid Howells 
1120b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1121b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1122025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1123b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1124b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1125b9b1f8d5SDavid Howells };
1126b9b1f8d5SDavid Howells 
1127b9b1f8d5SDavid Howells /*
1128b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1129b9b1f8d5SDavid Howells  */
11308b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc,
11314343d008SDavid Howells 			       struct address_space *mapping,
1132b9b1f8d5SDavid Howells 			       pgoff_t first, pgoff_t last,
1133b9b1f8d5SDavid Howells 			       unsigned offset, unsigned to,
1134a58823acSDavid Howells 			       loff_t size, loff_t pos, loff_t i_size,
1135a58823acSDavid Howells 			       struct afs_status_cb *scb)
1136b9b1f8d5SDavid Howells {
11374343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1138b9b1f8d5SDavid Howells 	struct afs_call *call;
1139f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1140b9b1f8d5SDavid Howells 	__be32 *bp;
1141b9b1f8d5SDavid Howells 
11423b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
11434343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1144b9b1f8d5SDavid Howells 
1145f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
1146b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1147b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1148b9b1f8d5SDavid Howells 	if (!call)
1149b9b1f8d5SDavid Howells 		return -ENOMEM;
1150b9b1f8d5SDavid Howells 
11514343d008SDavid Howells 	call->key = fc->key;
11524343d008SDavid Howells 	call->mapping = mapping;
1153b9b1f8d5SDavid Howells 	call->first = first;
1154b9b1f8d5SDavid Howells 	call->last = last;
1155b9b1f8d5SDavid Howells 	call->first_offset = offset;
1156b9b1f8d5SDavid Howells 	call->last_to = to;
1157b9b1f8d5SDavid Howells 	call->send_pages = true;
1158a58823acSDavid Howells 	call->out_scb = scb;
1159b9b1f8d5SDavid Howells 
1160b9b1f8d5SDavid Howells 	/* marshall the parameters */
1161b9b1f8d5SDavid Howells 	bp = call->request;
1162b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1163b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1164b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1165b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1166b9b1f8d5SDavid Howells 
1167ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1168ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1169b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1170b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1171b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1172b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1173b9b1f8d5SDavid Howells 
1174b9b1f8d5SDavid Howells 	*bp++ = htonl(pos >> 32);
1175b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) pos);
1176b9b1f8d5SDavid Howells 	*bp++ = htonl(size >> 32);
1177b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) size);
1178b9b1f8d5SDavid Howells 	*bp++ = htonl(i_size >> 32);
1179b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) i_size);
1180b9b1f8d5SDavid Howells 
1181025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
118220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
11830b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
11840b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1185b9b1f8d5SDavid Howells }
1186b9b1f8d5SDavid Howells 
118731143d5dSDavid Howells /*
118831143d5dSDavid Howells  * store a set of pages
118931143d5dSDavid Howells  */
11904343d008SDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
119131143d5dSDavid Howells 		      pgoff_t first, pgoff_t last,
1192a58823acSDavid Howells 		      unsigned offset, unsigned to,
1193a58823acSDavid Howells 		      struct afs_status_cb *scb)
119431143d5dSDavid Howells {
11954343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
119631143d5dSDavid Howells 	struct afs_call *call;
1197f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
119831143d5dSDavid Howells 	loff_t size, pos, i_size;
119931143d5dSDavid Howells 	__be32 *bp;
120031143d5dSDavid Howells 
120130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1202a58823acSDavid Howells 		return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb);
120330062bd1SDavid Howells 
12043b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
12054343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
120631143d5dSDavid Howells 
1207146a1192SDavid Howells 	size = (loff_t)to - (loff_t)offset;
120831143d5dSDavid Howells 	if (first != last)
120931143d5dSDavid Howells 		size += (loff_t)(last - first) << PAGE_SHIFT;
121031143d5dSDavid Howells 	pos = (loff_t)first << PAGE_SHIFT;
121131143d5dSDavid Howells 	pos += offset;
121231143d5dSDavid Howells 
121331143d5dSDavid Howells 	i_size = i_size_read(&vnode->vfs_inode);
121431143d5dSDavid Howells 	if (pos + size > i_size)
121531143d5dSDavid Howells 		i_size = size + pos;
121631143d5dSDavid Howells 
121731143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
121831143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
121931143d5dSDavid Howells 	       (unsigned long long) i_size);
122031143d5dSDavid Howells 
1221b9b1f8d5SDavid Howells 	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
12224343d008SDavid Howells 		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
1223a58823acSDavid Howells 					   size, pos, i_size, scb);
122431143d5dSDavid Howells 
1225f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
122631143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
122731143d5dSDavid Howells 				   (21 + 6) * 4);
122831143d5dSDavid Howells 	if (!call)
122931143d5dSDavid Howells 		return -ENOMEM;
123031143d5dSDavid Howells 
12314343d008SDavid Howells 	call->key = fc->key;
12324343d008SDavid Howells 	call->mapping = mapping;
123331143d5dSDavid Howells 	call->first = first;
123431143d5dSDavid Howells 	call->last = last;
123531143d5dSDavid Howells 	call->first_offset = offset;
123631143d5dSDavid Howells 	call->last_to = to;
123731143d5dSDavid Howells 	call->send_pages = true;
1238a58823acSDavid Howells 	call->out_scb = scb;
123931143d5dSDavid Howells 
124031143d5dSDavid Howells 	/* marshall the parameters */
124131143d5dSDavid Howells 	bp = call->request;
124231143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
124331143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
124431143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
124531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
124631143d5dSDavid Howells 
1247ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1248ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
124931143d5dSDavid Howells 	*bp++ = 0; /* owner */
125031143d5dSDavid Howells 	*bp++ = 0; /* group */
125131143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
125231143d5dSDavid Howells 	*bp++ = 0; /* segment size */
125331143d5dSDavid Howells 
125431143d5dSDavid Howells 	*bp++ = htonl(pos);
125531143d5dSDavid Howells 	*bp++ = htonl(size);
125631143d5dSDavid Howells 	*bp++ = htonl(i_size);
125731143d5dSDavid Howells 
1258d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1259025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
126020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
12610b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
12620b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
126331143d5dSDavid Howells }
126431143d5dSDavid Howells 
126531143d5dSDavid Howells /*
126631143d5dSDavid Howells  * deliver reply data to an FS.StoreStatus
126731143d5dSDavid Howells  */
1268d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call)
126931143d5dSDavid Howells {
127031143d5dSDavid Howells 	const __be32 *bp;
1271372ee163SDavid Howells 	int ret;
127231143d5dSDavid Howells 
1273d001648eSDavid Howells 	_enter("");
127431143d5dSDavid Howells 
1275d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1276372ee163SDavid Howells 	if (ret < 0)
1277372ee163SDavid Howells 		return ret;
127831143d5dSDavid Howells 
127931143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
128031143d5dSDavid Howells 	bp = call->buffer;
1281a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1282160cb957SDavid Howells 	if (ret < 0)
1283160cb957SDavid Howells 		return ret;
1284ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
128531143d5dSDavid Howells 
128631143d5dSDavid Howells 	_leave(" = 0 [done]");
128731143d5dSDavid Howells 	return 0;
128831143d5dSDavid Howells }
128931143d5dSDavid Howells 
129031143d5dSDavid Howells /*
129131143d5dSDavid Howells  * FS.StoreStatus operation type
129231143d5dSDavid Howells  */
129331143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
129431143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1295025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
129631143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
129731143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
129831143d5dSDavid Howells };
129931143d5dSDavid Howells 
130031143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
130131143d5dSDavid Howells 	.name		= "FS.StoreData",
1302025db80cSDavid Howells 	.op		= afs_FS_StoreData,
130331143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130431143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
130531143d5dSDavid Howells };
130631143d5dSDavid Howells 
1307b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1308b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1309025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1310b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_status,
1311b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1312b9b1f8d5SDavid Howells };
1313b9b1f8d5SDavid Howells 
1314b9b1f8d5SDavid Howells /*
1315b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1316b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1317b9b1f8d5SDavid Howells  */
1318a58823acSDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr,
1319a58823acSDavid Howells 				 struct afs_status_cb *scb)
1320b9b1f8d5SDavid Howells {
1321d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1322b9b1f8d5SDavid Howells 	struct afs_call *call;
1323f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1324b9b1f8d5SDavid Howells 	__be32 *bp;
1325b9b1f8d5SDavid Howells 
13263b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1327d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1328b9b1f8d5SDavid Howells 
1329b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1330b9b1f8d5SDavid Howells 
1331f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
1332b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1333b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1334b9b1f8d5SDavid Howells 	if (!call)
1335b9b1f8d5SDavid Howells 		return -ENOMEM;
1336b9b1f8d5SDavid Howells 
1337d2ddc776SDavid Howells 	call->key = fc->key;
1338a58823acSDavid Howells 	call->out_scb = scb;
1339b9b1f8d5SDavid Howells 
1340b9b1f8d5SDavid Howells 	/* marshall the parameters */
1341b9b1f8d5SDavid Howells 	bp = call->request;
1342b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1343b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1344b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1345b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1346b9b1f8d5SDavid Howells 
1347b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1348b9b1f8d5SDavid Howells 
13498c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* position of start of write */
13508c7ae38dSDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1351b9b1f8d5SDavid Howells 	*bp++ = 0;				/* size of write */
1352b9b1f8d5SDavid Howells 	*bp++ = 0;
1353b9b1f8d5SDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
1354b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1355b9b1f8d5SDavid Howells 
1356d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1357025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
135820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
13590b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
13600b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1361b9b1f8d5SDavid Howells }
1362b9b1f8d5SDavid Howells 
136331143d5dSDavid Howells /*
136431143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
136531143d5dSDavid Howells  * so as to alter the file size also
136631143d5dSDavid Howells  */
1367a58823acSDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
1368a58823acSDavid Howells 			       struct afs_status_cb *scb)
136931143d5dSDavid Howells {
1370d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
137131143d5dSDavid Howells 	struct afs_call *call;
1372f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
137331143d5dSDavid Howells 	__be32 *bp;
137431143d5dSDavid Howells 
13753b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1376d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
137731143d5dSDavid Howells 
137831143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1379b9b1f8d5SDavid Howells 	if (attr->ia_size >> 32)
1380a58823acSDavid Howells 		return afs_fs_setattr_size64(fc, attr, scb);
138131143d5dSDavid Howells 
1382f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
138331143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
138431143d5dSDavid Howells 				   (21 + 6) * 4);
138531143d5dSDavid Howells 	if (!call)
138631143d5dSDavid Howells 		return -ENOMEM;
138731143d5dSDavid Howells 
1388d2ddc776SDavid Howells 	call->key = fc->key;
1389a58823acSDavid Howells 	call->out_scb = scb;
139031143d5dSDavid Howells 
139131143d5dSDavid Howells 	/* marshall the parameters */
139231143d5dSDavid Howells 	bp = call->request;
139331143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
139431143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
139531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
139631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
139731143d5dSDavid Howells 
139831143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
139931143d5dSDavid Howells 
14008c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
140131143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
140231143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
140331143d5dSDavid Howells 
1404d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1405025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
140620b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14070b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14080b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
140931143d5dSDavid Howells }
141031143d5dSDavid Howells 
141131143d5dSDavid Howells /*
141231143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
141331143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
141431143d5dSDavid Howells  */
1415a58823acSDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
1416a58823acSDavid Howells 		   struct afs_status_cb *scb)
141731143d5dSDavid Howells {
1418d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
141931143d5dSDavid Howells 	struct afs_call *call;
1420f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
142131143d5dSDavid Howells 	__be32 *bp;
142231143d5dSDavid Howells 
142330062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1424a58823acSDavid Howells 		return yfs_fs_setattr(fc, attr, scb);
142530062bd1SDavid Howells 
142631143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1427a58823acSDavid Howells 		return afs_fs_setattr_size(fc, attr, scb);
142831143d5dSDavid Howells 
14293b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1430d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
143131143d5dSDavid Howells 
1432f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
143331143d5dSDavid Howells 				   (4 + 6) * 4,
143431143d5dSDavid Howells 				   (21 + 6) * 4);
143531143d5dSDavid Howells 	if (!call)
143631143d5dSDavid Howells 		return -ENOMEM;
143731143d5dSDavid Howells 
1438d2ddc776SDavid Howells 	call->key = fc->key;
1439a58823acSDavid Howells 	call->out_scb = scb;
144031143d5dSDavid Howells 
144131143d5dSDavid Howells 	/* marshall the parameters */
144231143d5dSDavid Howells 	bp = call->request;
144331143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
144431143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
144531143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
144631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
144731143d5dSDavid Howells 
144831143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
144931143d5dSDavid Howells 
1450d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1451025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
145220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14530b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14540b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
145531143d5dSDavid Howells }
145645222b9eSDavid Howells 
145745222b9eSDavid Howells /*
145845222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
145945222b9eSDavid Howells  */
1460d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
146145222b9eSDavid Howells {
146245222b9eSDavid Howells 	const __be32 *bp;
146345222b9eSDavid Howells 	char *p;
146412bdcf33SDavid Howells 	u32 size;
146545222b9eSDavid Howells 	int ret;
146645222b9eSDavid Howells 
1467d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
146845222b9eSDavid Howells 
146945222b9eSDavid Howells 	switch (call->unmarshall) {
147045222b9eSDavid Howells 	case 0:
147145222b9eSDavid Howells 		call->unmarshall++;
147212bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
147329881608SGustavo A. R. Silva 		/* Fall through */
147445222b9eSDavid Howells 
147529881608SGustavo A. R. Silva 		/* 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);
148629881608SGustavo A. R. Silva 		/* Fall through */
148745222b9eSDavid Howells 
148829881608SGustavo A. R. Silva 		/* extract the volume name length */
148945222b9eSDavid Howells 	case 2:
149012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1491372ee163SDavid Howells 		if (ret < 0)
1492372ee163SDavid Howells 			return ret;
149345222b9eSDavid Howells 
149445222b9eSDavid Howells 		call->count = ntohl(call->tmp);
149545222b9eSDavid Howells 		_debug("volname length: %u", call->count);
149645222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1497160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1498160cb957SDavid Howells 						  afs_eproto_volname_len);
149912bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1500ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
150145222b9eSDavid Howells 		call->unmarshall++;
150229881608SGustavo A. R. Silva 		/* Fall through */
150345222b9eSDavid Howells 
150429881608SGustavo A. R. Silva 		/* extract the volume name */
150545222b9eSDavid Howells 	case 3:
150645222b9eSDavid Howells 		_debug("extract volname");
150712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1508372ee163SDavid Howells 		if (ret < 0)
1509372ee163SDavid Howells 			return ret;
151045222b9eSDavid Howells 
1511ffba718eSDavid Howells 		p = call->buffer;
151245222b9eSDavid Howells 		p[call->count] = 0;
151345222b9eSDavid Howells 		_debug("volname '%s'", p);
151412bdcf33SDavid Howells 		afs_extract_to_tmp(call);
151545222b9eSDavid Howells 		call->unmarshall++;
151629881608SGustavo A. R. Silva 		/* Fall through */
151745222b9eSDavid Howells 
151829881608SGustavo A. R. Silva 		/* extract the offline message length */
151912bdcf33SDavid Howells 	case 4:
152012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1521372ee163SDavid Howells 		if (ret < 0)
1522372ee163SDavid Howells 			return ret;
152345222b9eSDavid Howells 
152445222b9eSDavid Howells 		call->count = ntohl(call->tmp);
152545222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
152645222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1527160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1528160cb957SDavid Howells 						  afs_eproto_offline_msg_len);
152912bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1530ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
153145222b9eSDavid Howells 		call->unmarshall++;
153229881608SGustavo A. R. Silva 		/* Fall through */
153345222b9eSDavid Howells 
153429881608SGustavo A. R. Silva 		/* extract the offline message */
153512bdcf33SDavid Howells 	case 5:
153645222b9eSDavid Howells 		_debug("extract offline");
153712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1538372ee163SDavid Howells 		if (ret < 0)
1539372ee163SDavid Howells 			return ret;
154045222b9eSDavid Howells 
1541ffba718eSDavid Howells 		p = call->buffer;
154245222b9eSDavid Howells 		p[call->count] = 0;
154345222b9eSDavid Howells 		_debug("offline '%s'", p);
154445222b9eSDavid Howells 
154512bdcf33SDavid Howells 		afs_extract_to_tmp(call);
154645222b9eSDavid Howells 		call->unmarshall++;
154729881608SGustavo A. R. Silva 		/* Fall through */
154845222b9eSDavid Howells 
154929881608SGustavo A. R. Silva 		/* extract the message of the day length */
155012bdcf33SDavid Howells 	case 6:
155112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1552372ee163SDavid Howells 		if (ret < 0)
1553372ee163SDavid Howells 			return ret;
155445222b9eSDavid Howells 
155545222b9eSDavid Howells 		call->count = ntohl(call->tmp);
155645222b9eSDavid Howells 		_debug("motd length: %u", call->count);
155745222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1558160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1559160cb957SDavid Howells 						  afs_eproto_motd_len);
156012bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1561ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
156245222b9eSDavid Howells 		call->unmarshall++;
156329881608SGustavo A. R. Silva 		/* Fall through */
156445222b9eSDavid Howells 
156529881608SGustavo A. R. Silva 		/* extract the message of the day */
156612bdcf33SDavid Howells 	case 7:
156745222b9eSDavid Howells 		_debug("extract motd");
156812bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1569372ee163SDavid Howells 		if (ret < 0)
1570372ee163SDavid Howells 			return ret;
157145222b9eSDavid Howells 
1572ffba718eSDavid Howells 		p = call->buffer;
157345222b9eSDavid Howells 		p[call->count] = 0;
157445222b9eSDavid Howells 		_debug("motd '%s'", p);
157545222b9eSDavid Howells 
157645222b9eSDavid Howells 		call->unmarshall++;
157745222b9eSDavid Howells 
157812bdcf33SDavid Howells 	case 8:
157945222b9eSDavid Howells 		break;
158045222b9eSDavid Howells 	}
158145222b9eSDavid Howells 
158245222b9eSDavid Howells 	_leave(" = 0 [done]");
158345222b9eSDavid Howells 	return 0;
158445222b9eSDavid Howells }
158545222b9eSDavid Howells 
158645222b9eSDavid Howells /*
158745222b9eSDavid Howells  * FS.GetVolumeStatus operation type
158845222b9eSDavid Howells  */
158945222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
159045222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1591025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
159245222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1593ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
159445222b9eSDavid Howells };
159545222b9eSDavid Howells 
159645222b9eSDavid Howells /*
159745222b9eSDavid Howells  * fetch the status of a volume
159845222b9eSDavid Howells  */
15998b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
1600d2ddc776SDavid Howells 			     struct afs_volume_status *vs)
160145222b9eSDavid Howells {
1602d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
160345222b9eSDavid Howells 	struct afs_call *call;
1604f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
160545222b9eSDavid Howells 	__be32 *bp;
160645222b9eSDavid Howells 
160730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
160830062bd1SDavid Howells 		return yfs_fs_get_volume_status(fc, vs);
160930062bd1SDavid Howells 
161045222b9eSDavid Howells 	_enter("");
161145222b9eSDavid Howells 
1612ffba718eSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4,
1613ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1614ffba718eSDavid Howells 	if (!call)
161545222b9eSDavid Howells 		return -ENOMEM;
161645222b9eSDavid Howells 
1617d2ddc776SDavid Howells 	call->key = fc->key;
1618ffba718eSDavid Howells 	call->out_volstatus = vs;
161945222b9eSDavid Howells 
162045222b9eSDavid Howells 	/* marshall the parameters */
162145222b9eSDavid Howells 	bp = call->request;
162245222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
162345222b9eSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
162445222b9eSDavid Howells 
1625d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1626025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
162720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
16280b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
16290b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
163045222b9eSDavid Howells }
1631e8d6c554SDavid Howells 
1632e8d6c554SDavid Howells /*
1633e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1634e8d6c554SDavid Howells  */
1635d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1636e8d6c554SDavid Howells {
1637e8d6c554SDavid Howells 	const __be32 *bp;
1638372ee163SDavid Howells 	int ret;
1639e8d6c554SDavid Howells 
1640d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1641e8d6c554SDavid Howells 
1642d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1643372ee163SDavid Howells 	if (ret < 0)
1644372ee163SDavid Howells 		return ret;
1645e8d6c554SDavid Howells 
1646e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1647e8d6c554SDavid Howells 	bp = call->buffer;
1648ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
1649e8d6c554SDavid Howells 
1650e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1651e8d6c554SDavid Howells 	return 0;
1652e8d6c554SDavid Howells }
1653e8d6c554SDavid Howells 
1654e8d6c554SDavid Howells /*
1655e8d6c554SDavid Howells  * FS.SetLock operation type
1656e8d6c554SDavid Howells  */
1657e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1658e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1659025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1660e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1661a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1662e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1663e8d6c554SDavid Howells };
1664e8d6c554SDavid Howells 
1665e8d6c554SDavid Howells /*
1666e8d6c554SDavid Howells  * FS.ExtendLock operation type
1667e8d6c554SDavid Howells  */
1668e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1669e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1670025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1671e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1672a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1673e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1674e8d6c554SDavid Howells };
1675e8d6c554SDavid Howells 
1676e8d6c554SDavid Howells /*
1677e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1678e8d6c554SDavid Howells  */
1679e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1680e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1681025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1682e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1683e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1684e8d6c554SDavid Howells };
1685e8d6c554SDavid Howells 
1686e8d6c554SDavid Howells /*
1687d2ddc776SDavid Howells  * Set a lock on a file
1688e8d6c554SDavid Howells  */
1689a58823acSDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
1690a58823acSDavid Howells 		    struct afs_status_cb *scb)
1691e8d6c554SDavid Howells {
1692d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1693e8d6c554SDavid Howells 	struct afs_call *call;
1694f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1695e8d6c554SDavid Howells 	__be32 *bp;
1696e8d6c554SDavid Howells 
169730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1698a58823acSDavid Howells 		return yfs_fs_set_lock(fc, type, scb);
169930062bd1SDavid Howells 
1700e8d6c554SDavid Howells 	_enter("");
1701e8d6c554SDavid Howells 
1702f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1703e8d6c554SDavid Howells 	if (!call)
1704e8d6c554SDavid Howells 		return -ENOMEM;
1705e8d6c554SDavid Howells 
1706d2ddc776SDavid Howells 	call->key = fc->key;
1707a58823acSDavid Howells 	call->lvnode = vnode;
1708a58823acSDavid Howells 	call->out_scb = scb;
1709e8d6c554SDavid Howells 
1710e8d6c554SDavid Howells 	/* marshall the parameters */
1711e8d6c554SDavid Howells 	bp = call->request;
1712e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1713e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1714e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1715e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1716e8d6c554SDavid Howells 	*bp++ = htonl(type);
1717e8d6c554SDavid Howells 
1718d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
17196c6c1d63SDavid Howells 	trace_afs_make_fs_calli(call, &vnode->fid, type);
172020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17210b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17220b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1723e8d6c554SDavid Howells }
1724e8d6c554SDavid Howells 
1725e8d6c554SDavid Howells /*
1726e8d6c554SDavid Howells  * extend a lock on a file
1727e8d6c554SDavid Howells  */
1728a58823acSDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1729e8d6c554SDavid Howells {
1730d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1731e8d6c554SDavid Howells 	struct afs_call *call;
1732f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1733e8d6c554SDavid Howells 	__be32 *bp;
1734e8d6c554SDavid Howells 
173530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1736a58823acSDavid Howells 		return yfs_fs_extend_lock(fc, scb);
173730062bd1SDavid Howells 
1738e8d6c554SDavid Howells 	_enter("");
1739e8d6c554SDavid Howells 
1740f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1741e8d6c554SDavid Howells 	if (!call)
1742e8d6c554SDavid Howells 		return -ENOMEM;
1743e8d6c554SDavid Howells 
1744d2ddc776SDavid Howells 	call->key = fc->key;
1745a58823acSDavid Howells 	call->lvnode = vnode;
1746a58823acSDavid Howells 	call->out_scb = scb;
1747e8d6c554SDavid Howells 
1748e8d6c554SDavid Howells 	/* marshall the parameters */
1749e8d6c554SDavid Howells 	bp = call->request;
1750e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1751e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1752e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1753e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1754e8d6c554SDavid Howells 
1755d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1756025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
175720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17580b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17590b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1760e8d6c554SDavid Howells }
1761e8d6c554SDavid Howells 
1762e8d6c554SDavid Howells /*
1763e8d6c554SDavid Howells  * release a lock on a file
1764e8d6c554SDavid Howells  */
1765a58823acSDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1766e8d6c554SDavid Howells {
1767d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1768e8d6c554SDavid Howells 	struct afs_call *call;
1769f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1770e8d6c554SDavid Howells 	__be32 *bp;
1771e8d6c554SDavid Howells 
177230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1773a58823acSDavid Howells 		return yfs_fs_release_lock(fc, scb);
177430062bd1SDavid Howells 
1775e8d6c554SDavid Howells 	_enter("");
1776e8d6c554SDavid Howells 
1777f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1778e8d6c554SDavid Howells 	if (!call)
1779e8d6c554SDavid Howells 		return -ENOMEM;
1780e8d6c554SDavid Howells 
1781d2ddc776SDavid Howells 	call->key = fc->key;
1782a58823acSDavid Howells 	call->lvnode = vnode;
1783a58823acSDavid Howells 	call->out_scb = scb;
1784e8d6c554SDavid Howells 
1785e8d6c554SDavid Howells 	/* marshall the parameters */
1786e8d6c554SDavid Howells 	bp = call->request;
1787e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1788e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1789e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1790e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1791e8d6c554SDavid Howells 
1792d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1793025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
179420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17950b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17960b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1797c435ee34SDavid Howells }
1798c435ee34SDavid Howells 
1799c435ee34SDavid Howells /*
1800c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1801c435ee34SDavid Howells  */
1802c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1803c435ee34SDavid Howells {
1804c435ee34SDavid Howells 	return afs_transfer_reply(call);
1805c435ee34SDavid Howells }
1806c435ee34SDavid Howells 
1807c435ee34SDavid Howells /*
1808c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1809c435ee34SDavid Howells  */
1810c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1811c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1812025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1813c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1814c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1815c435ee34SDavid Howells };
1816c435ee34SDavid Howells 
1817c435ee34SDavid Howells /*
1818c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1819c435ee34SDavid Howells  */
1820d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1821d2ddc776SDavid Howells 				 struct afs_server *server,
18228b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1823d2ddc776SDavid Howells 				 struct key *key)
1824c435ee34SDavid Howells {
1825c435ee34SDavid Howells 	struct afs_call *call;
1826c435ee34SDavid Howells 	__be32 *bp;
1827c435ee34SDavid Howells 
1828c435ee34SDavid Howells 	_enter("");
1829c435ee34SDavid Howells 
1830d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1831c435ee34SDavid Howells 	if (!call)
1832c435ee34SDavid Howells 		return -ENOMEM;
1833c435ee34SDavid Howells 
1834c435ee34SDavid Howells 	call->key = key;
1835c435ee34SDavid Howells 
1836c435ee34SDavid Howells 	/* marshall the parameters */
1837c435ee34SDavid Howells 	bp = call->request;
1838c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1839c435ee34SDavid Howells 
1840c435ee34SDavid Howells 	/* Can't take a ref on server */
18410b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
18420b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1843d2ddc776SDavid Howells }
1844d2ddc776SDavid Howells 
1845d2ddc776SDavid Howells /*
1846d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1847d2ddc776SDavid Howells  */
1848d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1849d2ddc776SDavid Howells {
1850d2ddc776SDavid Howells 	u32 count;
1851d2ddc776SDavid Howells 	int ret;
1852d2ddc776SDavid Howells 
1853fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1854d2ddc776SDavid Howells 
1855d2ddc776SDavid Howells 	switch (call->unmarshall) {
1856d2ddc776SDavid Howells 	case 0:
185712bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1858d2ddc776SDavid Howells 		call->unmarshall++;
185929881608SGustavo A. R. Silva 		/* Fall through */
1860d2ddc776SDavid Howells 
186129881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1862d2ddc776SDavid Howells 	case 1:
186312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1864d2ddc776SDavid Howells 		if (ret < 0)
1865d2ddc776SDavid Howells 			return ret;
1866d2ddc776SDavid Howells 
1867d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1868d2ddc776SDavid Howells 
1869d2ddc776SDavid Howells 		call->count = count;
1870d2ddc776SDavid Howells 		call->count2 = count;
187123a28913SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
1872d2ddc776SDavid Howells 		call->unmarshall++;
187329881608SGustavo A. R. Silva 		/* Fall through */
1874d2ddc776SDavid Howells 
187529881608SGustavo A. R. Silva 		/* Extract capabilities words */
1876d2ddc776SDavid Howells 	case 2:
187712bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1878d2ddc776SDavid Howells 		if (ret < 0)
1879d2ddc776SDavid Howells 			return ret;
1880d2ddc776SDavid Howells 
1881d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1882d2ddc776SDavid Howells 
1883d2ddc776SDavid Howells 		call->unmarshall++;
1884d2ddc776SDavid Howells 		break;
1885d2ddc776SDavid Howells 	}
1886d2ddc776SDavid Howells 
1887d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1888d2ddc776SDavid Howells 	return 0;
1889d2ddc776SDavid Howells }
1890d2ddc776SDavid Howells 
1891d2ddc776SDavid Howells /*
1892d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1893d2ddc776SDavid Howells  */
1894d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1895d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1896025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1897d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
18983bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1899ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1900d2ddc776SDavid Howells };
1901d2ddc776SDavid Howells 
1902d2ddc776SDavid Howells /*
1903d2ddc776SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This can
1904d2ddc776SDavid Howells  * return up to 196 words.
1905d2ddc776SDavid Howells  */
19060b9bf381SDavid Howells struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
1907d2ddc776SDavid Howells 					 struct afs_server *server,
1908d2ddc776SDavid Howells 					 struct afs_addr_cursor *ac,
19093bf0fb6fSDavid Howells 					 struct key *key,
19100b9bf381SDavid Howells 					 unsigned int server_index)
1911d2ddc776SDavid Howells {
1912d2ddc776SDavid Howells 	struct afs_call *call;
1913d2ddc776SDavid Howells 	__be32 *bp;
1914d2ddc776SDavid Howells 
1915d2ddc776SDavid Howells 	_enter("");
1916d2ddc776SDavid Howells 
1917d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1918d2ddc776SDavid Howells 	if (!call)
19190b9bf381SDavid Howells 		return ERR_PTR(-ENOMEM);
1920d2ddc776SDavid Howells 
1921d2ddc776SDavid Howells 	call->key = key;
192245218193SDavid Howells 	call->server = afs_get_server(server, afs_server_trace_get_caps);
1923ffba718eSDavid Howells 	call->server_index = server_index;
192430062bd1SDavid Howells 	call->upgrade = true;
19250b9bf381SDavid Howells 	call->async = true;
192694f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1927d2ddc776SDavid Howells 
1928d2ddc776SDavid Howells 	/* marshall the parameters */
1929d2ddc776SDavid Howells 	bp = call->request;
1930d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1931d2ddc776SDavid Howells 
1932d2ddc776SDavid Howells 	/* Can't take a ref on server */
1933025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
19340b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
19350b9bf381SDavid Howells 	return call;
1936e8d6c554SDavid Howells }
19375cf9dd55SDavid Howells 
19385cf9dd55SDavid Howells /*
19395cf9dd55SDavid Howells  * Deliver reply data to an FS.FetchStatus with no vnode.
19405cf9dd55SDavid Howells  */
19415cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
19425cf9dd55SDavid Howells {
19435cf9dd55SDavid Howells 	const __be32 *bp;
19445cf9dd55SDavid Howells 	int ret;
19455cf9dd55SDavid Howells 
19465cf9dd55SDavid Howells 	ret = afs_transfer_reply(call);
19475cf9dd55SDavid Howells 	if (ret < 0)
19485cf9dd55SDavid Howells 		return ret;
19495cf9dd55SDavid Howells 
19505cf9dd55SDavid Howells 	/* unmarshall the reply once we've received all of it */
19515cf9dd55SDavid Howells 	bp = call->buffer;
1952a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1953160cb957SDavid Howells 	if (ret < 0)
1954160cb957SDavid Howells 		return ret;
1955a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
1956a58823acSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
19575cf9dd55SDavid Howells 
19585cf9dd55SDavid Howells 	_leave(" = 0 [done]");
19595cf9dd55SDavid Howells 	return 0;
19605cf9dd55SDavid Howells }
19615cf9dd55SDavid Howells 
19625cf9dd55SDavid Howells /*
19635cf9dd55SDavid Howells  * FS.FetchStatus operation type
19645cf9dd55SDavid Howells  */
19655cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
19665cf9dd55SDavid Howells 	.name		= "FS.FetchStatus",
19675cf9dd55SDavid Howells 	.op		= afs_FS_FetchStatus,
19685cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
19695cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
19705cf9dd55SDavid Howells };
19715cf9dd55SDavid Howells 
19725cf9dd55SDavid Howells /*
19735cf9dd55SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
19745cf9dd55SDavid Howells  */
19755cf9dd55SDavid Howells int afs_fs_fetch_status(struct afs_fs_cursor *fc,
19765cf9dd55SDavid Howells 			struct afs_net *net,
19775cf9dd55SDavid Howells 			struct afs_fid *fid,
1978a58823acSDavid Howells 			struct afs_status_cb *scb,
19795cf9dd55SDavid Howells 			struct afs_volsync *volsync)
19805cf9dd55SDavid Howells {
19815cf9dd55SDavid Howells 	struct afs_call *call;
19825cf9dd55SDavid Howells 	__be32 *bp;
19835cf9dd55SDavid Howells 
198430062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1985a58823acSDavid Howells 		return yfs_fs_fetch_status(fc, net, fid, scb, volsync);
198630062bd1SDavid Howells 
19873b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
19885cf9dd55SDavid Howells 	       key_serial(fc->key), fid->vid, fid->vnode);
19895cf9dd55SDavid Howells 
19905cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
19915cf9dd55SDavid Howells 	if (!call) {
19925cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
19935cf9dd55SDavid Howells 		return -ENOMEM;
19945cf9dd55SDavid Howells 	}
19955cf9dd55SDavid Howells 
19965cf9dd55SDavid Howells 	call->key = fc->key;
1997ffba718eSDavid Howells 	call->out_fid = fid;
1998a58823acSDavid Howells 	call->out_scb = scb;
1999ffba718eSDavid Howells 	call->out_volsync = volsync;
20005cf9dd55SDavid Howells 
20015cf9dd55SDavid Howells 	/* marshall the parameters */
20025cf9dd55SDavid Howells 	bp = call->request;
20035cf9dd55SDavid Howells 	bp[0] = htonl(FSFETCHSTATUS);
20045cf9dd55SDavid Howells 	bp[1] = htonl(fid->vid);
20055cf9dd55SDavid Howells 	bp[2] = htonl(fid->vnode);
20065cf9dd55SDavid Howells 	bp[3] = htonl(fid->unique);
20075cf9dd55SDavid Howells 
20085cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
20095cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, fid);
201020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
20110b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
20120b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
20135cf9dd55SDavid Howells }
20145cf9dd55SDavid Howells 
20155cf9dd55SDavid Howells /*
20165cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
20175cf9dd55SDavid Howells  */
20185cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
20195cf9dd55SDavid Howells {
202087182759SDavid Howells 	struct afs_status_cb *scb;
20215cf9dd55SDavid Howells 	const __be32 *bp;
20225cf9dd55SDavid Howells 	u32 tmp;
20235cf9dd55SDavid Howells 	int ret;
20245cf9dd55SDavid Howells 
20255cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
20265cf9dd55SDavid Howells 
20275cf9dd55SDavid Howells 	switch (call->unmarshall) {
20285cf9dd55SDavid Howells 	case 0:
202912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
20305cf9dd55SDavid Howells 		call->unmarshall++;
203129881608SGustavo A. R. Silva 		/* Fall through */
20325cf9dd55SDavid Howells 
20335cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
20345cf9dd55SDavid Howells 	case 1:
20355cf9dd55SDavid Howells 		_debug("extract status count");
203612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20375cf9dd55SDavid Howells 		if (ret < 0)
20385cf9dd55SDavid Howells 			return ret;
20395cf9dd55SDavid Howells 
20405cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20415cf9dd55SDavid Howells 		_debug("status count: %u/%u", tmp, call->count2);
20425cf9dd55SDavid Howells 		if (tmp != call->count2)
2043160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2044160cb957SDavid Howells 						  afs_eproto_ibulkst_count);
20455cf9dd55SDavid Howells 
20465cf9dd55SDavid Howells 		call->count = 0;
20475cf9dd55SDavid Howells 		call->unmarshall++;
20485cf9dd55SDavid Howells 	more_counts:
204912bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
2050e690c9e3SGustavo A. R. Silva 		/* Fall through */
205129881608SGustavo A. R. Silva 
20525cf9dd55SDavid Howells 	case 2:
20535cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
205412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20555cf9dd55SDavid Howells 		if (ret < 0)
20565cf9dd55SDavid Howells 			return ret;
20575cf9dd55SDavid Howells 
20585cf9dd55SDavid Howells 		bp = call->buffer;
205987182759SDavid Howells 		scb = &call->out_scb[call->count];
2060a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, scb);
2061160cb957SDavid Howells 		if (ret < 0)
2062160cb957SDavid Howells 			return ret;
20635cf9dd55SDavid Howells 
20645cf9dd55SDavid Howells 		call->count++;
20655cf9dd55SDavid Howells 		if (call->count < call->count2)
20665cf9dd55SDavid Howells 			goto more_counts;
20675cf9dd55SDavid Howells 
20685cf9dd55SDavid Howells 		call->count = 0;
20695cf9dd55SDavid Howells 		call->unmarshall++;
207012bdcf33SDavid Howells 		afs_extract_to_tmp(call);
207129881608SGustavo A. R. Silva 		/* Fall through */
20725cf9dd55SDavid Howells 
20735cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
20745cf9dd55SDavid Howells 	case 3:
20755cf9dd55SDavid Howells 		_debug("extract CB count");
207612bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20775cf9dd55SDavid Howells 		if (ret < 0)
20785cf9dd55SDavid Howells 			return ret;
20795cf9dd55SDavid Howells 
20805cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20815cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
20825cf9dd55SDavid Howells 		if (tmp != call->count2)
2083160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2084160cb957SDavid Howells 						  afs_eproto_ibulkst_cb_count);
20855cf9dd55SDavid Howells 		call->count = 0;
20865cf9dd55SDavid Howells 		call->unmarshall++;
20875cf9dd55SDavid Howells 	more_cbs:
208812bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
2089e690c9e3SGustavo A. R. Silva 		/* Fall through */
209029881608SGustavo A. R. Silva 
20915cf9dd55SDavid Howells 	case 4:
20925cf9dd55SDavid Howells 		_debug("extract CB array");
209312bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20945cf9dd55SDavid Howells 		if (ret < 0)
20955cf9dd55SDavid Howells 			return ret;
20965cf9dd55SDavid Howells 
20975cf9dd55SDavid Howells 		_debug("unmarshall CB array");
20985cf9dd55SDavid Howells 		bp = call->buffer;
209987182759SDavid Howells 		scb = &call->out_scb[call->count];
2100a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
21015cf9dd55SDavid Howells 		call->count++;
21025cf9dd55SDavid Howells 		if (call->count < call->count2)
21035cf9dd55SDavid Howells 			goto more_cbs;
21045cf9dd55SDavid Howells 
210512bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
21065cf9dd55SDavid Howells 		call->unmarshall++;
2107e690c9e3SGustavo A. R. Silva 		/* Fall through */
210829881608SGustavo A. R. Silva 
21095cf9dd55SDavid Howells 	case 5:
211012bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
21115cf9dd55SDavid Howells 		if (ret < 0)
21125cf9dd55SDavid Howells 			return ret;
21135cf9dd55SDavid Howells 
21145cf9dd55SDavid Howells 		bp = call->buffer;
2115ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
21165cf9dd55SDavid Howells 
21175cf9dd55SDavid Howells 		call->unmarshall++;
21185cf9dd55SDavid Howells 
21195cf9dd55SDavid Howells 	case 6:
21205cf9dd55SDavid Howells 		break;
21215cf9dd55SDavid Howells 	}
21225cf9dd55SDavid Howells 
21235cf9dd55SDavid Howells 	_leave(" = 0 [done]");
21245cf9dd55SDavid Howells 	return 0;
21255cf9dd55SDavid Howells }
21265cf9dd55SDavid Howells 
21275cf9dd55SDavid Howells /*
21285cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
21295cf9dd55SDavid Howells  */
21305cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
21315cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
21325cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
21335cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
21345cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
21355cf9dd55SDavid Howells };
21365cf9dd55SDavid Howells 
21375cf9dd55SDavid Howells /*
21385cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
21395cf9dd55SDavid Howells  */
21405cf9dd55SDavid Howells int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
21415cf9dd55SDavid Howells 			      struct afs_net *net,
21425cf9dd55SDavid Howells 			      struct afs_fid *fids,
214387182759SDavid Howells 			      struct afs_status_cb *statuses,
21445cf9dd55SDavid Howells 			      unsigned int nr_fids,
21455cf9dd55SDavid Howells 			      struct afs_volsync *volsync)
21465cf9dd55SDavid Howells {
21475cf9dd55SDavid Howells 	struct afs_call *call;
21485cf9dd55SDavid Howells 	__be32 *bp;
21495cf9dd55SDavid Howells 	int i;
21505cf9dd55SDavid Howells 
215130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
215287182759SDavid Howells 		return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
215330062bd1SDavid Howells 						 nr_fids, volsync);
215430062bd1SDavid Howells 
21553b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
21565cf9dd55SDavid Howells 	       key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
21575cf9dd55SDavid Howells 
21585cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
21595cf9dd55SDavid Howells 				   (2 + nr_fids * 3) * 4,
21605cf9dd55SDavid Howells 				   21 * 4);
21615cf9dd55SDavid Howells 	if (!call) {
21625cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
21635cf9dd55SDavid Howells 		return -ENOMEM;
21645cf9dd55SDavid Howells 	}
21655cf9dd55SDavid Howells 
21665cf9dd55SDavid Howells 	call->key = fc->key;
216787182759SDavid Howells 	call->out_scb = statuses;
2168ffba718eSDavid Howells 	call->out_volsync = volsync;
21695cf9dd55SDavid Howells 	call->count2 = nr_fids;
21705cf9dd55SDavid Howells 
21715cf9dd55SDavid Howells 	/* marshall the parameters */
21725cf9dd55SDavid Howells 	bp = call->request;
21735cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
21745cf9dd55SDavid Howells 	*bp++ = htonl(nr_fids);
21755cf9dd55SDavid Howells 	for (i = 0; i < nr_fids; i++) {
21765cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vid);
21775cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vnode);
21785cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].unique);
21795cf9dd55SDavid Howells 	}
21805cf9dd55SDavid Howells 
21815cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
21825cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, &fids[0]);
218320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
21840b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
21850b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
21865cf9dd55SDavid Howells }
2187260f082bSDavid Howells 
2188260f082bSDavid Howells /*
2189260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
2190260f082bSDavid Howells  */
2191260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
2192260f082bSDavid Howells {
2193260f082bSDavid Howells 	struct afs_acl *acl;
2194260f082bSDavid Howells 	const __be32 *bp;
2195260f082bSDavid Howells 	unsigned int size;
2196260f082bSDavid Howells 	int ret;
2197260f082bSDavid Howells 
2198260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
2199260f082bSDavid Howells 
2200260f082bSDavid Howells 	switch (call->unmarshall) {
2201260f082bSDavid Howells 	case 0:
2202260f082bSDavid Howells 		afs_extract_to_tmp(call);
2203260f082bSDavid Howells 		call->unmarshall++;
220429881608SGustavo A. R. Silva 		/* Fall through */
2205260f082bSDavid Howells 
2206260f082bSDavid Howells 		/* extract the returned data length */
2207260f082bSDavid Howells 	case 1:
2208260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2209260f082bSDavid Howells 		if (ret < 0)
2210260f082bSDavid Howells 			return ret;
2211260f082bSDavid Howells 
2212260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
2213260f082bSDavid Howells 		size = round_up(size, 4);
2214260f082bSDavid Howells 
2215260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
2216260f082bSDavid Howells 		if (!acl)
2217260f082bSDavid Howells 			return -ENOMEM;
2218ffba718eSDavid Howells 		call->ret_acl = acl;
2219260f082bSDavid Howells 		acl->size = call->count2;
2220260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
2221260f082bSDavid Howells 		call->unmarshall++;
222229881608SGustavo A. R. Silva 		/* Fall through */
2223260f082bSDavid Howells 
2224260f082bSDavid Howells 		/* extract the returned data */
2225260f082bSDavid Howells 	case 2:
2226260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2227260f082bSDavid Howells 		if (ret < 0)
2228260f082bSDavid Howells 			return ret;
2229260f082bSDavid Howells 
2230260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
2231260f082bSDavid Howells 		call->unmarshall++;
223229881608SGustavo A. R. Silva 		/* Fall through */
2233260f082bSDavid Howells 
2234260f082bSDavid Howells 		/* extract the metadata */
2235260f082bSDavid Howells 	case 3:
2236260f082bSDavid Howells 		ret = afs_extract_data(call, false);
2237260f082bSDavid Howells 		if (ret < 0)
2238260f082bSDavid Howells 			return ret;
2239260f082bSDavid Howells 
2240260f082bSDavid Howells 		bp = call->buffer;
2241a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2242260f082bSDavid Howells 		if (ret < 0)
2243260f082bSDavid Howells 			return ret;
2244ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
2245260f082bSDavid Howells 
2246260f082bSDavid Howells 		call->unmarshall++;
2247260f082bSDavid Howells 
2248260f082bSDavid Howells 	case 4:
2249260f082bSDavid Howells 		break;
2250260f082bSDavid Howells 	}
2251260f082bSDavid Howells 
2252260f082bSDavid Howells 	_leave(" = 0 [done]");
2253260f082bSDavid Howells 	return 0;
2254260f082bSDavid Howells }
2255260f082bSDavid Howells 
2256260f082bSDavid Howells static void afs_destroy_fs_fetch_acl(struct afs_call *call)
2257260f082bSDavid Howells {
2258ffba718eSDavid Howells 	kfree(call->ret_acl);
2259260f082bSDavid Howells 	afs_flat_call_destructor(call);
2260260f082bSDavid Howells }
2261260f082bSDavid Howells 
2262260f082bSDavid Howells /*
2263260f082bSDavid Howells  * FS.FetchACL operation type
2264260f082bSDavid Howells  */
2265260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2266260f082bSDavid Howells 	.name		= "FS.FetchACL",
2267260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2268260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2269260f082bSDavid Howells 	.destructor	= afs_destroy_fs_fetch_acl,
2270260f082bSDavid Howells };
2271260f082bSDavid Howells 
2272260f082bSDavid Howells /*
2273260f082bSDavid Howells  * Fetch the ACL for a file.
2274260f082bSDavid Howells  */
2275a58823acSDavid Howells struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc,
2276a58823acSDavid Howells 				 struct afs_status_cb *scb)
2277260f082bSDavid Howells {
2278260f082bSDavid Howells 	struct afs_vnode *vnode = fc->vnode;
2279260f082bSDavid Howells 	struct afs_call *call;
2280260f082bSDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2281260f082bSDavid Howells 	__be32 *bp;
2282260f082bSDavid Howells 
2283260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2284260f082bSDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2285260f082bSDavid Howells 
2286260f082bSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2287260f082bSDavid Howells 	if (!call) {
2288260f082bSDavid Howells 		fc->ac.error = -ENOMEM;
2289260f082bSDavid Howells 		return ERR_PTR(-ENOMEM);
2290260f082bSDavid Howells 	}
2291260f082bSDavid Howells 
2292260f082bSDavid Howells 	call->key = fc->key;
2293ffba718eSDavid Howells 	call->ret_acl = NULL;
2294a58823acSDavid Howells 	call->out_scb = scb;
2295ffba718eSDavid Howells 	call->out_volsync = NULL;
2296260f082bSDavid Howells 
2297260f082bSDavid Howells 	/* marshall the parameters */
2298260f082bSDavid Howells 	bp = call->request;
2299260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2300260f082bSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
2301260f082bSDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
2302260f082bSDavid Howells 	bp[3] = htonl(vnode->fid.unique);
2303260f082bSDavid Howells 
2304260f082bSDavid Howells 	afs_use_fs_server(call, fc->cbi);
2305260f082bSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
2306260f082bSDavid Howells 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2307260f082bSDavid Howells 	return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
2308260f082bSDavid Howells }
2309b10494afSJoe Gorse 
2310b10494afSJoe Gorse /*
2311ffba718eSDavid Howells  * Deliver reply data to any operation that returns file status and volume
2312ffba718eSDavid Howells  * sync.
2313ffba718eSDavid Howells  */
2314ffba718eSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
2315ffba718eSDavid Howells {
2316ffba718eSDavid Howells 	const __be32 *bp;
2317ffba718eSDavid Howells 	int ret;
2318ffba718eSDavid Howells 
2319ffba718eSDavid Howells 	ret = afs_transfer_reply(call);
2320ffba718eSDavid Howells 	if (ret < 0)
2321ffba718eSDavid Howells 		return ret;
2322ffba718eSDavid Howells 
2323ffba718eSDavid Howells 	bp = call->buffer;
2324a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2325ffba718eSDavid Howells 	if (ret < 0)
2326ffba718eSDavid Howells 		return ret;
2327ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2328ffba718eSDavid Howells 
2329ffba718eSDavid Howells 	_leave(" = 0 [done]");
2330ffba718eSDavid Howells 	return 0;
2331ffba718eSDavid Howells }
2332ffba718eSDavid Howells 
2333ffba718eSDavid Howells /*
2334b10494afSJoe Gorse  * FS.StoreACL operation type
2335b10494afSJoe Gorse  */
2336b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2337b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2338b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2339ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2340b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2341b10494afSJoe Gorse };
2342b10494afSJoe Gorse 
2343b10494afSJoe Gorse /*
2344b10494afSJoe Gorse  * Fetch the ACL for a file.
2345b10494afSJoe Gorse  */
2346a58823acSDavid Howells int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl,
2347a58823acSDavid Howells 		     struct afs_status_cb *scb)
2348b10494afSJoe Gorse {
2349b10494afSJoe Gorse 	struct afs_vnode *vnode = fc->vnode;
2350b10494afSJoe Gorse 	struct afs_call *call;
2351b10494afSJoe Gorse 	struct afs_net *net = afs_v2net(vnode);
2352b10494afSJoe Gorse 	size_t size;
2353b10494afSJoe Gorse 	__be32 *bp;
2354b10494afSJoe Gorse 
2355b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2356b10494afSJoe Gorse 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2357b10494afSJoe Gorse 
2358b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2359b10494afSJoe Gorse 	call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
2360b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2361b10494afSJoe Gorse 	if (!call) {
2362b10494afSJoe Gorse 		fc->ac.error = -ENOMEM;
2363b10494afSJoe Gorse 		return -ENOMEM;
2364b10494afSJoe Gorse 	}
2365b10494afSJoe Gorse 
2366b10494afSJoe Gorse 	call->key = fc->key;
2367a58823acSDavid Howells 	call->out_scb = scb;
2368ffba718eSDavid Howells 	call->out_volsync = NULL;
2369b10494afSJoe Gorse 
2370b10494afSJoe Gorse 	/* marshall the parameters */
2371b10494afSJoe Gorse 	bp = call->request;
2372b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2373b10494afSJoe Gorse 	bp[1] = htonl(vnode->fid.vid);
2374b10494afSJoe Gorse 	bp[2] = htonl(vnode->fid.vnode);
2375b10494afSJoe Gorse 	bp[3] = htonl(vnode->fid.unique);
2376b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2377b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2378b10494afSJoe Gorse 	if (acl->size != size)
2379b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2380b10494afSJoe Gorse 
2381b10494afSJoe Gorse 	trace_afs_make_fs_call(call, &vnode->fid);
2382b10494afSJoe Gorse 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2383b10494afSJoe Gorse 	return afs_wait_for_call_to_complete(call, &fc->ac);
23841da177e4SLinus Torvalds }
2385