xref: /openbmc/linux/fs/afs/fsclient.c (revision c72057b5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
208e0e7c8SDavid Howells /* AFS File Server client stubs
31da177e4SLinus Torvalds  *
408e0e7c8SDavid Howells  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/init.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
101da177e4SLinus Torvalds #include <linux/sched.h>
1108e0e7c8SDavid Howells #include <linux/circ_buf.h>
12a01179e6SJeff Layton #include <linux/iversion.h>
131da177e4SLinus Torvalds #include "internal.h"
1408e0e7c8SDavid Howells #include "afs_fs.h"
15dd9fbcb8SDavid Howells #include "xdr_fs.h"
1630062bd1SDavid Howells #include "protocol_yfs.h"
171da177e4SLinus Torvalds 
18d2ddc776SDavid Howells static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
19c435ee34SDavid Howells {
20d2ddc776SDavid Howells 	call->cbi = afs_get_cb_interest(cbi);
21c435ee34SDavid Howells }
22c435ee34SDavid Howells 
236db3ac3cSDavid Howells /*
24260a9803SDavid Howells  * decode an AFSFid block
25260a9803SDavid Howells  */
26260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
27260a9803SDavid Howells {
28260a9803SDavid Howells 	const __be32 *bp = *_bp;
29260a9803SDavid Howells 
30260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
31260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
32260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
33260a9803SDavid Howells 	*_bp = bp;
34260a9803SDavid Howells }
35260a9803SDavid Howells 
36260a9803SDavid Howells /*
37888b3384SDavid Howells  * Dump a bad file status record.
38888b3384SDavid Howells  */
39888b3384SDavid Howells static void xdr_dump_bad(const __be32 *bp)
40888b3384SDavid Howells {
41888b3384SDavid Howells 	__be32 x[4];
42888b3384SDavid Howells 	int i;
43888b3384SDavid Howells 
44888b3384SDavid Howells 	pr_notice("AFS XDR: Bad status record\n");
45888b3384SDavid Howells 	for (i = 0; i < 5 * 4 * 4; i += 16) {
46888b3384SDavid Howells 		memcpy(x, bp, 16);
47888b3384SDavid Howells 		bp += 4;
48888b3384SDavid Howells 		pr_notice("%03x: %08x %08x %08x %08x\n",
49888b3384SDavid Howells 			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
50888b3384SDavid Howells 	}
51888b3384SDavid Howells 
52888b3384SDavid Howells 	memcpy(x, bp, 4);
53888b3384SDavid Howells 	pr_notice("0x50: %08x\n", ntohl(x[0]));
54888b3384SDavid Howells }
55888b3384SDavid Howells 
56888b3384SDavid Howells /*
57dd9fbcb8SDavid Howells  * decode an AFSFetchStatus block
58dd9fbcb8SDavid Howells  */
59a58823acSDavid Howells static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
60a58823acSDavid Howells 				     struct afs_call *call,
61a58823acSDavid Howells 				     struct afs_status_cb *scb)
62dd9fbcb8SDavid Howells {
63dd9fbcb8SDavid Howells 	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
64a58823acSDavid Howells 	struct afs_file_status *status = &scb->status;
65684b0f68SDavid Howells 	bool inline_error = (call->operation_ID == afs_FS_InlineBulkStatus);
66dd9fbcb8SDavid Howells 	u64 data_version, size;
67dd9fbcb8SDavid Howells 	u32 type, abort_code;
68c72057b5SDavid Howells 	int ret;
69dd9fbcb8SDavid Howells 
70684b0f68SDavid Howells 	abort_code = ntohl(xdr->abort_code);
71684b0f68SDavid Howells 
72dd9fbcb8SDavid Howells 	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
73684b0f68SDavid Howells 		if (xdr->if_version == htonl(0) &&
74684b0f68SDavid Howells 		    abort_code != 0 &&
75684b0f68SDavid Howells 		    inline_error) {
76684b0f68SDavid Howells 			/* The OpenAFS fileserver has a bug in FS.InlineBulkStatus
77684b0f68SDavid Howells 			 * whereby it doesn't set the interface version in the error
78684b0f68SDavid Howells 			 * case.
79684b0f68SDavid Howells 			 */
80684b0f68SDavid Howells 			status->abort_code = abort_code;
81a38a7558SDavid Howells 			scb->have_error = true;
82c72057b5SDavid Howells 			goto good;
83684b0f68SDavid Howells 		}
84684b0f68SDavid Howells 
85dd9fbcb8SDavid Howells 		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
86dd9fbcb8SDavid Howells 		goto bad;
87dd9fbcb8SDavid Howells 	}
88dd9fbcb8SDavid Howells 
89684b0f68SDavid Howells 	if (abort_code != 0 && inline_error) {
90684b0f68SDavid Howells 		status->abort_code = abort_code;
91c72057b5SDavid Howells 		goto good;
92684b0f68SDavid Howells 	}
93684b0f68SDavid Howells 
94dd9fbcb8SDavid Howells 	type = ntohl(xdr->type);
95dd9fbcb8SDavid Howells 	switch (type) {
96dd9fbcb8SDavid Howells 	case AFS_FTYPE_FILE:
97dd9fbcb8SDavid Howells 	case AFS_FTYPE_DIR:
98dd9fbcb8SDavid Howells 	case AFS_FTYPE_SYMLINK:
99dd9fbcb8SDavid Howells 		status->type = type;
100dd9fbcb8SDavid Howells 		break;
101dd9fbcb8SDavid Howells 	default:
102dd9fbcb8SDavid Howells 		goto bad;
103dd9fbcb8SDavid Howells 	}
104dd9fbcb8SDavid Howells 
105a58823acSDavid Howells 	status->nlink		= ntohl(xdr->nlink);
106a58823acSDavid Howells 	status->author		= ntohl(xdr->author);
107a58823acSDavid Howells 	status->owner		= ntohl(xdr->owner);
108a58823acSDavid Howells 	status->caller_access	= ntohl(xdr->caller_access); /* Ticket dependent */
109a58823acSDavid Howells 	status->anon_access	= ntohl(xdr->anon_access);
110a58823acSDavid Howells 	status->mode		= ntohl(xdr->mode) & S_IALLUGO;
111a58823acSDavid Howells 	status->group		= ntohl(xdr->group);
112a58823acSDavid Howells 	status->lock_count	= ntohl(xdr->lock_count);
113dd9fbcb8SDavid Howells 
114d4936803SDavid Howells 	status->mtime_client.tv_sec = ntohl(xdr->mtime_client);
115d4936803SDavid Howells 	status->mtime_client.tv_nsec = 0;
116d4936803SDavid Howells 	status->mtime_server.tv_sec = ntohl(xdr->mtime_server);
117d4936803SDavid Howells 	status->mtime_server.tv_nsec = 0;
118dd9fbcb8SDavid Howells 
119dd9fbcb8SDavid Howells 	size  = (u64)ntohl(xdr->size_lo);
120dd9fbcb8SDavid Howells 	size |= (u64)ntohl(xdr->size_hi) << 32;
121dd9fbcb8SDavid Howells 	status->size = size;
122dd9fbcb8SDavid Howells 
123dd9fbcb8SDavid Howells 	data_version  = (u64)ntohl(xdr->data_version_lo);
124dd9fbcb8SDavid Howells 	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
125dd9fbcb8SDavid Howells 	status->data_version = data_version;
126a38a7558SDavid Howells 	scb->have_status = true;
127c72057b5SDavid Howells good:
128c72057b5SDavid Howells 	ret = 0;
129c72057b5SDavid Howells advance:
130dd9fbcb8SDavid Howells 	*_bp = (const void *)*_bp + sizeof(*xdr);
131c72057b5SDavid Howells 	return ret;
132dd9fbcb8SDavid Howells 
133dd9fbcb8SDavid Howells bad:
134dd9fbcb8SDavid Howells 	xdr_dump_bad(*_bp);
135c72057b5SDavid Howells 	ret = afs_protocol_error(call, -EBADMSG, afs_eproto_bad_status);
136c72057b5SDavid Howells 	goto advance;
137c875c76aSDavid Howells }
138c875c76aSDavid Howells 
13978107055SDavid Howells static time64_t xdr_decode_expiry(struct afs_call *call, u32 expiry)
14078107055SDavid Howells {
14178107055SDavid Howells 	return ktime_divns(call->reply_time, NSEC_PER_SEC) + expiry;
14278107055SDavid Howells }
14378107055SDavid Howells 
144a58823acSDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp,
145a58823acSDavid Howells 				   struct afs_call *call,
146a58823acSDavid Howells 				   struct afs_status_cb *scb)
14778107055SDavid Howells {
148a58823acSDavid Howells 	struct afs_callback *cb = &scb->callback;
14978107055SDavid Howells 	const __be32 *bp = *_bp;
15078107055SDavid Howells 
1517c712458SDavid Howells 	bp++; /* version */
15278107055SDavid Howells 	cb->expires_at	= xdr_decode_expiry(call, ntohl(*bp++));
1537c712458SDavid Howells 	bp++; /* type */
154a58823acSDavid Howells 	scb->have_cb	= true;
15578107055SDavid Howells 	*_bp = bp;
15678107055SDavid Howells }
15778107055SDavid Howells 
1581da177e4SLinus Torvalds /*
15908e0e7c8SDavid Howells  * decode an AFSVolSync block
1601da177e4SLinus Torvalds  */
16108e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
16208e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1631da177e4SLinus Torvalds {
16408e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
16530062bd1SDavid Howells 	u32 creation;
1661da177e4SLinus Torvalds 
16730062bd1SDavid Howells 	creation = ntohl(*bp++);
16808e0e7c8SDavid Howells 	bp++; /* spare2 */
16908e0e7c8SDavid Howells 	bp++; /* spare3 */
17008e0e7c8SDavid Howells 	bp++; /* spare4 */
17108e0e7c8SDavid Howells 	bp++; /* spare5 */
17208e0e7c8SDavid Howells 	bp++; /* spare6 */
17308e0e7c8SDavid Howells 	*_bp = bp;
17430062bd1SDavid Howells 
17530062bd1SDavid Howells 	if (volsync)
17630062bd1SDavid Howells 		volsync->creation = creation;
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
17908e0e7c8SDavid Howells /*
18031143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
18131143d5dSDavid Howells  */
18231143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
18331143d5dSDavid Howells {
18431143d5dSDavid Howells 	__be32 *bp = *_bp;
18531143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
18631143d5dSDavid Howells 
18731143d5dSDavid Howells 	mask = 0;
18831143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18931143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
19031143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
19131143d5dSDavid Howells 	}
19231143d5dSDavid Howells 
19331143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
19431143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
195a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
19631143d5dSDavid Howells 	}
19731143d5dSDavid Howells 
19831143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19931143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
200a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
20131143d5dSDavid Howells 	}
20231143d5dSDavid Howells 
20331143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
20431143d5dSDavid Howells 		mask |= AFS_SET_MODE;
20531143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
20631143d5dSDavid Howells 	}
20731143d5dSDavid Howells 
20831143d5dSDavid Howells 	*bp++ = htonl(mask);
20931143d5dSDavid Howells 	*bp++ = htonl(mtime);
21031143d5dSDavid Howells 	*bp++ = htonl(owner);
21131143d5dSDavid Howells 	*bp++ = htonl(group);
21231143d5dSDavid Howells 	*bp++ = htonl(mode);
21331143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
21431143d5dSDavid Howells 	*_bp = bp;
21531143d5dSDavid Howells }
21631143d5dSDavid Howells 
21731143d5dSDavid Howells /*
21845222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21945222b9eSDavid Howells  */
22045222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
22145222b9eSDavid Howells 					    struct afs_volume_status *vs)
22245222b9eSDavid Howells {
22345222b9eSDavid Howells 	const __be32 *bp = *_bp;
22445222b9eSDavid Howells 
22545222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
23045222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
23145222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
23245222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
23345222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
23445222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
23545222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
23645222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23730062bd1SDavid Howells 	vs->vol_copy_date	= 0;
23830062bd1SDavid Howells 	vs->vol_backup_date	= 0;
23945222b9eSDavid Howells 	*_bp = bp;
24045222b9eSDavid Howells }
24145222b9eSDavid Howells 
24245222b9eSDavid Howells /*
24308e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
24408e0e7c8SDavid Howells  */
2455cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
24608e0e7c8SDavid Howells {
24708e0e7c8SDavid Howells 	const __be32 *bp;
248372ee163SDavid Howells 	int ret;
2491da177e4SLinus Torvalds 
250d001648eSDavid Howells 	ret = afs_transfer_reply(call);
251372ee163SDavid Howells 	if (ret < 0)
252372ee163SDavid Howells 		return ret;
2531da177e4SLinus Torvalds 
25408e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25508e0e7c8SDavid Howells 	bp = call->buffer;
256a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
257160cb957SDavid Howells 	if (ret < 0)
258160cb957SDavid Howells 		return ret;
259a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
260ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2611da177e4SLinus Torvalds 
26208e0e7c8SDavid Howells 	_leave(" = 0 [done]");
26308e0e7c8SDavid Howells 	return 0;
264ec26815aSDavid Howells }
26508e0e7c8SDavid Howells 
26608e0e7c8SDavid Howells /*
26708e0e7c8SDavid Howells  * FS.FetchStatus operation type
26808e0e7c8SDavid Howells  */
2695cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
2705cf9dd55SDavid Howells 	.name		= "FS.FetchStatus(vnode)",
271025db80cSDavid Howells 	.op		= afs_FS_FetchStatus,
2725cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status_vnode,
27308e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
27408e0e7c8SDavid Howells };
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds /*
2771da177e4SLinus Torvalds  * fetch the status information for a file
2781da177e4SLinus Torvalds  */
279a58823acSDavid Howells int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_status_cb *scb,
280a58823acSDavid Howells 			     struct afs_volsync *volsync)
2811da177e4SLinus Torvalds {
282d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
28308e0e7c8SDavid Howells 	struct afs_call *call;
284f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2851da177e4SLinus Torvalds 	__be32 *bp;
2861da177e4SLinus Torvalds 
28730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
288a58823acSDavid Howells 		return yfs_fs_fetch_file_status(fc, scb, volsync);
28930062bd1SDavid Howells 
2903b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
291d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2921da177e4SLinus Torvalds 
2935cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
2945cf9dd55SDavid Howells 				   16, (21 + 3 + 6) * 4);
295d2ddc776SDavid Howells 	if (!call) {
296d2ddc776SDavid Howells 		fc->ac.error = -ENOMEM;
29708e0e7c8SDavid Howells 		return -ENOMEM;
298d2ddc776SDavid Howells 	}
2991da177e4SLinus Torvalds 
300d2ddc776SDavid Howells 	call->key = fc->key;
301a58823acSDavid Howells 	call->out_scb = scb;
302ffba718eSDavid Howells 	call->out_volsync = volsync;
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds 	/* marshall the parameters */
30508e0e7c8SDavid Howells 	bp = call->request;
3061da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
3071da177e4SLinus Torvalds 	bp[1] = htonl(vnode->fid.vid);
3081da177e4SLinus Torvalds 	bp[2] = htonl(vnode->fid.vnode);
3091da177e4SLinus Torvalds 	bp[3] = htonl(vnode->fid.unique);
3101da177e4SLinus Torvalds 
311d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
312025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
3130b9bf381SDavid Howells 
31420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
3150b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
3160b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
317ec26815aSDavid Howells }
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds /*
32008e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
3211da177e4SLinus Torvalds  */
322d001648eSDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call)
3231da177e4SLinus Torvalds {
324ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
32508e0e7c8SDavid Howells 	const __be32 *bp;
326196ee9cdSDavid Howells 	unsigned int size;
3271da177e4SLinus Torvalds 	int ret;
3281da177e4SLinus Torvalds 
32912bdcf33SDavid Howells 	_enter("{%u,%zu/%llu}",
330fc276122SDavid Howells 	       call->unmarshall, iov_iter_count(call->iter), req->actual_len);
3311da177e4SLinus Torvalds 
33208e0e7c8SDavid Howells 	switch (call->unmarshall) {
33308e0e7c8SDavid Howells 	case 0:
334196ee9cdSDavid Howells 		req->actual_len = 0;
33512bdcf33SDavid Howells 		req->index = 0;
33612bdcf33SDavid Howells 		req->offset = req->pos & (PAGE_SIZE - 1);
33708e0e7c8SDavid Howells 		call->unmarshall++;
33812bdcf33SDavid Howells 		if (call->operation_ID == FSFETCHDATA64) {
33912bdcf33SDavid Howells 			afs_extract_to_tmp64(call);
34012bdcf33SDavid Howells 		} else {
34112bdcf33SDavid Howells 			call->tmp_u = htonl(0);
34212bdcf33SDavid Howells 			afs_extract_to_tmp(call);
343b9b1f8d5SDavid Howells 		}
34429881608SGustavo A. R. Silva 		/* Fall through */
3451da177e4SLinus Torvalds 
34629881608SGustavo A. R. Silva 		/* extract the returned data length */
34712bdcf33SDavid Howells 	case 1:
34808e0e7c8SDavid Howells 		_debug("extract data length");
34912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
350372ee163SDavid Howells 		if (ret < 0)
351372ee163SDavid Howells 			return ret;
3521da177e4SLinus Torvalds 
35312bdcf33SDavid Howells 		req->actual_len = be64_to_cpu(call->tmp64);
354196ee9cdSDavid Howells 		_debug("DATA length: %llu", req->actual_len);
35512bdcf33SDavid Howells 		req->remain = min(req->len, req->actual_len);
35612bdcf33SDavid Howells 		if (req->remain == 0)
357196ee9cdSDavid Howells 			goto no_more_data;
35812bdcf33SDavid Howells 
35908e0e7c8SDavid Howells 		call->unmarshall++;
3601da177e4SLinus Torvalds 
361196ee9cdSDavid Howells 	begin_page:
3626db3ac3cSDavid Howells 		ASSERTCMP(req->index, <, req->nr_pages);
36312bdcf33SDavid Howells 		if (req->remain > PAGE_SIZE - req->offset)
36412bdcf33SDavid Howells 			size = PAGE_SIZE - req->offset;
365196ee9cdSDavid Howells 		else
366196ee9cdSDavid Howells 			size = req->remain;
36712bdcf33SDavid Howells 		call->bvec[0].bv_len = size;
36812bdcf33SDavid Howells 		call->bvec[0].bv_offset = req->offset;
36912bdcf33SDavid Howells 		call->bvec[0].bv_page = req->pages[req->index];
370fc276122SDavid Howells 		iov_iter_bvec(&call->def_iter, READ, call->bvec, 1, size);
37112bdcf33SDavid Howells 		ASSERTCMP(size, <=, PAGE_SIZE);
37229881608SGustavo A. R. Silva 		/* Fall through */
373196ee9cdSDavid Howells 
37429881608SGustavo A. R. Silva 		/* extract the returned data */
37512bdcf33SDavid Howells 	case 2:
37612bdcf33SDavid Howells 		_debug("extract data %zu/%llu",
377fc276122SDavid Howells 		       iov_iter_count(call->iter), req->remain);
378196ee9cdSDavid Howells 
37912bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
380372ee163SDavid Howells 		if (ret < 0)
381372ee163SDavid Howells 			return ret;
38212bdcf33SDavid Howells 		req->remain -= call->bvec[0].bv_len;
38312bdcf33SDavid Howells 		req->offset += call->bvec[0].bv_len;
38412bdcf33SDavid Howells 		ASSERTCMP(req->offset, <=, PAGE_SIZE);
38512bdcf33SDavid Howells 		if (req->offset == PAGE_SIZE) {
38612bdcf33SDavid Howells 			req->offset = 0;
387196ee9cdSDavid Howells 			if (req->page_done)
388a58823acSDavid Howells 				req->page_done(req);
38929f06985SDavid Howells 			req->index++;
39012bdcf33SDavid Howells 			if (req->remain > 0)
391196ee9cdSDavid Howells 				goto begin_page;
392196ee9cdSDavid Howells 		}
39312bdcf33SDavid Howells 
39412bdcf33SDavid Howells 		ASSERTCMP(req->remain, ==, 0);
39512bdcf33SDavid Howells 		if (req->actual_len <= req->len)
3966db3ac3cSDavid Howells 			goto no_more_data;
3976db3ac3cSDavid Howells 
3986db3ac3cSDavid Howells 		/* Discard any excess data the server gave us */
39923a28913SDavid Howells 		afs_extract_discard(call, req->actual_len - req->len);
40012bdcf33SDavid Howells 		call->unmarshall = 3;
401e690c9e3SGustavo A. R. Silva 		/* Fall through */
40229881608SGustavo A. R. Silva 
40312bdcf33SDavid Howells 	case 3:
40412bdcf33SDavid Howells 		_debug("extract discard %zu/%llu",
405fc276122SDavid Howells 		       iov_iter_count(call->iter), req->actual_len - req->len);
4066db3ac3cSDavid Howells 
40712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
4086db3ac3cSDavid Howells 		if (ret < 0)
4096db3ac3cSDavid Howells 			return ret;
4101da177e4SLinus Torvalds 
411196ee9cdSDavid Howells 	no_more_data:
41212bdcf33SDavid Howells 		call->unmarshall = 4;
41312bdcf33SDavid Howells 		afs_extract_to_buf(call, (21 + 3 + 6) * 4);
41429881608SGustavo A. R. Silva 		/* Fall through */
41508e0e7c8SDavid Howells 
41629881608SGustavo A. R. Silva 		/* extract the metadata */
41712bdcf33SDavid Howells 	case 4:
41812bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
419372ee163SDavid Howells 		if (ret < 0)
420372ee163SDavid Howells 			return ret;
4211da177e4SLinus Torvalds 
42208e0e7c8SDavid Howells 		bp = call->buffer;
423a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
424160cb957SDavid Howells 		if (ret < 0)
425160cb957SDavid Howells 			return ret;
426a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, call->out_scb);
427ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
4281da177e4SLinus Torvalds 
429a58823acSDavid Howells 		req->data_version = call->out_scb->status.data_version;
430a58823acSDavid Howells 		req->file_size = call->out_scb->status.size;
431a58823acSDavid Howells 
43208e0e7c8SDavid Howells 		call->unmarshall++;
4331da177e4SLinus Torvalds 
43412bdcf33SDavid Howells 	case 5:
4351da177e4SLinus Torvalds 		break;
4361da177e4SLinus Torvalds 	}
4371da177e4SLinus Torvalds 
4386db3ac3cSDavid Howells 	for (; req->index < req->nr_pages; req->index++) {
43912bdcf33SDavid Howells 		if (req->offset < PAGE_SIZE)
4406db3ac3cSDavid Howells 			zero_user_segment(req->pages[req->index],
44112bdcf33SDavid Howells 					  req->offset, PAGE_SIZE);
442196ee9cdSDavid Howells 		if (req->page_done)
443a58823acSDavid Howells 			req->page_done(req);
44412bdcf33SDavid Howells 		req->offset = 0;
445416351f2SDavid Howells 	}
446416351f2SDavid Howells 
44708e0e7c8SDavid Howells 	_leave(" = 0 [done]");
44808e0e7c8SDavid Howells 	return 0;
449ec26815aSDavid Howells }
4501da177e4SLinus Torvalds 
451196ee9cdSDavid Howells static void afs_fetch_data_destructor(struct afs_call *call)
452196ee9cdSDavid Howells {
453ffba718eSDavid Howells 	struct afs_read *req = call->read_request;
454196ee9cdSDavid Howells 
455196ee9cdSDavid Howells 	afs_put_read(req);
456196ee9cdSDavid Howells 	afs_flat_call_destructor(call);
457196ee9cdSDavid Howells }
458196ee9cdSDavid Howells 
4591da177e4SLinus Torvalds /*
46008e0e7c8SDavid Howells  * FS.FetchData operation type
4611da177e4SLinus Torvalds  */
46208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
46300d3b7a4SDavid Howells 	.name		= "FS.FetchData",
464025db80cSDavid Howells 	.op		= afs_FS_FetchData,
46508e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
466196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
46708e0e7c8SDavid Howells };
46808e0e7c8SDavid Howells 
469b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
470b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
471025db80cSDavid Howells 	.op		= afs_FS_FetchData64,
472b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
473196ee9cdSDavid Howells 	.destructor	= afs_fetch_data_destructor,
474b9b1f8d5SDavid Howells };
475b9b1f8d5SDavid Howells 
476b9b1f8d5SDavid Howells /*
477b9b1f8d5SDavid Howells  * fetch data from a very large file
478b9b1f8d5SDavid Howells  */
479a58823acSDavid Howells static int afs_fs_fetch_data64(struct afs_fs_cursor *fc,
480a58823acSDavid Howells 			       struct afs_status_cb *scb,
481a58823acSDavid Howells 			       struct afs_read *req)
482b9b1f8d5SDavid Howells {
483d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
484b9b1f8d5SDavid Howells 	struct afs_call *call;
485f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
486b9b1f8d5SDavid Howells 	__be32 *bp;
487b9b1f8d5SDavid Howells 
488b9b1f8d5SDavid Howells 	_enter("");
489b9b1f8d5SDavid Howells 
490f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
491b9b1f8d5SDavid Howells 	if (!call)
492b9b1f8d5SDavid Howells 		return -ENOMEM;
493b9b1f8d5SDavid Howells 
494d2ddc776SDavid Howells 	call->key = fc->key;
495a58823acSDavid Howells 	call->out_scb = scb;
496ffba718eSDavid Howells 	call->out_volsync = NULL;
497d4438a25SDavid Howells 	call->read_request = afs_get_read(req);
498b9b1f8d5SDavid Howells 
499b9b1f8d5SDavid Howells 	/* marshall the parameters */
500b9b1f8d5SDavid Howells 	bp = call->request;
501b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
502b9b1f8d5SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
503b9b1f8d5SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
504b9b1f8d5SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
505196ee9cdSDavid Howells 	bp[4] = htonl(upper_32_bits(req->pos));
506196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->pos));
507b9b1f8d5SDavid Howells 	bp[6] = 0;
508196ee9cdSDavid Howells 	bp[7] = htonl(lower_32_bits(req->len));
509b9b1f8d5SDavid Howells 
510d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
511025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
51220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5130b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5140b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
515b9b1f8d5SDavid Howells }
516b9b1f8d5SDavid Howells 
51708e0e7c8SDavid Howells /*
51808e0e7c8SDavid Howells  * fetch data from a file
51908e0e7c8SDavid Howells  */
520a58823acSDavid Howells int afs_fs_fetch_data(struct afs_fs_cursor *fc,
521a58823acSDavid Howells 		      struct afs_status_cb *scb,
522a58823acSDavid Howells 		      struct afs_read *req)
5231da177e4SLinus Torvalds {
524d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
52508e0e7c8SDavid Howells 	struct afs_call *call;
526f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
52708e0e7c8SDavid Howells 	__be32 *bp;
5281da177e4SLinus Torvalds 
52930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
530a58823acSDavid Howells 		return yfs_fs_fetch_data(fc, scb, req);
53130062bd1SDavid Howells 
532196ee9cdSDavid Howells 	if (upper_32_bits(req->pos) ||
533196ee9cdSDavid Howells 	    upper_32_bits(req->len) ||
534196ee9cdSDavid Howells 	    upper_32_bits(req->pos + req->len))
535a58823acSDavid Howells 		return afs_fs_fetch_data64(fc, scb, req);
536b9b1f8d5SDavid Howells 
53708e0e7c8SDavid Howells 	_enter("");
5381da177e4SLinus Torvalds 
539f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
54008e0e7c8SDavid Howells 	if (!call)
54108e0e7c8SDavid Howells 		return -ENOMEM;
5421da177e4SLinus Torvalds 
543d2ddc776SDavid Howells 	call->key = fc->key;
544a58823acSDavid Howells 	call->out_scb = scb;
545ffba718eSDavid Howells 	call->out_volsync = NULL;
546d4438a25SDavid Howells 	call->read_request = afs_get_read(req);
5471da177e4SLinus Torvalds 
5481da177e4SLinus Torvalds 	/* marshall the parameters */
54908e0e7c8SDavid Howells 	bp = call->request;
55008e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
55108e0e7c8SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
55208e0e7c8SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
55308e0e7c8SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
554196ee9cdSDavid Howells 	bp[4] = htonl(lower_32_bits(req->pos));
555196ee9cdSDavid Howells 	bp[5] = htonl(lower_32_bits(req->len));
5561da177e4SLinus Torvalds 
557d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
558025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
55920b8391fSDavid Howells 	afs_set_fc_call(call, fc);
5600b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
5610b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
56208e0e7c8SDavid Howells }
563260a9803SDavid Howells 
564260a9803SDavid Howells /*
565260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
566260a9803SDavid Howells  */
567d001648eSDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call)
568260a9803SDavid Howells {
569260a9803SDavid Howells 	const __be32 *bp;
570372ee163SDavid Howells 	int ret;
571260a9803SDavid Howells 
572d001648eSDavid Howells 	ret = afs_transfer_reply(call);
573372ee163SDavid Howells 	if (ret < 0)
574372ee163SDavid Howells 		return ret;
575260a9803SDavid Howells 
576260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
577260a9803SDavid Howells 	bp = call->buffer;
578ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
579a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
580160cb957SDavid Howells 	if (ret < 0)
581160cb957SDavid Howells 		return ret;
582a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
583160cb957SDavid Howells 	if (ret < 0)
584160cb957SDavid Howells 		return ret;
585a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
586ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
587260a9803SDavid Howells 
588260a9803SDavid Howells 	_leave(" = 0 [done]");
589260a9803SDavid Howells 	return 0;
590260a9803SDavid Howells }
591260a9803SDavid Howells 
592260a9803SDavid Howells /*
593260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
594260a9803SDavid Howells  */
595025db80cSDavid Howells static const struct afs_call_type afs_RXFSCreateFile = {
596025db80cSDavid Howells 	.name		= "FS.CreateFile",
597025db80cSDavid Howells 	.op		= afs_FS_CreateFile,
598025db80cSDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
599025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
600025db80cSDavid Howells };
601025db80cSDavid Howells 
602025db80cSDavid Howells static const struct afs_call_type afs_RXFSMakeDir = {
603025db80cSDavid Howells 	.name		= "FS.MakeDir",
604025db80cSDavid Howells 	.op		= afs_FS_MakeDir,
605260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
606260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
607260a9803SDavid Howells };
608260a9803SDavid Howells 
609260a9803SDavid Howells /*
610260a9803SDavid Howells  * create a file or make a directory
611260a9803SDavid Howells  */
6128b2a464cSDavid Howells int afs_fs_create(struct afs_fs_cursor *fc,
613260a9803SDavid Howells 		  const char *name,
614260a9803SDavid Howells 		  umode_t mode,
615a58823acSDavid Howells 		  struct afs_status_cb *dvnode_scb,
616260a9803SDavid Howells 		  struct afs_fid *newfid,
617a58823acSDavid Howells 		  struct afs_status_cb *new_scb)
618260a9803SDavid Howells {
619ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
620260a9803SDavid Howells 	struct afs_call *call;
621ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
622260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
623260a9803SDavid Howells 	__be32 *bp;
624260a9803SDavid Howells 
62530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags)){
62630062bd1SDavid Howells 		if (S_ISDIR(mode))
627a58823acSDavid Howells 			return yfs_fs_make_dir(fc, name, mode, dvnode_scb,
628a58823acSDavid Howells 					       newfid, new_scb);
62930062bd1SDavid Howells 		else
630a58823acSDavid Howells 			return yfs_fs_create_file(fc, name, mode, dvnode_scb,
631a58823acSDavid Howells 						  newfid, new_scb);
63230062bd1SDavid Howells 	}
63330062bd1SDavid Howells 
634260a9803SDavid Howells 	_enter("");
635260a9803SDavid Howells 
636260a9803SDavid Howells 	namesz = strlen(name);
637260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
638260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
639260a9803SDavid Howells 
640025db80cSDavid Howells 	call = afs_alloc_flat_call(
641025db80cSDavid Howells 		net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
642025db80cSDavid Howells 		reqsz, (3 + 21 + 21 + 3 + 6) * 4);
643260a9803SDavid Howells 	if (!call)
644260a9803SDavid Howells 		return -ENOMEM;
645260a9803SDavid Howells 
646d2ddc776SDavid Howells 	call->key = fc->key;
647a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
648ffba718eSDavid Howells 	call->out_fid = newfid;
649a58823acSDavid Howells 	call->out_scb = new_scb;
650260a9803SDavid Howells 
651260a9803SDavid Howells 	/* marshall the parameters */
652260a9803SDavid Howells 	bp = call->request;
653260a9803SDavid Howells 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
654ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
655ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
656ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
657260a9803SDavid Howells 	*bp++ = htonl(namesz);
658260a9803SDavid Howells 	memcpy(bp, name, namesz);
659260a9803SDavid Howells 	bp = (void *) bp + namesz;
660260a9803SDavid Howells 	if (padsz > 0) {
661260a9803SDavid Howells 		memset(bp, 0, padsz);
662260a9803SDavid Howells 		bp = (void *) bp + padsz;
663260a9803SDavid Howells 	}
664ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
665ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
666260a9803SDavid Howells 	*bp++ = 0; /* owner */
667260a9803SDavid Howells 	*bp++ = 0; /* group */
668260a9803SDavid Howells 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
669260a9803SDavid Howells 	*bp++ = 0; /* segment size */
670260a9803SDavid Howells 
671d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
672ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
67320b8391fSDavid Howells 	afs_set_fc_call(call, fc);
6740b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
6750b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
676260a9803SDavid Howells }
677260a9803SDavid Howells 
678260a9803SDavid Howells /*
679ffba718eSDavid Howells  * Deliver reply data to any operation that returns directory status and volume
680b10494afSJoe Gorse  * sync.
681260a9803SDavid Howells  */
682ffba718eSDavid Howells static int afs_deliver_fs_dir_status_and_vol(struct afs_call *call)
683260a9803SDavid Howells {
684260a9803SDavid Howells 	const __be32 *bp;
685372ee163SDavid Howells 	int ret;
686260a9803SDavid Howells 
687d001648eSDavid Howells 	ret = afs_transfer_reply(call);
688372ee163SDavid Howells 	if (ret < 0)
689372ee163SDavid Howells 		return ret;
690260a9803SDavid Howells 
691260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
692260a9803SDavid Howells 	bp = call->buffer;
693a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
694160cb957SDavid Howells 	if (ret < 0)
695160cb957SDavid Howells 		return ret;
696ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
697260a9803SDavid Howells 
698260a9803SDavid Howells 	_leave(" = 0 [done]");
699260a9803SDavid Howells 	return 0;
700260a9803SDavid Howells }
701260a9803SDavid Howells 
702260a9803SDavid Howells /*
703260a9803SDavid Howells  * FS.RemoveDir/FS.RemoveFile operation type
704260a9803SDavid Howells  */
705025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveFile = {
706025db80cSDavid Howells 	.name		= "FS.RemoveFile",
707025db80cSDavid Howells 	.op		= afs_FS_RemoveFile,
708ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
709025db80cSDavid Howells 	.destructor	= afs_flat_call_destructor,
710025db80cSDavid Howells };
711025db80cSDavid Howells 
712025db80cSDavid Howells static const struct afs_call_type afs_RXFSRemoveDir = {
713025db80cSDavid Howells 	.name		= "FS.RemoveDir",
714025db80cSDavid Howells 	.op		= afs_FS_RemoveDir,
715ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_dir_status_and_vol,
716260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
717260a9803SDavid Howells };
718260a9803SDavid Howells 
719260a9803SDavid Howells /*
720260a9803SDavid Howells  * remove a file or directory
721260a9803SDavid Howells  */
72230062bd1SDavid Howells int afs_fs_remove(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
723a58823acSDavid Howells 		  const char *name, bool isdir, struct afs_status_cb *dvnode_scb)
724260a9803SDavid Howells {
72530062bd1SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
726260a9803SDavid Howells 	struct afs_call *call;
72730062bd1SDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
728260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
729260a9803SDavid Howells 	__be32 *bp;
730260a9803SDavid Howells 
73130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
732a58823acSDavid Howells 		return yfs_fs_remove(fc, vnode, name, isdir, dvnode_scb);
73330062bd1SDavid Howells 
734260a9803SDavid Howells 	_enter("");
735260a9803SDavid Howells 
736260a9803SDavid Howells 	namesz = strlen(name);
737260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
738260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
739260a9803SDavid Howells 
740025db80cSDavid Howells 	call = afs_alloc_flat_call(
741025db80cSDavid Howells 		net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
742025db80cSDavid Howells 		reqsz, (21 + 6) * 4);
743260a9803SDavid Howells 	if (!call)
744260a9803SDavid Howells 		return -ENOMEM;
745260a9803SDavid Howells 
746d2ddc776SDavid Howells 	call->key = fc->key;
747a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
748260a9803SDavid Howells 
749260a9803SDavid Howells 	/* marshall the parameters */
750260a9803SDavid Howells 	bp = call->request;
751260a9803SDavid Howells 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
75230062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
75330062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
75430062bd1SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
755260a9803SDavid Howells 	*bp++ = htonl(namesz);
756260a9803SDavid Howells 	memcpy(bp, name, namesz);
757260a9803SDavid Howells 	bp = (void *) bp + namesz;
758260a9803SDavid Howells 	if (padsz > 0) {
759260a9803SDavid Howells 		memset(bp, 0, padsz);
760260a9803SDavid Howells 		bp = (void *) bp + padsz;
761260a9803SDavid Howells 	}
762260a9803SDavid Howells 
763d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
76480548b03SDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
76520b8391fSDavid Howells 	afs_set_fc_call(call, fc);
7660b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
7670b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
768260a9803SDavid Howells }
769260a9803SDavid Howells 
770260a9803SDavid Howells /*
771260a9803SDavid Howells  * deliver reply data to an FS.Link
772260a9803SDavid Howells  */
773d001648eSDavid Howells static int afs_deliver_fs_link(struct afs_call *call)
774260a9803SDavid Howells {
775260a9803SDavid Howells 	const __be32 *bp;
776372ee163SDavid Howells 	int ret;
777260a9803SDavid Howells 
778d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
779260a9803SDavid Howells 
780d001648eSDavid Howells 	ret = afs_transfer_reply(call);
781372ee163SDavid Howells 	if (ret < 0)
782372ee163SDavid Howells 		return ret;
783260a9803SDavid Howells 
784260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
785260a9803SDavid Howells 	bp = call->buffer;
786a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
787160cb957SDavid Howells 	if (ret < 0)
788160cb957SDavid Howells 		return ret;
789a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
790160cb957SDavid Howells 	if (ret < 0)
791160cb957SDavid Howells 		return ret;
792ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
793260a9803SDavid Howells 
794260a9803SDavid Howells 	_leave(" = 0 [done]");
795260a9803SDavid Howells 	return 0;
796260a9803SDavid Howells }
797260a9803SDavid Howells 
798260a9803SDavid Howells /*
799260a9803SDavid Howells  * FS.Link operation type
800260a9803SDavid Howells  */
801260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
802260a9803SDavid Howells 	.name		= "FS.Link",
803025db80cSDavid Howells 	.op		= afs_FS_Link,
804260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
805260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
806260a9803SDavid Howells };
807260a9803SDavid Howells 
808260a9803SDavid Howells /*
809260a9803SDavid Howells  * make a hard link
810260a9803SDavid Howells  */
811d2ddc776SDavid Howells int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
812a58823acSDavid Howells 		const char *name,
813a58823acSDavid Howells 		struct afs_status_cb *dvnode_scb,
814a58823acSDavid Howells 		struct afs_status_cb *vnode_scb)
815260a9803SDavid Howells {
816d2ddc776SDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
817260a9803SDavid Howells 	struct afs_call *call;
818f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
819260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
820260a9803SDavid Howells 	__be32 *bp;
821260a9803SDavid Howells 
82230062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
823a58823acSDavid Howells 		return yfs_fs_link(fc, vnode, name, dvnode_scb, vnode_scb);
82430062bd1SDavid Howells 
825260a9803SDavid Howells 	_enter("");
826260a9803SDavid Howells 
827260a9803SDavid Howells 	namesz = strlen(name);
828260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
829260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
830260a9803SDavid Howells 
831f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
832260a9803SDavid Howells 	if (!call)
833260a9803SDavid Howells 		return -ENOMEM;
834260a9803SDavid Howells 
835d2ddc776SDavid Howells 	call->key = fc->key;
836a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
837a58823acSDavid Howells 	call->out_scb = vnode_scb;
838260a9803SDavid Howells 
839260a9803SDavid Howells 	/* marshall the parameters */
840260a9803SDavid Howells 	bp = call->request;
841260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
842260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
843260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
844260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
845260a9803SDavid Howells 	*bp++ = htonl(namesz);
846260a9803SDavid Howells 	memcpy(bp, name, namesz);
847260a9803SDavid Howells 	bp = (void *) bp + namesz;
848260a9803SDavid Howells 	if (padsz > 0) {
849260a9803SDavid Howells 		memset(bp, 0, padsz);
850260a9803SDavid Howells 		bp = (void *) bp + padsz;
851260a9803SDavid Howells 	}
852260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
853260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
854260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
855260a9803SDavid Howells 
856d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
85780548b03SDavid Howells 	trace_afs_make_fs_call1(call, &vnode->fid, name);
85820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
8590b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
8600b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
861260a9803SDavid Howells }
862260a9803SDavid Howells 
863260a9803SDavid Howells /*
864260a9803SDavid Howells  * deliver reply data to an FS.Symlink
865260a9803SDavid Howells  */
866d001648eSDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call)
867260a9803SDavid Howells {
868260a9803SDavid Howells 	const __be32 *bp;
869372ee163SDavid Howells 	int ret;
870260a9803SDavid Howells 
871d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
872260a9803SDavid Howells 
873d001648eSDavid Howells 	ret = afs_transfer_reply(call);
874372ee163SDavid Howells 	if (ret < 0)
875372ee163SDavid Howells 		return ret;
876260a9803SDavid Howells 
877260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
878260a9803SDavid Howells 	bp = call->buffer;
879ffba718eSDavid Howells 	xdr_decode_AFSFid(&bp, call->out_fid);
880a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
881160cb957SDavid Howells 	if (ret < 0)
882160cb957SDavid Howells 		return ret;
883a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
884160cb957SDavid Howells 	if (ret < 0)
885160cb957SDavid Howells 		return ret;
886ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
887260a9803SDavid Howells 
888260a9803SDavid Howells 	_leave(" = 0 [done]");
889260a9803SDavid Howells 	return 0;
890260a9803SDavid Howells }
891260a9803SDavid Howells 
892260a9803SDavid Howells /*
893260a9803SDavid Howells  * FS.Symlink operation type
894260a9803SDavid Howells  */
895260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
896260a9803SDavid Howells 	.name		= "FS.Symlink",
897025db80cSDavid Howells 	.op		= afs_FS_Symlink,
898260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
899260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
900260a9803SDavid Howells };
901260a9803SDavid Howells 
902260a9803SDavid Howells /*
903260a9803SDavid Howells  * create a symbolic link
904260a9803SDavid Howells  */
9058b2a464cSDavid Howells int afs_fs_symlink(struct afs_fs_cursor *fc,
906260a9803SDavid Howells 		   const char *name,
907260a9803SDavid Howells 		   const char *contents,
908a58823acSDavid Howells 		   struct afs_status_cb *dvnode_scb,
909260a9803SDavid Howells 		   struct afs_fid *newfid,
910a58823acSDavid Howells 		   struct afs_status_cb *new_scb)
911260a9803SDavid Howells {
912ffba718eSDavid Howells 	struct afs_vnode *dvnode = fc->vnode;
913260a9803SDavid Howells 	struct afs_call *call;
914ffba718eSDavid Howells 	struct afs_net *net = afs_v2net(dvnode);
915260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
916260a9803SDavid Howells 	__be32 *bp;
917260a9803SDavid Howells 
91830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
919a58823acSDavid Howells 		return yfs_fs_symlink(fc, name, contents, dvnode_scb,
920a58823acSDavid Howells 				      newfid, new_scb);
92130062bd1SDavid Howells 
922260a9803SDavid Howells 	_enter("");
923260a9803SDavid Howells 
924260a9803SDavid Howells 	namesz = strlen(name);
925260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
926260a9803SDavid Howells 
927260a9803SDavid Howells 	c_namesz = strlen(contents);
928260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
929260a9803SDavid Howells 
930260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
931260a9803SDavid Howells 
932f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
933260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
934260a9803SDavid Howells 	if (!call)
935260a9803SDavid Howells 		return -ENOMEM;
936260a9803SDavid Howells 
937d2ddc776SDavid Howells 	call->key = fc->key;
938a58823acSDavid Howells 	call->out_dir_scb = dvnode_scb;
939ffba718eSDavid Howells 	call->out_fid = newfid;
940a58823acSDavid Howells 	call->out_scb = new_scb;
941260a9803SDavid Howells 
942260a9803SDavid Howells 	/* marshall the parameters */
943260a9803SDavid Howells 	bp = call->request;
944260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
945ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
946ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
947ffba718eSDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
948260a9803SDavid Howells 	*bp++ = htonl(namesz);
949260a9803SDavid Howells 	memcpy(bp, name, namesz);
950260a9803SDavid Howells 	bp = (void *) bp + namesz;
951260a9803SDavid Howells 	if (padsz > 0) {
952260a9803SDavid Howells 		memset(bp, 0, padsz);
953260a9803SDavid Howells 		bp = (void *) bp + padsz;
954260a9803SDavid Howells 	}
955260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
956260a9803SDavid Howells 	memcpy(bp, contents, c_namesz);
957260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
958260a9803SDavid Howells 	if (c_padsz > 0) {
959260a9803SDavid Howells 		memset(bp, 0, c_padsz);
960260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
961260a9803SDavid Howells 	}
962ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
963ffba718eSDavid Howells 	*bp++ = htonl(dvnode->vfs_inode.i_mtime.tv_sec); /* mtime */
964260a9803SDavid Howells 	*bp++ = 0; /* owner */
965260a9803SDavid Howells 	*bp++ = 0; /* group */
966260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
967260a9803SDavid Howells 	*bp++ = 0; /* segment size */
968260a9803SDavid Howells 
969d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
970ffba718eSDavid Howells 	trace_afs_make_fs_call1(call, &dvnode->fid, name);
97120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
9720b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
9730b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
974260a9803SDavid Howells }
975260a9803SDavid Howells 
976260a9803SDavid Howells /*
977260a9803SDavid Howells  * deliver reply data to an FS.Rename
978260a9803SDavid Howells  */
979d001648eSDavid Howells static int afs_deliver_fs_rename(struct afs_call *call)
980260a9803SDavid Howells {
981260a9803SDavid Howells 	const __be32 *bp;
982372ee163SDavid Howells 	int ret;
983260a9803SDavid Howells 
984d001648eSDavid Howells 	ret = afs_transfer_reply(call);
985372ee163SDavid Howells 	if (ret < 0)
986372ee163SDavid Howells 		return ret;
987260a9803SDavid Howells 
988260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
989260a9803SDavid Howells 	bp = call->buffer;
990a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_dir_scb);
991160cb957SDavid Howells 	if (ret < 0)
992160cb957SDavid Howells 		return ret;
993a58823acSDavid Howells 	if (call->out_dir_scb != call->out_scb) {
994a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
995160cb957SDavid Howells 		if (ret < 0)
996160cb957SDavid Howells 			return ret;
997160cb957SDavid Howells 	}
998ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
999260a9803SDavid Howells 
1000260a9803SDavid Howells 	_leave(" = 0 [done]");
1001260a9803SDavid Howells 	return 0;
1002260a9803SDavid Howells }
1003260a9803SDavid Howells 
1004260a9803SDavid Howells /*
1005260a9803SDavid Howells  * FS.Rename operation type
1006260a9803SDavid Howells  */
1007260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
1008260a9803SDavid Howells 	.name		= "FS.Rename",
1009025db80cSDavid Howells 	.op		= afs_FS_Rename,
1010260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
1011260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
1012260a9803SDavid Howells };
1013260a9803SDavid Howells 
1014260a9803SDavid Howells /*
1015a58823acSDavid Howells  * Rename/move a file or directory.
1016260a9803SDavid Howells  */
10178b2a464cSDavid Howells int afs_fs_rename(struct afs_fs_cursor *fc,
1018260a9803SDavid Howells 		  const char *orig_name,
1019260a9803SDavid Howells 		  struct afs_vnode *new_dvnode,
102063a4681fSDavid Howells 		  const char *new_name,
1021a58823acSDavid Howells 		  struct afs_status_cb *orig_dvnode_scb,
1022a58823acSDavid Howells 		  struct afs_status_cb *new_dvnode_scb)
1023260a9803SDavid Howells {
1024d2ddc776SDavid Howells 	struct afs_vnode *orig_dvnode = fc->vnode;
1025260a9803SDavid Howells 	struct afs_call *call;
1026f044c884SDavid Howells 	struct afs_net *net = afs_v2net(orig_dvnode);
1027260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1028260a9803SDavid Howells 	__be32 *bp;
1029260a9803SDavid Howells 
103030062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
103130062bd1SDavid Howells 		return yfs_fs_rename(fc, orig_name,
103230062bd1SDavid Howells 				     new_dvnode, new_name,
1033a58823acSDavid Howells 				     orig_dvnode_scb,
1034a58823acSDavid Howells 				     new_dvnode_scb);
103530062bd1SDavid Howells 
1036260a9803SDavid Howells 	_enter("");
1037260a9803SDavid Howells 
1038260a9803SDavid Howells 	o_namesz = strlen(orig_name);
1039260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
1040260a9803SDavid Howells 
1041260a9803SDavid Howells 	n_namesz = strlen(new_name);
1042260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
1043260a9803SDavid Howells 
1044260a9803SDavid Howells 	reqsz = (4 * 4) +
1045260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1046260a9803SDavid Howells 		(3 * 4) +
1047260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1048260a9803SDavid Howells 
1049f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1050260a9803SDavid Howells 	if (!call)
1051260a9803SDavid Howells 		return -ENOMEM;
1052260a9803SDavid Howells 
1053d2ddc776SDavid Howells 	call->key = fc->key;
1054a58823acSDavid Howells 	call->out_dir_scb = orig_dvnode_scb;
1055a58823acSDavid Howells 	call->out_scb = new_dvnode_scb;
1056260a9803SDavid Howells 
1057260a9803SDavid Howells 	/* marshall the parameters */
1058260a9803SDavid Howells 	bp = call->request;
1059260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1060260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vid);
1061260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vnode);
1062260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.unique);
1063260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1064260a9803SDavid Howells 	memcpy(bp, orig_name, o_namesz);
1065260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1066260a9803SDavid Howells 	if (o_padsz > 0) {
1067260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1068260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1069260a9803SDavid Howells 	}
1070260a9803SDavid Howells 
1071260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vid);
1072260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vnode);
1073260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.unique);
1074260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1075260a9803SDavid Howells 	memcpy(bp, new_name, n_namesz);
1076260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1077260a9803SDavid Howells 	if (n_padsz > 0) {
1078260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1079260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1080260a9803SDavid Howells 	}
1081260a9803SDavid Howells 
1082d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
108380548b03SDavid Howells 	trace_afs_make_fs_call2(call, &orig_dvnode->fid, orig_name, new_name);
108420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
10850b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
10860b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1087260a9803SDavid Howells }
108831143d5dSDavid Howells 
108931143d5dSDavid Howells /*
109031143d5dSDavid Howells  * deliver reply data to an FS.StoreData
109131143d5dSDavid Howells  */
1092d001648eSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call)
109331143d5dSDavid Howells {
109431143d5dSDavid Howells 	const __be32 *bp;
1095372ee163SDavid Howells 	int ret;
109631143d5dSDavid Howells 
1097d001648eSDavid Howells 	_enter("");
109831143d5dSDavid Howells 
1099d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1100372ee163SDavid Howells 	if (ret < 0)
1101372ee163SDavid Howells 		return ret;
110231143d5dSDavid Howells 
110331143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
110431143d5dSDavid Howells 	bp = call->buffer;
1105a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1106160cb957SDavid Howells 	if (ret < 0)
1107160cb957SDavid Howells 		return ret;
1108ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
110931143d5dSDavid Howells 
111031143d5dSDavid Howells 	_leave(" = 0 [done]");
111131143d5dSDavid Howells 	return 0;
111231143d5dSDavid Howells }
111331143d5dSDavid Howells 
111431143d5dSDavid Howells /*
111531143d5dSDavid Howells  * FS.StoreData operation type
111631143d5dSDavid Howells  */
111731143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
111831143d5dSDavid Howells 	.name		= "FS.StoreData",
1119025db80cSDavid Howells 	.op		= afs_FS_StoreData,
112031143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
112131143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
112231143d5dSDavid Howells };
112331143d5dSDavid Howells 
1124b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1125b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1126025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1127b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1128b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1129b9b1f8d5SDavid Howells };
1130b9b1f8d5SDavid Howells 
1131b9b1f8d5SDavid Howells /*
1132b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1133b9b1f8d5SDavid Howells  */
11348b2a464cSDavid Howells static int afs_fs_store_data64(struct afs_fs_cursor *fc,
11354343d008SDavid Howells 			       struct address_space *mapping,
1136b9b1f8d5SDavid Howells 			       pgoff_t first, pgoff_t last,
1137b9b1f8d5SDavid Howells 			       unsigned offset, unsigned to,
1138a58823acSDavid Howells 			       loff_t size, loff_t pos, loff_t i_size,
1139a58823acSDavid Howells 			       struct afs_status_cb *scb)
1140b9b1f8d5SDavid Howells {
11414343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1142b9b1f8d5SDavid Howells 	struct afs_call *call;
1143f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1144b9b1f8d5SDavid Howells 	__be32 *bp;
1145b9b1f8d5SDavid Howells 
11463b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
11474343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1148b9b1f8d5SDavid Howells 
1149f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
1150b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1151b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1152b9b1f8d5SDavid Howells 	if (!call)
1153b9b1f8d5SDavid Howells 		return -ENOMEM;
1154b9b1f8d5SDavid Howells 
11554343d008SDavid Howells 	call->key = fc->key;
11564343d008SDavid Howells 	call->mapping = mapping;
1157b9b1f8d5SDavid Howells 	call->first = first;
1158b9b1f8d5SDavid Howells 	call->last = last;
1159b9b1f8d5SDavid Howells 	call->first_offset = offset;
1160b9b1f8d5SDavid Howells 	call->last_to = to;
1161b9b1f8d5SDavid Howells 	call->send_pages = true;
1162a58823acSDavid Howells 	call->out_scb = scb;
1163b9b1f8d5SDavid Howells 
1164b9b1f8d5SDavid Howells 	/* marshall the parameters */
1165b9b1f8d5SDavid Howells 	bp = call->request;
1166b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1167b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1168b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1169b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1170b9b1f8d5SDavid Howells 
1171ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1172ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1173b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1174b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1175b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1176b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1177b9b1f8d5SDavid Howells 
1178b9b1f8d5SDavid Howells 	*bp++ = htonl(pos >> 32);
1179b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) pos);
1180b9b1f8d5SDavid Howells 	*bp++ = htonl(size >> 32);
1181b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) size);
1182b9b1f8d5SDavid Howells 	*bp++ = htonl(i_size >> 32);
1183b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) i_size);
1184b9b1f8d5SDavid Howells 
1185025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
118620b8391fSDavid Howells 	afs_set_fc_call(call, fc);
11870b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
11880b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1189b9b1f8d5SDavid Howells }
1190b9b1f8d5SDavid Howells 
119131143d5dSDavid Howells /*
119231143d5dSDavid Howells  * store a set of pages
119331143d5dSDavid Howells  */
11944343d008SDavid Howells int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
119531143d5dSDavid Howells 		      pgoff_t first, pgoff_t last,
1196a58823acSDavid Howells 		      unsigned offset, unsigned to,
1197a58823acSDavid Howells 		      struct afs_status_cb *scb)
119831143d5dSDavid Howells {
11994343d008SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
120031143d5dSDavid Howells 	struct afs_call *call;
1201f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
120231143d5dSDavid Howells 	loff_t size, pos, i_size;
120331143d5dSDavid Howells 	__be32 *bp;
120431143d5dSDavid Howells 
120530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1206a58823acSDavid Howells 		return yfs_fs_store_data(fc, mapping, first, last, offset, to, scb);
120730062bd1SDavid Howells 
12083b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
12094343d008SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
121031143d5dSDavid Howells 
1211146a1192SDavid Howells 	size = (loff_t)to - (loff_t)offset;
121231143d5dSDavid Howells 	if (first != last)
121331143d5dSDavid Howells 		size += (loff_t)(last - first) << PAGE_SHIFT;
121431143d5dSDavid Howells 	pos = (loff_t)first << PAGE_SHIFT;
121531143d5dSDavid Howells 	pos += offset;
121631143d5dSDavid Howells 
121731143d5dSDavid Howells 	i_size = i_size_read(&vnode->vfs_inode);
121831143d5dSDavid Howells 	if (pos + size > i_size)
121931143d5dSDavid Howells 		i_size = size + pos;
122031143d5dSDavid Howells 
122131143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
122231143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
122331143d5dSDavid Howells 	       (unsigned long long) i_size);
122431143d5dSDavid Howells 
1225b9b1f8d5SDavid Howells 	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
12264343d008SDavid Howells 		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
1227a58823acSDavid Howells 					   size, pos, i_size, scb);
122831143d5dSDavid Howells 
1229f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
123031143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
123131143d5dSDavid Howells 				   (21 + 6) * 4);
123231143d5dSDavid Howells 	if (!call)
123331143d5dSDavid Howells 		return -ENOMEM;
123431143d5dSDavid Howells 
12354343d008SDavid Howells 	call->key = fc->key;
12364343d008SDavid Howells 	call->mapping = mapping;
123731143d5dSDavid Howells 	call->first = first;
123831143d5dSDavid Howells 	call->last = last;
123931143d5dSDavid Howells 	call->first_offset = offset;
124031143d5dSDavid Howells 	call->last_to = to;
124131143d5dSDavid Howells 	call->send_pages = true;
1242a58823acSDavid Howells 	call->out_scb = scb;
124331143d5dSDavid Howells 
124431143d5dSDavid Howells 	/* marshall the parameters */
124531143d5dSDavid Howells 	bp = call->request;
124631143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
124731143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
124831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
124931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
125031143d5dSDavid Howells 
1251ab94f5d0SMarc Dionne 	*bp++ = htonl(AFS_SET_MTIME); /* mask */
1252ab94f5d0SMarc Dionne 	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
125331143d5dSDavid Howells 	*bp++ = 0; /* owner */
125431143d5dSDavid Howells 	*bp++ = 0; /* group */
125531143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
125631143d5dSDavid Howells 	*bp++ = 0; /* segment size */
125731143d5dSDavid Howells 
125831143d5dSDavid Howells 	*bp++ = htonl(pos);
125931143d5dSDavid Howells 	*bp++ = htonl(size);
126031143d5dSDavid Howells 	*bp++ = htonl(i_size);
126131143d5dSDavid Howells 
1262d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1263025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
126420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
12650b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
12660b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
126731143d5dSDavid Howells }
126831143d5dSDavid Howells 
126931143d5dSDavid Howells /*
127031143d5dSDavid Howells  * deliver reply data to an FS.StoreStatus
127131143d5dSDavid Howells  */
1272d001648eSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call)
127331143d5dSDavid Howells {
127431143d5dSDavid Howells 	const __be32 *bp;
1275372ee163SDavid Howells 	int ret;
127631143d5dSDavid Howells 
1277d001648eSDavid Howells 	_enter("");
127831143d5dSDavid Howells 
1279d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1280372ee163SDavid Howells 	if (ret < 0)
1281372ee163SDavid Howells 		return ret;
128231143d5dSDavid Howells 
128331143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
128431143d5dSDavid Howells 	bp = call->buffer;
1285a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1286160cb957SDavid Howells 	if (ret < 0)
1287160cb957SDavid Howells 		return ret;
1288ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
128931143d5dSDavid Howells 
129031143d5dSDavid Howells 	_leave(" = 0 [done]");
129131143d5dSDavid Howells 	return 0;
129231143d5dSDavid Howells }
129331143d5dSDavid Howells 
129431143d5dSDavid Howells /*
129531143d5dSDavid Howells  * FS.StoreStatus operation type
129631143d5dSDavid Howells  */
129731143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
129831143d5dSDavid Howells 	.name		= "FS.StoreStatus",
1299025db80cSDavid Howells 	.op		= afs_FS_StoreStatus,
130031143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130131143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
130231143d5dSDavid Howells };
130331143d5dSDavid Howells 
130431143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
130531143d5dSDavid Howells 	.name		= "FS.StoreData",
1306025db80cSDavid Howells 	.op		= afs_FS_StoreData,
130731143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
130831143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
130931143d5dSDavid Howells };
131031143d5dSDavid Howells 
1311b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1312b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1313025db80cSDavid Howells 	.op		= afs_FS_StoreData64,
1314b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_status,
1315b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1316b9b1f8d5SDavid Howells };
1317b9b1f8d5SDavid Howells 
1318b9b1f8d5SDavid Howells /*
1319b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1320b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1321b9b1f8d5SDavid Howells  */
1322a58823acSDavid Howells static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr,
1323a58823acSDavid Howells 				 struct afs_status_cb *scb)
1324b9b1f8d5SDavid Howells {
1325d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1326b9b1f8d5SDavid Howells 	struct afs_call *call;
1327f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1328b9b1f8d5SDavid Howells 	__be32 *bp;
1329b9b1f8d5SDavid Howells 
13303b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1331d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1332b9b1f8d5SDavid Howells 
1333b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1334b9b1f8d5SDavid Howells 
1335f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
1336b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1337b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1338b9b1f8d5SDavid Howells 	if (!call)
1339b9b1f8d5SDavid Howells 		return -ENOMEM;
1340b9b1f8d5SDavid Howells 
1341d2ddc776SDavid Howells 	call->key = fc->key;
1342a58823acSDavid Howells 	call->out_scb = scb;
1343b9b1f8d5SDavid Howells 
1344b9b1f8d5SDavid Howells 	/* marshall the parameters */
1345b9b1f8d5SDavid Howells 	bp = call->request;
1346b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1347b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1348b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1349b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1350b9b1f8d5SDavid Howells 
1351b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1352b9b1f8d5SDavid Howells 
13538c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* position of start of write */
13548c7ae38dSDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1355b9b1f8d5SDavid Howells 	*bp++ = 0;				/* size of write */
1356b9b1f8d5SDavid Howells 	*bp++ = 0;
1357b9b1f8d5SDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
1358b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1359b9b1f8d5SDavid Howells 
1360d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1361025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
136220b8391fSDavid Howells 	afs_set_fc_call(call, fc);
13630b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
13640b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1365b9b1f8d5SDavid Howells }
1366b9b1f8d5SDavid Howells 
136731143d5dSDavid Howells /*
136831143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
136931143d5dSDavid Howells  * so as to alter the file size also
137031143d5dSDavid Howells  */
1371a58823acSDavid Howells static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr,
1372a58823acSDavid Howells 			       struct afs_status_cb *scb)
137331143d5dSDavid Howells {
1374d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
137531143d5dSDavid Howells 	struct afs_call *call;
1376f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
137731143d5dSDavid Howells 	__be32 *bp;
137831143d5dSDavid Howells 
13793b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1380d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
138131143d5dSDavid Howells 
138231143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1383b9b1f8d5SDavid Howells 	if (attr->ia_size >> 32)
1384a58823acSDavid Howells 		return afs_fs_setattr_size64(fc, attr, scb);
138531143d5dSDavid Howells 
1386f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
138731143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
138831143d5dSDavid Howells 				   (21 + 6) * 4);
138931143d5dSDavid Howells 	if (!call)
139031143d5dSDavid Howells 		return -ENOMEM;
139131143d5dSDavid Howells 
1392d2ddc776SDavid Howells 	call->key = fc->key;
1393a58823acSDavid Howells 	call->out_scb = scb;
139431143d5dSDavid Howells 
139531143d5dSDavid Howells 	/* marshall the parameters */
139631143d5dSDavid Howells 	bp = call->request;
139731143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
139831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
139931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
140031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
140131143d5dSDavid Howells 
140231143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
140331143d5dSDavid Howells 
14048c7ae38dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* position of start of write */
140531143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
140631143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
140731143d5dSDavid Howells 
1408d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1409025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
141020b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14110b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14120b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
141331143d5dSDavid Howells }
141431143d5dSDavid Howells 
141531143d5dSDavid Howells /*
141631143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
141731143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
141831143d5dSDavid Howells  */
1419a58823acSDavid Howells int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr,
1420a58823acSDavid Howells 		   struct afs_status_cb *scb)
142131143d5dSDavid Howells {
1422d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
142331143d5dSDavid Howells 	struct afs_call *call;
1424f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
142531143d5dSDavid Howells 	__be32 *bp;
142631143d5dSDavid Howells 
142730062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1428a58823acSDavid Howells 		return yfs_fs_setattr(fc, attr, scb);
142930062bd1SDavid Howells 
143031143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
1431a58823acSDavid Howells 		return afs_fs_setattr_size(fc, attr, scb);
143231143d5dSDavid Howells 
14333b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
1434d2ddc776SDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
143531143d5dSDavid Howells 
1436f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
143731143d5dSDavid Howells 				   (4 + 6) * 4,
143831143d5dSDavid Howells 				   (21 + 6) * 4);
143931143d5dSDavid Howells 	if (!call)
144031143d5dSDavid Howells 		return -ENOMEM;
144131143d5dSDavid Howells 
1442d2ddc776SDavid Howells 	call->key = fc->key;
1443a58823acSDavid Howells 	call->out_scb = scb;
144431143d5dSDavid Howells 
144531143d5dSDavid Howells 	/* marshall the parameters */
144631143d5dSDavid Howells 	bp = call->request;
144731143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
144831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
144931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
145031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
145131143d5dSDavid Howells 
145231143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
145331143d5dSDavid Howells 
1454d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1455025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
145620b8391fSDavid Howells 	afs_set_fc_call(call, fc);
14570b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
14580b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
145931143d5dSDavid Howells }
146045222b9eSDavid Howells 
146145222b9eSDavid Howells /*
146245222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
146345222b9eSDavid Howells  */
1464d001648eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call)
146545222b9eSDavid Howells {
146645222b9eSDavid Howells 	const __be32 *bp;
146745222b9eSDavid Howells 	char *p;
146812bdcf33SDavid Howells 	u32 size;
146945222b9eSDavid Howells 	int ret;
147045222b9eSDavid Howells 
1471d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
147245222b9eSDavid Howells 
147345222b9eSDavid Howells 	switch (call->unmarshall) {
147445222b9eSDavid Howells 	case 0:
147545222b9eSDavid Howells 		call->unmarshall++;
147612bdcf33SDavid Howells 		afs_extract_to_buf(call, 12 * 4);
147729881608SGustavo A. R. Silva 		/* Fall through */
147845222b9eSDavid Howells 
147929881608SGustavo A. R. Silva 		/* extract the returned status record */
148045222b9eSDavid Howells 	case 1:
148145222b9eSDavid Howells 		_debug("extract status");
148212bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1483372ee163SDavid Howells 		if (ret < 0)
1484372ee163SDavid Howells 			return ret;
148545222b9eSDavid Howells 
148645222b9eSDavid Howells 		bp = call->buffer;
1487ffba718eSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, call->out_volstatus);
148845222b9eSDavid Howells 		call->unmarshall++;
148912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
149029881608SGustavo A. R. Silva 		/* Fall through */
149145222b9eSDavid Howells 
149229881608SGustavo A. R. Silva 		/* extract the volume name length */
149345222b9eSDavid Howells 	case 2:
149412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1495372ee163SDavid Howells 		if (ret < 0)
1496372ee163SDavid Howells 			return ret;
149745222b9eSDavid Howells 
149845222b9eSDavid Howells 		call->count = ntohl(call->tmp);
149945222b9eSDavid Howells 		_debug("volname length: %u", call->count);
150045222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1501160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1502160cb957SDavid Howells 						  afs_eproto_volname_len);
150312bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1504ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
150545222b9eSDavid Howells 		call->unmarshall++;
150629881608SGustavo A. R. Silva 		/* Fall through */
150745222b9eSDavid Howells 
150829881608SGustavo A. R. Silva 		/* extract the volume name */
150945222b9eSDavid Howells 	case 3:
151045222b9eSDavid Howells 		_debug("extract volname");
151112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1512372ee163SDavid Howells 		if (ret < 0)
1513372ee163SDavid Howells 			return ret;
151445222b9eSDavid Howells 
1515ffba718eSDavid Howells 		p = call->buffer;
151645222b9eSDavid Howells 		p[call->count] = 0;
151745222b9eSDavid Howells 		_debug("volname '%s'", p);
151812bdcf33SDavid Howells 		afs_extract_to_tmp(call);
151945222b9eSDavid Howells 		call->unmarshall++;
152029881608SGustavo A. R. Silva 		/* Fall through */
152145222b9eSDavid Howells 
152229881608SGustavo A. R. Silva 		/* extract the offline message length */
152312bdcf33SDavid Howells 	case 4:
152412bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1525372ee163SDavid Howells 		if (ret < 0)
1526372ee163SDavid Howells 			return ret;
152745222b9eSDavid Howells 
152845222b9eSDavid Howells 		call->count = ntohl(call->tmp);
152945222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
153045222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1531160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1532160cb957SDavid Howells 						  afs_eproto_offline_msg_len);
153312bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1534ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
153545222b9eSDavid Howells 		call->unmarshall++;
153629881608SGustavo A. R. Silva 		/* Fall through */
153745222b9eSDavid Howells 
153829881608SGustavo A. R. Silva 		/* extract the offline message */
153912bdcf33SDavid Howells 	case 5:
154045222b9eSDavid Howells 		_debug("extract offline");
154112bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1542372ee163SDavid Howells 		if (ret < 0)
1543372ee163SDavid Howells 			return ret;
154445222b9eSDavid Howells 
1545ffba718eSDavid Howells 		p = call->buffer;
154645222b9eSDavid Howells 		p[call->count] = 0;
154745222b9eSDavid Howells 		_debug("offline '%s'", p);
154845222b9eSDavid Howells 
154912bdcf33SDavid Howells 		afs_extract_to_tmp(call);
155045222b9eSDavid Howells 		call->unmarshall++;
155129881608SGustavo A. R. Silva 		/* Fall through */
155245222b9eSDavid Howells 
155329881608SGustavo A. R. Silva 		/* extract the message of the day length */
155412bdcf33SDavid Howells 	case 6:
155512bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1556372ee163SDavid Howells 		if (ret < 0)
1557372ee163SDavid Howells 			return ret;
155845222b9eSDavid Howells 
155945222b9eSDavid Howells 		call->count = ntohl(call->tmp);
156045222b9eSDavid Howells 		_debug("motd length: %u", call->count);
156145222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
1562160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
1563160cb957SDavid Howells 						  afs_eproto_motd_len);
156412bdcf33SDavid Howells 		size = (call->count + 3) & ~3; /* It's padded */
1565ffba718eSDavid Howells 		afs_extract_to_buf(call, size);
156645222b9eSDavid Howells 		call->unmarshall++;
156729881608SGustavo A. R. Silva 		/* Fall through */
156845222b9eSDavid Howells 
156929881608SGustavo A. R. Silva 		/* extract the message of the day */
157012bdcf33SDavid Howells 	case 7:
157145222b9eSDavid Howells 		_debug("extract motd");
157212bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1573372ee163SDavid Howells 		if (ret < 0)
1574372ee163SDavid Howells 			return ret;
157545222b9eSDavid Howells 
1576ffba718eSDavid Howells 		p = call->buffer;
157745222b9eSDavid Howells 		p[call->count] = 0;
157845222b9eSDavid Howells 		_debug("motd '%s'", p);
157945222b9eSDavid Howells 
158045222b9eSDavid Howells 		call->unmarshall++;
158145222b9eSDavid Howells 
158212bdcf33SDavid Howells 	case 8:
158345222b9eSDavid Howells 		break;
158445222b9eSDavid Howells 	}
158545222b9eSDavid Howells 
158645222b9eSDavid Howells 	_leave(" = 0 [done]");
158745222b9eSDavid Howells 	return 0;
158845222b9eSDavid Howells }
158945222b9eSDavid Howells 
159045222b9eSDavid Howells /*
159145222b9eSDavid Howells  * FS.GetVolumeStatus operation type
159245222b9eSDavid Howells  */
159345222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
159445222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
1595025db80cSDavid Howells 	.op		= afs_FS_GetVolumeStatus,
159645222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
1597ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
159845222b9eSDavid Howells };
159945222b9eSDavid Howells 
160045222b9eSDavid Howells /*
160145222b9eSDavid Howells  * fetch the status of a volume
160245222b9eSDavid Howells  */
16038b2a464cSDavid Howells int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
1604d2ddc776SDavid Howells 			     struct afs_volume_status *vs)
160545222b9eSDavid Howells {
1606d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
160745222b9eSDavid Howells 	struct afs_call *call;
1608f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
160945222b9eSDavid Howells 	__be32 *bp;
161045222b9eSDavid Howells 
161130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
161230062bd1SDavid Howells 		return yfs_fs_get_volume_status(fc, vs);
161330062bd1SDavid Howells 
161445222b9eSDavid Howells 	_enter("");
161545222b9eSDavid Howells 
1616ffba718eSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4,
1617ffba718eSDavid Howells 				   max(12 * 4, AFSOPAQUEMAX + 1));
1618ffba718eSDavid Howells 	if (!call)
161945222b9eSDavid Howells 		return -ENOMEM;
162045222b9eSDavid Howells 
1621d2ddc776SDavid Howells 	call->key = fc->key;
1622ffba718eSDavid Howells 	call->out_volstatus = vs;
162345222b9eSDavid Howells 
162445222b9eSDavid Howells 	/* marshall the parameters */
162545222b9eSDavid Howells 	bp = call->request;
162645222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
162745222b9eSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
162845222b9eSDavid Howells 
1629d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1630025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
163120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
16320b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
16330b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
163445222b9eSDavid Howells }
1635e8d6c554SDavid Howells 
1636e8d6c554SDavid Howells /*
1637e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1638e8d6c554SDavid Howells  */
1639d001648eSDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
1640e8d6c554SDavid Howells {
1641e8d6c554SDavid Howells 	const __be32 *bp;
1642372ee163SDavid Howells 	int ret;
1643e8d6c554SDavid Howells 
1644d001648eSDavid Howells 	_enter("{%u}", call->unmarshall);
1645e8d6c554SDavid Howells 
1646d001648eSDavid Howells 	ret = afs_transfer_reply(call);
1647372ee163SDavid Howells 	if (ret < 0)
1648372ee163SDavid Howells 		return ret;
1649e8d6c554SDavid Howells 
1650e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1651e8d6c554SDavid Howells 	bp = call->buffer;
1652ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
1653e8d6c554SDavid Howells 
1654e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1655e8d6c554SDavid Howells 	return 0;
1656e8d6c554SDavid Howells }
1657e8d6c554SDavid Howells 
1658e8d6c554SDavid Howells /*
1659e8d6c554SDavid Howells  * FS.SetLock operation type
1660e8d6c554SDavid Howells  */
1661e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1662e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1663025db80cSDavid Howells 	.op		= afs_FS_SetLock,
1664e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1665a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1666e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1667e8d6c554SDavid Howells };
1668e8d6c554SDavid Howells 
1669e8d6c554SDavid Howells /*
1670e8d6c554SDavid Howells  * FS.ExtendLock operation type
1671e8d6c554SDavid Howells  */
1672e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1673e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1674025db80cSDavid Howells 	.op		= afs_FS_ExtendLock,
1675e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1676a690f60aSDavid Howells 	.done		= afs_lock_op_done,
1677e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1678e8d6c554SDavid Howells };
1679e8d6c554SDavid Howells 
1680e8d6c554SDavid Howells /*
1681e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1682e8d6c554SDavid Howells  */
1683e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1684e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1685025db80cSDavid Howells 	.op		= afs_FS_ReleaseLock,
1686e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1687e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1688e8d6c554SDavid Howells };
1689e8d6c554SDavid Howells 
1690e8d6c554SDavid Howells /*
1691d2ddc776SDavid Howells  * Set a lock on a file
1692e8d6c554SDavid Howells  */
1693a58823acSDavid Howells int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type,
1694a58823acSDavid Howells 		    struct afs_status_cb *scb)
1695e8d6c554SDavid Howells {
1696d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1697e8d6c554SDavid Howells 	struct afs_call *call;
1698f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1699e8d6c554SDavid Howells 	__be32 *bp;
1700e8d6c554SDavid Howells 
170130062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1702a58823acSDavid Howells 		return yfs_fs_set_lock(fc, type, scb);
170330062bd1SDavid Howells 
1704e8d6c554SDavid Howells 	_enter("");
1705e8d6c554SDavid Howells 
1706f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
1707e8d6c554SDavid Howells 	if (!call)
1708e8d6c554SDavid Howells 		return -ENOMEM;
1709e8d6c554SDavid Howells 
1710d2ddc776SDavid Howells 	call->key = fc->key;
1711a58823acSDavid Howells 	call->lvnode = vnode;
1712a58823acSDavid Howells 	call->out_scb = scb;
1713e8d6c554SDavid Howells 
1714e8d6c554SDavid Howells 	/* marshall the parameters */
1715e8d6c554SDavid Howells 	bp = call->request;
1716e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1717e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1718e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1719e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1720e8d6c554SDavid Howells 	*bp++ = htonl(type);
1721e8d6c554SDavid Howells 
1722d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
17236c6c1d63SDavid Howells 	trace_afs_make_fs_calli(call, &vnode->fid, type);
172420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17250b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17260b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1727e8d6c554SDavid Howells }
1728e8d6c554SDavid Howells 
1729e8d6c554SDavid Howells /*
1730e8d6c554SDavid Howells  * extend a lock on a file
1731e8d6c554SDavid Howells  */
1732a58823acSDavid Howells int afs_fs_extend_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1733e8d6c554SDavid Howells {
1734d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1735e8d6c554SDavid Howells 	struct afs_call *call;
1736f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1737e8d6c554SDavid Howells 	__be32 *bp;
1738e8d6c554SDavid Howells 
173930062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1740a58823acSDavid Howells 		return yfs_fs_extend_lock(fc, scb);
174130062bd1SDavid Howells 
1742e8d6c554SDavid Howells 	_enter("");
1743e8d6c554SDavid Howells 
1744f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
1745e8d6c554SDavid Howells 	if (!call)
1746e8d6c554SDavid Howells 		return -ENOMEM;
1747e8d6c554SDavid Howells 
1748d2ddc776SDavid Howells 	call->key = fc->key;
1749a58823acSDavid Howells 	call->lvnode = vnode;
1750a58823acSDavid Howells 	call->out_scb = scb;
1751e8d6c554SDavid Howells 
1752e8d6c554SDavid Howells 	/* marshall the parameters */
1753e8d6c554SDavid Howells 	bp = call->request;
1754e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1755e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1756e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1757e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1758e8d6c554SDavid Howells 
1759d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1760025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
176120b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17620b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
17630b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1764e8d6c554SDavid Howells }
1765e8d6c554SDavid Howells 
1766e8d6c554SDavid Howells /*
1767e8d6c554SDavid Howells  * release a lock on a file
1768e8d6c554SDavid Howells  */
1769a58823acSDavid Howells int afs_fs_release_lock(struct afs_fs_cursor *fc, struct afs_status_cb *scb)
1770e8d6c554SDavid Howells {
1771d2ddc776SDavid Howells 	struct afs_vnode *vnode = fc->vnode;
1772e8d6c554SDavid Howells 	struct afs_call *call;
1773f044c884SDavid Howells 	struct afs_net *net = afs_v2net(vnode);
1774e8d6c554SDavid Howells 	__be32 *bp;
1775e8d6c554SDavid Howells 
177630062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1777a58823acSDavid Howells 		return yfs_fs_release_lock(fc, scb);
177830062bd1SDavid Howells 
1779e8d6c554SDavid Howells 	_enter("");
1780e8d6c554SDavid Howells 
1781f044c884SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1782e8d6c554SDavid Howells 	if (!call)
1783e8d6c554SDavid Howells 		return -ENOMEM;
1784e8d6c554SDavid Howells 
1785d2ddc776SDavid Howells 	call->key = fc->key;
1786a58823acSDavid Howells 	call->lvnode = vnode;
1787a58823acSDavid Howells 	call->out_scb = scb;
1788e8d6c554SDavid Howells 
1789e8d6c554SDavid Howells 	/* marshall the parameters */
1790e8d6c554SDavid Howells 	bp = call->request;
1791e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1792e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1793e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1794e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1795e8d6c554SDavid Howells 
1796d2ddc776SDavid Howells 	afs_use_fs_server(call, fc->cbi);
1797025db80cSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
179820b8391fSDavid Howells 	afs_set_fc_call(call, fc);
17990b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
18000b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
1801c435ee34SDavid Howells }
1802c435ee34SDavid Howells 
1803c435ee34SDavid Howells /*
1804c435ee34SDavid Howells  * Deliver reply data to an FS.GiveUpAllCallBacks operation.
1805c435ee34SDavid Howells  */
1806c435ee34SDavid Howells static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
1807c435ee34SDavid Howells {
1808c435ee34SDavid Howells 	return afs_transfer_reply(call);
1809c435ee34SDavid Howells }
1810c435ee34SDavid Howells 
1811c435ee34SDavid Howells /*
1812c435ee34SDavid Howells  * FS.GiveUpAllCallBacks operation type
1813c435ee34SDavid Howells  */
1814c435ee34SDavid Howells static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
1815c435ee34SDavid Howells 	.name		= "FS.GiveUpAllCallBacks",
1816025db80cSDavid Howells 	.op		= afs_FS_GiveUpAllCallBacks,
1817c435ee34SDavid Howells 	.deliver	= afs_deliver_fs_give_up_all_callbacks,
1818c435ee34SDavid Howells 	.destructor	= afs_flat_call_destructor,
1819c435ee34SDavid Howells };
1820c435ee34SDavid Howells 
1821c435ee34SDavid Howells /*
1822c435ee34SDavid Howells  * Flush all the callbacks we have on a server.
1823c435ee34SDavid Howells  */
1824d2ddc776SDavid Howells int afs_fs_give_up_all_callbacks(struct afs_net *net,
1825d2ddc776SDavid Howells 				 struct afs_server *server,
18268b2a464cSDavid Howells 				 struct afs_addr_cursor *ac,
1827d2ddc776SDavid Howells 				 struct key *key)
1828c435ee34SDavid Howells {
1829c435ee34SDavid Howells 	struct afs_call *call;
1830c435ee34SDavid Howells 	__be32 *bp;
1831c435ee34SDavid Howells 
1832c435ee34SDavid Howells 	_enter("");
1833c435ee34SDavid Howells 
1834d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1835c435ee34SDavid Howells 	if (!call)
1836c435ee34SDavid Howells 		return -ENOMEM;
1837c435ee34SDavid Howells 
1838c435ee34SDavid Howells 	call->key = key;
1839c435ee34SDavid Howells 
1840c435ee34SDavid Howells 	/* marshall the parameters */
1841c435ee34SDavid Howells 	bp = call->request;
1842c435ee34SDavid Howells 	*bp++ = htonl(FSGIVEUPALLCALLBACKS);
1843c435ee34SDavid Howells 
1844c435ee34SDavid Howells 	/* Can't take a ref on server */
18450b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
18460b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, ac);
1847d2ddc776SDavid Howells }
1848d2ddc776SDavid Howells 
1849d2ddc776SDavid Howells /*
1850d2ddc776SDavid Howells  * Deliver reply data to an FS.GetCapabilities operation.
1851d2ddc776SDavid Howells  */
1852d2ddc776SDavid Howells static int afs_deliver_fs_get_capabilities(struct afs_call *call)
1853d2ddc776SDavid Howells {
1854d2ddc776SDavid Howells 	u32 count;
1855d2ddc776SDavid Howells 	int ret;
1856d2ddc776SDavid Howells 
1857fc276122SDavid Howells 	_enter("{%u,%zu}", call->unmarshall, iov_iter_count(call->iter));
1858d2ddc776SDavid Howells 
1859d2ddc776SDavid Howells 	switch (call->unmarshall) {
1860d2ddc776SDavid Howells 	case 0:
186112bdcf33SDavid Howells 		afs_extract_to_tmp(call);
1862d2ddc776SDavid Howells 		call->unmarshall++;
186329881608SGustavo A. R. Silva 		/* Fall through */
1864d2ddc776SDavid Howells 
186529881608SGustavo A. R. Silva 		/* Extract the capabilities word count */
1866d2ddc776SDavid Howells 	case 1:
186712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
1868d2ddc776SDavid Howells 		if (ret < 0)
1869d2ddc776SDavid Howells 			return ret;
1870d2ddc776SDavid Howells 
1871d2ddc776SDavid Howells 		count = ntohl(call->tmp);
1872d2ddc776SDavid Howells 
1873d2ddc776SDavid Howells 		call->count = count;
1874d2ddc776SDavid Howells 		call->count2 = count;
187523a28913SDavid Howells 		afs_extract_discard(call, count * sizeof(__be32));
1876d2ddc776SDavid Howells 		call->unmarshall++;
187729881608SGustavo A. R. Silva 		/* Fall through */
1878d2ddc776SDavid Howells 
187929881608SGustavo A. R. Silva 		/* Extract capabilities words */
1880d2ddc776SDavid Howells 	case 2:
188112bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
1882d2ddc776SDavid Howells 		if (ret < 0)
1883d2ddc776SDavid Howells 			return ret;
1884d2ddc776SDavid Howells 
1885d2ddc776SDavid Howells 		/* TODO: Examine capabilities */
1886d2ddc776SDavid Howells 
1887d2ddc776SDavid Howells 		call->unmarshall++;
1888d2ddc776SDavid Howells 		break;
1889d2ddc776SDavid Howells 	}
1890d2ddc776SDavid Howells 
1891d2ddc776SDavid Howells 	_leave(" = 0 [done]");
1892d2ddc776SDavid Howells 	return 0;
1893d2ddc776SDavid Howells }
1894d2ddc776SDavid Howells 
1895d2ddc776SDavid Howells /*
1896d2ddc776SDavid Howells  * FS.GetCapabilities operation type
1897d2ddc776SDavid Howells  */
1898d2ddc776SDavid Howells static const struct afs_call_type afs_RXFSGetCapabilities = {
1899d2ddc776SDavid Howells 	.name		= "FS.GetCapabilities",
1900025db80cSDavid Howells 	.op		= afs_FS_GetCapabilities,
1901d2ddc776SDavid Howells 	.deliver	= afs_deliver_fs_get_capabilities,
19023bf0fb6fSDavid Howells 	.done		= afs_fileserver_probe_result,
1903ffba718eSDavid Howells 	.destructor	= afs_flat_call_destructor,
1904d2ddc776SDavid Howells };
1905d2ddc776SDavid Howells 
1906d2ddc776SDavid Howells /*
1907d2ddc776SDavid Howells  * Probe a fileserver for the capabilities that it supports.  This can
1908d2ddc776SDavid Howells  * return up to 196 words.
1909d2ddc776SDavid Howells  */
19100b9bf381SDavid Howells struct afs_call *afs_fs_get_capabilities(struct afs_net *net,
1911d2ddc776SDavid Howells 					 struct afs_server *server,
1912d2ddc776SDavid Howells 					 struct afs_addr_cursor *ac,
19133bf0fb6fSDavid Howells 					 struct key *key,
19140b9bf381SDavid Howells 					 unsigned int server_index)
1915d2ddc776SDavid Howells {
1916d2ddc776SDavid Howells 	struct afs_call *call;
1917d2ddc776SDavid Howells 	__be32 *bp;
1918d2ddc776SDavid Howells 
1919d2ddc776SDavid Howells 	_enter("");
1920d2ddc776SDavid Howells 
1921d2ddc776SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
1922d2ddc776SDavid Howells 	if (!call)
19230b9bf381SDavid Howells 		return ERR_PTR(-ENOMEM);
1924d2ddc776SDavid Howells 
1925d2ddc776SDavid Howells 	call->key = key;
192645218193SDavid Howells 	call->server = afs_get_server(server, afs_server_trace_get_caps);
1927ffba718eSDavid Howells 	call->server_index = server_index;
192830062bd1SDavid Howells 	call->upgrade = true;
19290b9bf381SDavid Howells 	call->async = true;
193094f699c9SDavid Howells 	call->max_lifespan = AFS_PROBE_MAX_LIFESPAN;
1931d2ddc776SDavid Howells 
1932d2ddc776SDavid Howells 	/* marshall the parameters */
1933d2ddc776SDavid Howells 	bp = call->request;
1934d2ddc776SDavid Howells 	*bp++ = htonl(FSGETCAPABILITIES);
1935d2ddc776SDavid Howells 
1936d2ddc776SDavid Howells 	/* Can't take a ref on server */
1937025db80cSDavid Howells 	trace_afs_make_fs_call(call, NULL);
19380b9bf381SDavid Howells 	afs_make_call(ac, call, GFP_NOFS);
19390b9bf381SDavid Howells 	return call;
1940e8d6c554SDavid Howells }
19415cf9dd55SDavid Howells 
19425cf9dd55SDavid Howells /*
19435cf9dd55SDavid Howells  * Deliver reply data to an FS.FetchStatus with no vnode.
19445cf9dd55SDavid Howells  */
19455cf9dd55SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call)
19465cf9dd55SDavid Howells {
19475cf9dd55SDavid Howells 	const __be32 *bp;
19485cf9dd55SDavid Howells 	int ret;
19495cf9dd55SDavid Howells 
19505cf9dd55SDavid Howells 	ret = afs_transfer_reply(call);
19515cf9dd55SDavid Howells 	if (ret < 0)
19525cf9dd55SDavid Howells 		return ret;
19535cf9dd55SDavid Howells 
19545cf9dd55SDavid Howells 	/* unmarshall the reply once we've received all of it */
19555cf9dd55SDavid Howells 	bp = call->buffer;
1956a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
1957160cb957SDavid Howells 	if (ret < 0)
1958160cb957SDavid Howells 		return ret;
1959a58823acSDavid Howells 	xdr_decode_AFSCallBack(&bp, call, call->out_scb);
1960a58823acSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
19615cf9dd55SDavid Howells 
19625cf9dd55SDavid Howells 	_leave(" = 0 [done]");
19635cf9dd55SDavid Howells 	return 0;
19645cf9dd55SDavid Howells }
19655cf9dd55SDavid Howells 
19665cf9dd55SDavid Howells /*
19675cf9dd55SDavid Howells  * FS.FetchStatus operation type
19685cf9dd55SDavid Howells  */
19695cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
19705cf9dd55SDavid Howells 	.name		= "FS.FetchStatus",
19715cf9dd55SDavid Howells 	.op		= afs_FS_FetchStatus,
19725cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
19735cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
19745cf9dd55SDavid Howells };
19755cf9dd55SDavid Howells 
19765cf9dd55SDavid Howells /*
19775cf9dd55SDavid Howells  * Fetch the status information for a fid without needing a vnode handle.
19785cf9dd55SDavid Howells  */
19795cf9dd55SDavid Howells int afs_fs_fetch_status(struct afs_fs_cursor *fc,
19805cf9dd55SDavid Howells 			struct afs_net *net,
19815cf9dd55SDavid Howells 			struct afs_fid *fid,
1982a58823acSDavid Howells 			struct afs_status_cb *scb,
19835cf9dd55SDavid Howells 			struct afs_volsync *volsync)
19845cf9dd55SDavid Howells {
19855cf9dd55SDavid Howells 	struct afs_call *call;
19865cf9dd55SDavid Howells 	__be32 *bp;
19875cf9dd55SDavid Howells 
198830062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
1989a58823acSDavid Howells 		return yfs_fs_fetch_status(fc, net, fid, scb, volsync);
199030062bd1SDavid Howells 
19913b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},,",
19925cf9dd55SDavid Howells 	       key_serial(fc->key), fid->vid, fid->vnode);
19935cf9dd55SDavid Howells 
19945cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
19955cf9dd55SDavid Howells 	if (!call) {
19965cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
19975cf9dd55SDavid Howells 		return -ENOMEM;
19985cf9dd55SDavid Howells 	}
19995cf9dd55SDavid Howells 
20005cf9dd55SDavid Howells 	call->key = fc->key;
2001ffba718eSDavid Howells 	call->out_fid = fid;
2002a58823acSDavid Howells 	call->out_scb = scb;
2003ffba718eSDavid Howells 	call->out_volsync = volsync;
20045cf9dd55SDavid Howells 
20055cf9dd55SDavid Howells 	/* marshall the parameters */
20065cf9dd55SDavid Howells 	bp = call->request;
20075cf9dd55SDavid Howells 	bp[0] = htonl(FSFETCHSTATUS);
20085cf9dd55SDavid Howells 	bp[1] = htonl(fid->vid);
20095cf9dd55SDavid Howells 	bp[2] = htonl(fid->vnode);
20105cf9dd55SDavid Howells 	bp[3] = htonl(fid->unique);
20115cf9dd55SDavid Howells 
20125cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
20135cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, fid);
201420b8391fSDavid Howells 	afs_set_fc_call(call, fc);
20150b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
20160b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
20175cf9dd55SDavid Howells }
20185cf9dd55SDavid Howells 
20195cf9dd55SDavid Howells /*
20205cf9dd55SDavid Howells  * Deliver reply data to an FS.InlineBulkStatus call
20215cf9dd55SDavid Howells  */
20225cf9dd55SDavid Howells static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
20235cf9dd55SDavid Howells {
202487182759SDavid Howells 	struct afs_status_cb *scb;
20255cf9dd55SDavid Howells 	const __be32 *bp;
20265cf9dd55SDavid Howells 	u32 tmp;
20275cf9dd55SDavid Howells 	int ret;
20285cf9dd55SDavid Howells 
20295cf9dd55SDavid Howells 	_enter("{%u}", call->unmarshall);
20305cf9dd55SDavid Howells 
20315cf9dd55SDavid Howells 	switch (call->unmarshall) {
20325cf9dd55SDavid Howells 	case 0:
203312bdcf33SDavid Howells 		afs_extract_to_tmp(call);
20345cf9dd55SDavid Howells 		call->unmarshall++;
203529881608SGustavo A. R. Silva 		/* Fall through */
20365cf9dd55SDavid Howells 
20375cf9dd55SDavid Howells 		/* Extract the file status count and array in two steps */
20385cf9dd55SDavid Howells 	case 1:
20395cf9dd55SDavid Howells 		_debug("extract status count");
204012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20415cf9dd55SDavid Howells 		if (ret < 0)
20425cf9dd55SDavid Howells 			return ret;
20435cf9dd55SDavid Howells 
20445cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20455cf9dd55SDavid Howells 		_debug("status count: %u/%u", tmp, call->count2);
20465cf9dd55SDavid Howells 		if (tmp != call->count2)
2047160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2048160cb957SDavid Howells 						  afs_eproto_ibulkst_count);
20495cf9dd55SDavid Howells 
20505cf9dd55SDavid Howells 		call->count = 0;
20515cf9dd55SDavid Howells 		call->unmarshall++;
20525cf9dd55SDavid Howells 	more_counts:
205312bdcf33SDavid Howells 		afs_extract_to_buf(call, 21 * sizeof(__be32));
2054e690c9e3SGustavo A. R. Silva 		/* Fall through */
205529881608SGustavo A. R. Silva 
20565cf9dd55SDavid Howells 	case 2:
20575cf9dd55SDavid Howells 		_debug("extract status array %u", call->count);
205812bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20595cf9dd55SDavid Howells 		if (ret < 0)
20605cf9dd55SDavid Howells 			return ret;
20615cf9dd55SDavid Howells 
20625cf9dd55SDavid Howells 		bp = call->buffer;
206387182759SDavid Howells 		scb = &call->out_scb[call->count];
2064a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, scb);
2065160cb957SDavid Howells 		if (ret < 0)
2066160cb957SDavid Howells 			return ret;
20675cf9dd55SDavid Howells 
20685cf9dd55SDavid Howells 		call->count++;
20695cf9dd55SDavid Howells 		if (call->count < call->count2)
20705cf9dd55SDavid Howells 			goto more_counts;
20715cf9dd55SDavid Howells 
20725cf9dd55SDavid Howells 		call->count = 0;
20735cf9dd55SDavid Howells 		call->unmarshall++;
207412bdcf33SDavid Howells 		afs_extract_to_tmp(call);
207529881608SGustavo A. R. Silva 		/* Fall through */
20765cf9dd55SDavid Howells 
20775cf9dd55SDavid Howells 		/* Extract the callback count and array in two steps */
20785cf9dd55SDavid Howells 	case 3:
20795cf9dd55SDavid Howells 		_debug("extract CB count");
208012bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20815cf9dd55SDavid Howells 		if (ret < 0)
20825cf9dd55SDavid Howells 			return ret;
20835cf9dd55SDavid Howells 
20845cf9dd55SDavid Howells 		tmp = ntohl(call->tmp);
20855cf9dd55SDavid Howells 		_debug("CB count: %u", tmp);
20865cf9dd55SDavid Howells 		if (tmp != call->count2)
2087160cb957SDavid Howells 			return afs_protocol_error(call, -EBADMSG,
2088160cb957SDavid Howells 						  afs_eproto_ibulkst_cb_count);
20895cf9dd55SDavid Howells 		call->count = 0;
20905cf9dd55SDavid Howells 		call->unmarshall++;
20915cf9dd55SDavid Howells 	more_cbs:
209212bdcf33SDavid Howells 		afs_extract_to_buf(call, 3 * sizeof(__be32));
2093e690c9e3SGustavo A. R. Silva 		/* Fall through */
209429881608SGustavo A. R. Silva 
20955cf9dd55SDavid Howells 	case 4:
20965cf9dd55SDavid Howells 		_debug("extract CB array");
209712bdcf33SDavid Howells 		ret = afs_extract_data(call, true);
20985cf9dd55SDavid Howells 		if (ret < 0)
20995cf9dd55SDavid Howells 			return ret;
21005cf9dd55SDavid Howells 
21015cf9dd55SDavid Howells 		_debug("unmarshall CB array");
21025cf9dd55SDavid Howells 		bp = call->buffer;
210387182759SDavid Howells 		scb = &call->out_scb[call->count];
2104a58823acSDavid Howells 		xdr_decode_AFSCallBack(&bp, call, scb);
21055cf9dd55SDavid Howells 		call->count++;
21065cf9dd55SDavid Howells 		if (call->count < call->count2)
21075cf9dd55SDavid Howells 			goto more_cbs;
21085cf9dd55SDavid Howells 
210912bdcf33SDavid Howells 		afs_extract_to_buf(call, 6 * sizeof(__be32));
21105cf9dd55SDavid Howells 		call->unmarshall++;
2111e690c9e3SGustavo A. R. Silva 		/* Fall through */
211229881608SGustavo A. R. Silva 
21135cf9dd55SDavid Howells 	case 5:
211412bdcf33SDavid Howells 		ret = afs_extract_data(call, false);
21155cf9dd55SDavid Howells 		if (ret < 0)
21165cf9dd55SDavid Howells 			return ret;
21175cf9dd55SDavid Howells 
21185cf9dd55SDavid Howells 		bp = call->buffer;
2119ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
21205cf9dd55SDavid Howells 
21215cf9dd55SDavid Howells 		call->unmarshall++;
21225cf9dd55SDavid Howells 
21235cf9dd55SDavid Howells 	case 6:
21245cf9dd55SDavid Howells 		break;
21255cf9dd55SDavid Howells 	}
21265cf9dd55SDavid Howells 
21275cf9dd55SDavid Howells 	_leave(" = 0 [done]");
21285cf9dd55SDavid Howells 	return 0;
21295cf9dd55SDavid Howells }
21305cf9dd55SDavid Howells 
21315cf9dd55SDavid Howells /*
21325cf9dd55SDavid Howells  * FS.InlineBulkStatus operation type
21335cf9dd55SDavid Howells  */
21345cf9dd55SDavid Howells static const struct afs_call_type afs_RXFSInlineBulkStatus = {
21355cf9dd55SDavid Howells 	.name		= "FS.InlineBulkStatus",
21365cf9dd55SDavid Howells 	.op		= afs_FS_InlineBulkStatus,
21375cf9dd55SDavid Howells 	.deliver	= afs_deliver_fs_inline_bulk_status,
21385cf9dd55SDavid Howells 	.destructor	= afs_flat_call_destructor,
21395cf9dd55SDavid Howells };
21405cf9dd55SDavid Howells 
21415cf9dd55SDavid Howells /*
21425cf9dd55SDavid Howells  * Fetch the status information for up to 50 files
21435cf9dd55SDavid Howells  */
21445cf9dd55SDavid Howells int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
21455cf9dd55SDavid Howells 			      struct afs_net *net,
21465cf9dd55SDavid Howells 			      struct afs_fid *fids,
214787182759SDavid Howells 			      struct afs_status_cb *statuses,
21485cf9dd55SDavid Howells 			      unsigned int nr_fids,
21495cf9dd55SDavid Howells 			      struct afs_volsync *volsync)
21505cf9dd55SDavid Howells {
21515cf9dd55SDavid Howells 	struct afs_call *call;
21525cf9dd55SDavid Howells 	__be32 *bp;
21535cf9dd55SDavid Howells 	int i;
21545cf9dd55SDavid Howells 
215530062bd1SDavid Howells 	if (test_bit(AFS_SERVER_FL_IS_YFS, &fc->cbi->server->flags))
215687182759SDavid Howells 		return yfs_fs_inline_bulk_status(fc, net, fids, statuses,
215730062bd1SDavid Howells 						 nr_fids, volsync);
215830062bd1SDavid Howells 
21593b6492dfSDavid Howells 	_enter(",%x,{%llx:%llu},%u",
21605cf9dd55SDavid Howells 	       key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);
21615cf9dd55SDavid Howells 
21625cf9dd55SDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
21635cf9dd55SDavid Howells 				   (2 + nr_fids * 3) * 4,
21645cf9dd55SDavid Howells 				   21 * 4);
21655cf9dd55SDavid Howells 	if (!call) {
21665cf9dd55SDavid Howells 		fc->ac.error = -ENOMEM;
21675cf9dd55SDavid Howells 		return -ENOMEM;
21685cf9dd55SDavid Howells 	}
21695cf9dd55SDavid Howells 
21705cf9dd55SDavid Howells 	call->key = fc->key;
217187182759SDavid Howells 	call->out_scb = statuses;
2172ffba718eSDavid Howells 	call->out_volsync = volsync;
21735cf9dd55SDavid Howells 	call->count2 = nr_fids;
21745cf9dd55SDavid Howells 
21755cf9dd55SDavid Howells 	/* marshall the parameters */
21765cf9dd55SDavid Howells 	bp = call->request;
21775cf9dd55SDavid Howells 	*bp++ = htonl(FSINLINEBULKSTATUS);
21785cf9dd55SDavid Howells 	*bp++ = htonl(nr_fids);
21795cf9dd55SDavid Howells 	for (i = 0; i < nr_fids; i++) {
21805cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vid);
21815cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].vnode);
21825cf9dd55SDavid Howells 		*bp++ = htonl(fids[i].unique);
21835cf9dd55SDavid Howells 	}
21845cf9dd55SDavid Howells 
21855cf9dd55SDavid Howells 	afs_use_fs_server(call, fc->cbi);
21865cf9dd55SDavid Howells 	trace_afs_make_fs_call(call, &fids[0]);
218720b8391fSDavid Howells 	afs_set_fc_call(call, fc);
21880b9bf381SDavid Howells 	afs_make_call(&fc->ac, call, GFP_NOFS);
21890b9bf381SDavid Howells 	return afs_wait_for_call_to_complete(call, &fc->ac);
21905cf9dd55SDavid Howells }
2191260f082bSDavid Howells 
2192260f082bSDavid Howells /*
2193260f082bSDavid Howells  * deliver reply data to an FS.FetchACL
2194260f082bSDavid Howells  */
2195260f082bSDavid Howells static int afs_deliver_fs_fetch_acl(struct afs_call *call)
2196260f082bSDavid Howells {
2197260f082bSDavid Howells 	struct afs_acl *acl;
2198260f082bSDavid Howells 	const __be32 *bp;
2199260f082bSDavid Howells 	unsigned int size;
2200260f082bSDavid Howells 	int ret;
2201260f082bSDavid Howells 
2202260f082bSDavid Howells 	_enter("{%u}", call->unmarshall);
2203260f082bSDavid Howells 
2204260f082bSDavid Howells 	switch (call->unmarshall) {
2205260f082bSDavid Howells 	case 0:
2206260f082bSDavid Howells 		afs_extract_to_tmp(call);
2207260f082bSDavid Howells 		call->unmarshall++;
220829881608SGustavo A. R. Silva 		/* Fall through */
2209260f082bSDavid Howells 
2210260f082bSDavid Howells 		/* extract the returned data length */
2211260f082bSDavid Howells 	case 1:
2212260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2213260f082bSDavid Howells 		if (ret < 0)
2214260f082bSDavid Howells 			return ret;
2215260f082bSDavid Howells 
2216260f082bSDavid Howells 		size = call->count2 = ntohl(call->tmp);
2217260f082bSDavid Howells 		size = round_up(size, 4);
2218260f082bSDavid Howells 
2219260f082bSDavid Howells 		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
2220260f082bSDavid Howells 		if (!acl)
2221260f082bSDavid Howells 			return -ENOMEM;
2222ffba718eSDavid Howells 		call->ret_acl = acl;
2223260f082bSDavid Howells 		acl->size = call->count2;
2224260f082bSDavid Howells 		afs_extract_begin(call, acl->data, size);
2225260f082bSDavid Howells 		call->unmarshall++;
222629881608SGustavo A. R. Silva 		/* Fall through */
2227260f082bSDavid Howells 
2228260f082bSDavid Howells 		/* extract the returned data */
2229260f082bSDavid Howells 	case 2:
2230260f082bSDavid Howells 		ret = afs_extract_data(call, true);
2231260f082bSDavid Howells 		if (ret < 0)
2232260f082bSDavid Howells 			return ret;
2233260f082bSDavid Howells 
2234260f082bSDavid Howells 		afs_extract_to_buf(call, (21 + 6) * 4);
2235260f082bSDavid Howells 		call->unmarshall++;
223629881608SGustavo A. R. Silva 		/* Fall through */
2237260f082bSDavid Howells 
2238260f082bSDavid Howells 		/* extract the metadata */
2239260f082bSDavid Howells 	case 3:
2240260f082bSDavid Howells 		ret = afs_extract_data(call, false);
2241260f082bSDavid Howells 		if (ret < 0)
2242260f082bSDavid Howells 			return ret;
2243260f082bSDavid Howells 
2244260f082bSDavid Howells 		bp = call->buffer;
2245a58823acSDavid Howells 		ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2246260f082bSDavid Howells 		if (ret < 0)
2247260f082bSDavid Howells 			return ret;
2248ffba718eSDavid Howells 		xdr_decode_AFSVolSync(&bp, call->out_volsync);
2249260f082bSDavid Howells 
2250260f082bSDavid Howells 		call->unmarshall++;
2251260f082bSDavid Howells 
2252260f082bSDavid Howells 	case 4:
2253260f082bSDavid Howells 		break;
2254260f082bSDavid Howells 	}
2255260f082bSDavid Howells 
2256260f082bSDavid Howells 	_leave(" = 0 [done]");
2257260f082bSDavid Howells 	return 0;
2258260f082bSDavid Howells }
2259260f082bSDavid Howells 
2260260f082bSDavid Howells static void afs_destroy_fs_fetch_acl(struct afs_call *call)
2261260f082bSDavid Howells {
2262ffba718eSDavid Howells 	kfree(call->ret_acl);
2263260f082bSDavid Howells 	afs_flat_call_destructor(call);
2264260f082bSDavid Howells }
2265260f082bSDavid Howells 
2266260f082bSDavid Howells /*
2267260f082bSDavid Howells  * FS.FetchACL operation type
2268260f082bSDavid Howells  */
2269260f082bSDavid Howells static const struct afs_call_type afs_RXFSFetchACL = {
2270260f082bSDavid Howells 	.name		= "FS.FetchACL",
2271260f082bSDavid Howells 	.op		= afs_FS_FetchACL,
2272260f082bSDavid Howells 	.deliver	= afs_deliver_fs_fetch_acl,
2273260f082bSDavid Howells 	.destructor	= afs_destroy_fs_fetch_acl,
2274260f082bSDavid Howells };
2275260f082bSDavid Howells 
2276260f082bSDavid Howells /*
2277260f082bSDavid Howells  * Fetch the ACL for a file.
2278260f082bSDavid Howells  */
2279a58823acSDavid Howells struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc,
2280a58823acSDavid Howells 				 struct afs_status_cb *scb)
2281260f082bSDavid Howells {
2282260f082bSDavid Howells 	struct afs_vnode *vnode = fc->vnode;
2283260f082bSDavid Howells 	struct afs_call *call;
2284260f082bSDavid Howells 	struct afs_net *net = afs_v2net(vnode);
2285260f082bSDavid Howells 	__be32 *bp;
2286260f082bSDavid Howells 
2287260f082bSDavid Howells 	_enter(",%x,{%llx:%llu},,",
2288260f082bSDavid Howells 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2289260f082bSDavid Howells 
2290260f082bSDavid Howells 	call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
2291260f082bSDavid Howells 	if (!call) {
2292260f082bSDavid Howells 		fc->ac.error = -ENOMEM;
2293260f082bSDavid Howells 		return ERR_PTR(-ENOMEM);
2294260f082bSDavid Howells 	}
2295260f082bSDavid Howells 
2296260f082bSDavid Howells 	call->key = fc->key;
2297ffba718eSDavid Howells 	call->ret_acl = NULL;
2298a58823acSDavid Howells 	call->out_scb = scb;
2299ffba718eSDavid Howells 	call->out_volsync = NULL;
2300260f082bSDavid Howells 
2301260f082bSDavid Howells 	/* marshall the parameters */
2302260f082bSDavid Howells 	bp = call->request;
2303260f082bSDavid Howells 	bp[0] = htonl(FSFETCHACL);
2304260f082bSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
2305260f082bSDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
2306260f082bSDavid Howells 	bp[3] = htonl(vnode->fid.unique);
2307260f082bSDavid Howells 
2308260f082bSDavid Howells 	afs_use_fs_server(call, fc->cbi);
2309260f082bSDavid Howells 	trace_afs_make_fs_call(call, &vnode->fid);
2310260f082bSDavid Howells 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2311260f082bSDavid Howells 	return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
2312260f082bSDavid Howells }
2313b10494afSJoe Gorse 
2314b10494afSJoe Gorse /*
2315ffba718eSDavid Howells  * Deliver reply data to any operation that returns file status and volume
2316ffba718eSDavid Howells  * sync.
2317ffba718eSDavid Howells  */
2318ffba718eSDavid Howells static int afs_deliver_fs_file_status_and_vol(struct afs_call *call)
2319ffba718eSDavid Howells {
2320ffba718eSDavid Howells 	const __be32 *bp;
2321ffba718eSDavid Howells 	int ret;
2322ffba718eSDavid Howells 
2323ffba718eSDavid Howells 	ret = afs_transfer_reply(call);
2324ffba718eSDavid Howells 	if (ret < 0)
2325ffba718eSDavid Howells 		return ret;
2326ffba718eSDavid Howells 
2327ffba718eSDavid Howells 	bp = call->buffer;
2328a58823acSDavid Howells 	ret = xdr_decode_AFSFetchStatus(&bp, call, call->out_scb);
2329ffba718eSDavid Howells 	if (ret < 0)
2330ffba718eSDavid Howells 		return ret;
2331ffba718eSDavid Howells 	xdr_decode_AFSVolSync(&bp, call->out_volsync);
2332ffba718eSDavid Howells 
2333ffba718eSDavid Howells 	_leave(" = 0 [done]");
2334ffba718eSDavid Howells 	return 0;
2335ffba718eSDavid Howells }
2336ffba718eSDavid Howells 
2337ffba718eSDavid Howells /*
2338b10494afSJoe Gorse  * FS.StoreACL operation type
2339b10494afSJoe Gorse  */
2340b10494afSJoe Gorse static const struct afs_call_type afs_RXFSStoreACL = {
2341b10494afSJoe Gorse 	.name		= "FS.StoreACL",
2342b10494afSJoe Gorse 	.op		= afs_FS_StoreACL,
2343ffba718eSDavid Howells 	.deliver	= afs_deliver_fs_file_status_and_vol,
2344b10494afSJoe Gorse 	.destructor	= afs_flat_call_destructor,
2345b10494afSJoe Gorse };
2346b10494afSJoe Gorse 
2347b10494afSJoe Gorse /*
2348b10494afSJoe Gorse  * Fetch the ACL for a file.
2349b10494afSJoe Gorse  */
2350a58823acSDavid Howells int afs_fs_store_acl(struct afs_fs_cursor *fc, const struct afs_acl *acl,
2351a58823acSDavid Howells 		     struct afs_status_cb *scb)
2352b10494afSJoe Gorse {
2353b10494afSJoe Gorse 	struct afs_vnode *vnode = fc->vnode;
2354b10494afSJoe Gorse 	struct afs_call *call;
2355b10494afSJoe Gorse 	struct afs_net *net = afs_v2net(vnode);
2356b10494afSJoe Gorse 	size_t size;
2357b10494afSJoe Gorse 	__be32 *bp;
2358b10494afSJoe Gorse 
2359b10494afSJoe Gorse 	_enter(",%x,{%llx:%llu},,",
2360b10494afSJoe Gorse 	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
2361b10494afSJoe Gorse 
2362b10494afSJoe Gorse 	size = round_up(acl->size, 4);
2363b10494afSJoe Gorse 	call = afs_alloc_flat_call(net, &afs_RXFSStoreACL,
2364b10494afSJoe Gorse 				   5 * 4 + size, (21 + 6) * 4);
2365b10494afSJoe Gorse 	if (!call) {
2366b10494afSJoe Gorse 		fc->ac.error = -ENOMEM;
2367b10494afSJoe Gorse 		return -ENOMEM;
2368b10494afSJoe Gorse 	}
2369b10494afSJoe Gorse 
2370b10494afSJoe Gorse 	call->key = fc->key;
2371a58823acSDavid Howells 	call->out_scb = scb;
2372ffba718eSDavid Howells 	call->out_volsync = NULL;
2373b10494afSJoe Gorse 
2374b10494afSJoe Gorse 	/* marshall the parameters */
2375b10494afSJoe Gorse 	bp = call->request;
2376b10494afSJoe Gorse 	bp[0] = htonl(FSSTOREACL);
2377b10494afSJoe Gorse 	bp[1] = htonl(vnode->fid.vid);
2378b10494afSJoe Gorse 	bp[2] = htonl(vnode->fid.vnode);
2379b10494afSJoe Gorse 	bp[3] = htonl(vnode->fid.unique);
2380b10494afSJoe Gorse 	bp[4] = htonl(acl->size);
2381b10494afSJoe Gorse 	memcpy(&bp[5], acl->data, acl->size);
2382b10494afSJoe Gorse 	if (acl->size != size)
2383b10494afSJoe Gorse 		memset((void *)&bp[5] + acl->size, 0, size - acl->size);
2384b10494afSJoe Gorse 
2385b10494afSJoe Gorse 	trace_afs_make_fs_call(call, &vnode->fid);
2386b10494afSJoe Gorse 	afs_make_call(&fc->ac, call, GFP_KERNEL);
2387b10494afSJoe Gorse 	return afs_wait_for_call_to_complete(call, &fc->ac);
23881da177e4SLinus Torvalds }
2389