xref: /openbmc/linux/fs/afs/fsclient.c (revision a0a5386a)
108e0e7c8SDavid Howells /* AFS File Server client stubs
21da177e4SLinus Torvalds  *
308e0e7c8SDavid Howells  * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
41da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or
71da177e4SLinus Torvalds  * modify it under the terms of the GNU General Public License
81da177e4SLinus Torvalds  * as published by the Free Software Foundation; either version
91da177e4SLinus Torvalds  * 2 of the License, or (at your option) any later version.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/init.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
141da177e4SLinus Torvalds #include <linux/sched.h>
1508e0e7c8SDavid Howells #include <linux/circ_buf.h>
161da177e4SLinus Torvalds #include "internal.h"
1708e0e7c8SDavid Howells #include "afs_fs.h"
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds /*
20260a9803SDavid Howells  * decode an AFSFid block
21260a9803SDavid Howells  */
22260a9803SDavid Howells static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
23260a9803SDavid Howells {
24260a9803SDavid Howells 	const __be32 *bp = *_bp;
25260a9803SDavid Howells 
26260a9803SDavid Howells 	fid->vid		= ntohl(*bp++);
27260a9803SDavid Howells 	fid->vnode		= ntohl(*bp++);
28260a9803SDavid Howells 	fid->unique		= ntohl(*bp++);
29260a9803SDavid Howells 	*_bp = bp;
30260a9803SDavid Howells }
31260a9803SDavid Howells 
32260a9803SDavid Howells /*
3308e0e7c8SDavid Howells  * decode an AFSFetchStatus block
341da177e4SLinus Torvalds  */
3508e0e7c8SDavid Howells static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
36260a9803SDavid Howells 				      struct afs_file_status *status,
3731143d5dSDavid Howells 				      struct afs_vnode *vnode,
3831143d5dSDavid Howells 				      afs_dataversion_t *store_version)
391da177e4SLinus Torvalds {
4031143d5dSDavid Howells 	afs_dataversion_t expected_version;
4108e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
4208e0e7c8SDavid Howells 	umode_t mode;
43260a9803SDavid Howells 	u64 data_version, size;
4408e0e7c8SDavid Howells 	u32 changed = 0; /* becomes non-zero if ctime-type changes seen */
45a0a5386aSEric W. Biederman 	kuid_t owner;
46a0a5386aSEric W. Biederman 	kgid_t group;
4708e0e7c8SDavid Howells 
4808e0e7c8SDavid Howells #define EXTRACT(DST)				\
4908e0e7c8SDavid Howells 	do {					\
5008e0e7c8SDavid Howells 		u32 x = ntohl(*bp++);		\
5108e0e7c8SDavid Howells 		changed |= DST - x;		\
5208e0e7c8SDavid Howells 		DST = x;			\
5308e0e7c8SDavid Howells 	} while (0)
5408e0e7c8SDavid Howells 
55260a9803SDavid Howells 	status->if_version = ntohl(*bp++);
56260a9803SDavid Howells 	EXTRACT(status->type);
57260a9803SDavid Howells 	EXTRACT(status->nlink);
58260a9803SDavid Howells 	size = ntohl(*bp++);
5908e0e7c8SDavid Howells 	data_version = ntohl(*bp++);
60260a9803SDavid Howells 	EXTRACT(status->author);
61a0a5386aSEric W. Biederman 	owner = make_kuid(&init_user_ns, ntohl(*bp++));
62a0a5386aSEric W. Biederman 	changed |= !uid_eq(owner, status->owner);
63a0a5386aSEric W. Biederman 	status->owner = owner;
64260a9803SDavid Howells 	EXTRACT(status->caller_access); /* call ticket dependent */
65260a9803SDavid Howells 	EXTRACT(status->anon_access);
66260a9803SDavid Howells 	EXTRACT(status->mode);
67260a9803SDavid Howells 	EXTRACT(status->parent.vnode);
68260a9803SDavid Howells 	EXTRACT(status->parent.unique);
6908e0e7c8SDavid Howells 	bp++; /* seg size */
70260a9803SDavid Howells 	status->mtime_client = ntohl(*bp++);
71260a9803SDavid Howells 	status->mtime_server = ntohl(*bp++);
72a0a5386aSEric W. Biederman 	group = make_kgid(&init_user_ns, ntohl(*bp++));
73a0a5386aSEric W. Biederman 	changed |= !gid_eq(group, status->group);
74a0a5386aSEric W. Biederman 	status->group = group;
7508e0e7c8SDavid Howells 	bp++; /* sync counter */
7608e0e7c8SDavid Howells 	data_version |= (u64) ntohl(*bp++) << 32;
77e8d6c554SDavid Howells 	EXTRACT(status->lock_count);
78260a9803SDavid Howells 	size |= (u64) ntohl(*bp++) << 32;
7908e0e7c8SDavid Howells 	bp++; /* spare 4 */
8008e0e7c8SDavid Howells 	*_bp = bp;
8108e0e7c8SDavid Howells 
82260a9803SDavid Howells 	if (size != status->size) {
83260a9803SDavid Howells 		status->size = size;
84260a9803SDavid Howells 		changed |= true;
85260a9803SDavid Howells 	}
86260a9803SDavid Howells 	status->mode &= S_IALLUGO;
8708e0e7c8SDavid Howells 
88260a9803SDavid Howells 	_debug("vnode time %lx, %lx",
89260a9803SDavid Howells 	       status->mtime_client, status->mtime_server);
90260a9803SDavid Howells 
91260a9803SDavid Howells 	if (vnode) {
92260a9803SDavid Howells 		status->parent.vid = vnode->fid.vid;
93260a9803SDavid Howells 		if (changed && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
94260a9803SDavid Howells 			_debug("vnode changed");
95260a9803SDavid Howells 			i_size_write(&vnode->vfs_inode, size);
96260a9803SDavid Howells 			vnode->vfs_inode.i_uid = status->owner;
97260a9803SDavid Howells 			vnode->vfs_inode.i_gid = status->group;
98d6e43f75SDavid Howells 			vnode->vfs_inode.i_generation = vnode->fid.unique;
99bfe86848SMiklos Szeredi 			set_nlink(&vnode->vfs_inode, status->nlink);
100260a9803SDavid Howells 
10108e0e7c8SDavid Howells 			mode = vnode->vfs_inode.i_mode;
10208e0e7c8SDavid Howells 			mode &= ~S_IALLUGO;
103260a9803SDavid Howells 			mode |= status->mode;
104260a9803SDavid Howells 			barrier();
10508e0e7c8SDavid Howells 			vnode->vfs_inode.i_mode = mode;
10608e0e7c8SDavid Howells 		}
10708e0e7c8SDavid Howells 
108260a9803SDavid Howells 		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server;
10908e0e7c8SDavid Howells 		vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime;
11008e0e7c8SDavid Howells 		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime;
111d6e43f75SDavid Howells 		vnode->vfs_inode.i_version	= data_version;
112260a9803SDavid Howells 	}
11308e0e7c8SDavid Howells 
11431143d5dSDavid Howells 	expected_version = status->data_version;
11531143d5dSDavid Howells 	if (store_version)
11631143d5dSDavid Howells 		expected_version = *store_version;
11731143d5dSDavid Howells 
11831143d5dSDavid Howells 	if (expected_version != data_version) {
119260a9803SDavid Howells 		status->data_version = data_version;
120260a9803SDavid Howells 		if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
121260a9803SDavid Howells 			_debug("vnode modified %llx on {%x:%u}",
122ba3e0e1aSDavid S. Miller 			       (unsigned long long) data_version,
123ba3e0e1aSDavid S. Miller 			       vnode->fid.vid, vnode->fid.vnode);
12408e0e7c8SDavid Howells 			set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
12508e0e7c8SDavid Howells 			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
1261da177e4SLinus Torvalds 		}
12731143d5dSDavid Howells 	} else if (store_version) {
12831143d5dSDavid Howells 		status->data_version = data_version;
129ec26815aSDavid Howells 	}
130260a9803SDavid Howells }
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds /*
13308e0e7c8SDavid Howells  * decode an AFSCallBack block
1341da177e4SLinus Torvalds  */
13508e0e7c8SDavid Howells static void xdr_decode_AFSCallBack(const __be32 **_bp, struct afs_vnode *vnode)
1361da177e4SLinus Torvalds {
13708e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
1381da177e4SLinus Torvalds 
13908e0e7c8SDavid Howells 	vnode->cb_version	= ntohl(*bp++);
14008e0e7c8SDavid Howells 	vnode->cb_expiry	= ntohl(*bp++);
14108e0e7c8SDavid Howells 	vnode->cb_type		= ntohl(*bp++);
14208e0e7c8SDavid Howells 	vnode->cb_expires	= vnode->cb_expiry + get_seconds();
14308e0e7c8SDavid Howells 	*_bp = bp;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
146260a9803SDavid Howells static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
147260a9803SDavid Howells 				       struct afs_callback *cb)
148260a9803SDavid Howells {
149260a9803SDavid Howells 	const __be32 *bp = *_bp;
150260a9803SDavid Howells 
151260a9803SDavid Howells 	cb->version	= ntohl(*bp++);
152260a9803SDavid Howells 	cb->expiry	= ntohl(*bp++);
153260a9803SDavid Howells 	cb->type	= ntohl(*bp++);
154260a9803SDavid Howells 	*_bp = bp;
155260a9803SDavid Howells }
156260a9803SDavid Howells 
1571da177e4SLinus Torvalds /*
15808e0e7c8SDavid Howells  * decode an AFSVolSync block
1591da177e4SLinus Torvalds  */
16008e0e7c8SDavid Howells static void xdr_decode_AFSVolSync(const __be32 **_bp,
16108e0e7c8SDavid Howells 				  struct afs_volsync *volsync)
1621da177e4SLinus Torvalds {
16308e0e7c8SDavid Howells 	const __be32 *bp = *_bp;
1641da177e4SLinus Torvalds 
16508e0e7c8SDavid Howells 	volsync->creation = ntohl(*bp++);
16608e0e7c8SDavid Howells 	bp++; /* spare2 */
16708e0e7c8SDavid Howells 	bp++; /* spare3 */
16808e0e7c8SDavid Howells 	bp++; /* spare4 */
16908e0e7c8SDavid Howells 	bp++; /* spare5 */
17008e0e7c8SDavid Howells 	bp++; /* spare6 */
17108e0e7c8SDavid Howells 	*_bp = bp;
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds 
17408e0e7c8SDavid Howells /*
17531143d5dSDavid Howells  * encode the requested attributes into an AFSStoreStatus block
17631143d5dSDavid Howells  */
17731143d5dSDavid Howells static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
17831143d5dSDavid Howells {
17931143d5dSDavid Howells 	__be32 *bp = *_bp;
18031143d5dSDavid Howells 	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
18131143d5dSDavid Howells 
18231143d5dSDavid Howells 	mask = 0;
18331143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MTIME) {
18431143d5dSDavid Howells 		mask |= AFS_SET_MTIME;
18531143d5dSDavid Howells 		mtime = attr->ia_mtime.tv_sec;
18631143d5dSDavid Howells 	}
18731143d5dSDavid Howells 
18831143d5dSDavid Howells 	if (attr->ia_valid & ATTR_UID) {
18931143d5dSDavid Howells 		mask |= AFS_SET_OWNER;
190a0a5386aSEric W. Biederman 		owner = from_kuid(&init_user_ns, attr->ia_uid);
19131143d5dSDavid Howells 	}
19231143d5dSDavid Howells 
19331143d5dSDavid Howells 	if (attr->ia_valid & ATTR_GID) {
19431143d5dSDavid Howells 		mask |= AFS_SET_GROUP;
195a0a5386aSEric W. Biederman 		group = from_kgid(&init_user_ns, attr->ia_gid);
19631143d5dSDavid Howells 	}
19731143d5dSDavid Howells 
19831143d5dSDavid Howells 	if (attr->ia_valid & ATTR_MODE) {
19931143d5dSDavid Howells 		mask |= AFS_SET_MODE;
20031143d5dSDavid Howells 		mode = attr->ia_mode & S_IALLUGO;
20131143d5dSDavid Howells 	}
20231143d5dSDavid Howells 
20331143d5dSDavid Howells 	*bp++ = htonl(mask);
20431143d5dSDavid Howells 	*bp++ = htonl(mtime);
20531143d5dSDavid Howells 	*bp++ = htonl(owner);
20631143d5dSDavid Howells 	*bp++ = htonl(group);
20731143d5dSDavid Howells 	*bp++ = htonl(mode);
20831143d5dSDavid Howells 	*bp++ = 0;		/* segment size */
20931143d5dSDavid Howells 	*_bp = bp;
21031143d5dSDavid Howells }
21131143d5dSDavid Howells 
21231143d5dSDavid Howells /*
21345222b9eSDavid Howells  * decode an AFSFetchVolumeStatus block
21445222b9eSDavid Howells  */
21545222b9eSDavid Howells static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
21645222b9eSDavid Howells 					    struct afs_volume_status *vs)
21745222b9eSDavid Howells {
21845222b9eSDavid Howells 	const __be32 *bp = *_bp;
21945222b9eSDavid Howells 
22045222b9eSDavid Howells 	vs->vid			= ntohl(*bp++);
22145222b9eSDavid Howells 	vs->parent_id		= ntohl(*bp++);
22245222b9eSDavid Howells 	vs->online		= ntohl(*bp++);
22345222b9eSDavid Howells 	vs->in_service		= ntohl(*bp++);
22445222b9eSDavid Howells 	vs->blessed		= ntohl(*bp++);
22545222b9eSDavid Howells 	vs->needs_salvage	= ntohl(*bp++);
22645222b9eSDavid Howells 	vs->type		= ntohl(*bp++);
22745222b9eSDavid Howells 	vs->min_quota		= ntohl(*bp++);
22845222b9eSDavid Howells 	vs->max_quota		= ntohl(*bp++);
22945222b9eSDavid Howells 	vs->blocks_in_use	= ntohl(*bp++);
23045222b9eSDavid Howells 	vs->part_blocks_avail	= ntohl(*bp++);
23145222b9eSDavid Howells 	vs->part_max_blocks	= ntohl(*bp++);
23245222b9eSDavid Howells 	*_bp = bp;
23345222b9eSDavid Howells }
23445222b9eSDavid Howells 
23545222b9eSDavid Howells /*
23608e0e7c8SDavid Howells  * deliver reply data to an FS.FetchStatus
23708e0e7c8SDavid Howells  */
23808e0e7c8SDavid Howells static int afs_deliver_fs_fetch_status(struct afs_call *call,
23908e0e7c8SDavid Howells 				       struct sk_buff *skb, bool last)
24008e0e7c8SDavid Howells {
241260a9803SDavid Howells 	struct afs_vnode *vnode = call->reply;
24208e0e7c8SDavid Howells 	const __be32 *bp;
2431da177e4SLinus Torvalds 
24408e0e7c8SDavid Howells 	_enter(",,%u", last);
2451da177e4SLinus Torvalds 
24608e0e7c8SDavid Howells 	afs_transfer_reply(call, skb);
24708e0e7c8SDavid Howells 	if (!last)
24808e0e7c8SDavid Howells 		return 0;
2491da177e4SLinus Torvalds 
25008e0e7c8SDavid Howells 	if (call->reply_size != call->reply_max)
25108e0e7c8SDavid Howells 		return -EBADMSG;
2521da177e4SLinus Torvalds 
25308e0e7c8SDavid Howells 	/* unmarshall the reply once we've received all of it */
25408e0e7c8SDavid Howells 	bp = call->buffer;
25531143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
256260a9803SDavid Howells 	xdr_decode_AFSCallBack(&bp, vnode);
25708e0e7c8SDavid Howells 	if (call->reply2)
25808e0e7c8SDavid Howells 		xdr_decode_AFSVolSync(&bp, call->reply2);
2591da177e4SLinus Torvalds 
26008e0e7c8SDavid Howells 	_leave(" = 0 [done]");
26108e0e7c8SDavid Howells 	return 0;
262ec26815aSDavid Howells }
26308e0e7c8SDavid Howells 
26408e0e7c8SDavid Howells /*
26508e0e7c8SDavid Howells  * FS.FetchStatus operation type
26608e0e7c8SDavid Howells  */
26708e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchStatus = {
26800d3b7a4SDavid Howells 	.name		= "FS.FetchStatus",
26908e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_status,
27008e0e7c8SDavid Howells 	.abort_to_error	= afs_abort_to_error,
27108e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
27208e0e7c8SDavid Howells };
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds /*
2751da177e4SLinus Torvalds  * fetch the status information for a file
2761da177e4SLinus Torvalds  */
27708e0e7c8SDavid Howells int afs_fs_fetch_file_status(struct afs_server *server,
27800d3b7a4SDavid Howells 			     struct key *key,
2791da177e4SLinus Torvalds 			     struct afs_vnode *vnode,
28008e0e7c8SDavid Howells 			     struct afs_volsync *volsync,
28108e0e7c8SDavid Howells 			     const struct afs_wait_mode *wait_mode)
2821da177e4SLinus Torvalds {
28308e0e7c8SDavid Howells 	struct afs_call *call;
2841da177e4SLinus Torvalds 	__be32 *bp;
2851da177e4SLinus Torvalds 
286416351f2SDavid Howells 	_enter(",%x,{%x:%u},,",
287260a9803SDavid Howells 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
2881da177e4SLinus Torvalds 
289260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
29008e0e7c8SDavid Howells 	if (!call)
29108e0e7c8SDavid Howells 		return -ENOMEM;
2921da177e4SLinus Torvalds 
29300d3b7a4SDavid Howells 	call->key = key;
29408e0e7c8SDavid Howells 	call->reply = vnode;
29508e0e7c8SDavid Howells 	call->reply2 = volsync;
29608e0e7c8SDavid Howells 	call->service_id = FS_SERVICE;
29708e0e7c8SDavid Howells 	call->port = htons(AFS_FS_PORT);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	/* marshall the parameters */
30008e0e7c8SDavid Howells 	bp = call->request;
3011da177e4SLinus Torvalds 	bp[0] = htonl(FSFETCHSTATUS);
3021da177e4SLinus Torvalds 	bp[1] = htonl(vnode->fid.vid);
3031da177e4SLinus Torvalds 	bp[2] = htonl(vnode->fid.vnode);
3041da177e4SLinus Torvalds 	bp[3] = htonl(vnode->fid.unique);
3051da177e4SLinus Torvalds 
30608e0e7c8SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
307ec26815aSDavid Howells }
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds /*
31008e0e7c8SDavid Howells  * deliver reply data to an FS.FetchData
3111da177e4SLinus Torvalds  */
31208e0e7c8SDavid Howells static int afs_deliver_fs_fetch_data(struct afs_call *call,
31308e0e7c8SDavid Howells 				     struct sk_buff *skb, bool last)
3141da177e4SLinus Torvalds {
315260a9803SDavid Howells 	struct afs_vnode *vnode = call->reply;
31608e0e7c8SDavid Howells 	const __be32 *bp;
31708e0e7c8SDavid Howells 	struct page *page;
31808e0e7c8SDavid Howells 	void *buffer;
3191da177e4SLinus Torvalds 	int ret;
3201da177e4SLinus Torvalds 
32108e0e7c8SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
3221da177e4SLinus Torvalds 
32308e0e7c8SDavid Howells 	switch (call->unmarshall) {
32408e0e7c8SDavid Howells 	case 0:
32508e0e7c8SDavid Howells 		call->offset = 0;
32608e0e7c8SDavid Howells 		call->unmarshall++;
327b9b1f8d5SDavid Howells 		if (call->operation_ID != FSFETCHDATA64) {
328b9b1f8d5SDavid Howells 			call->unmarshall++;
329b9b1f8d5SDavid Howells 			goto no_msw;
330b9b1f8d5SDavid Howells 		}
3311da177e4SLinus Torvalds 
332b9b1f8d5SDavid Howells 		/* extract the upper part of the returned data length of an
333b9b1f8d5SDavid Howells 		 * FSFETCHDATA64 op (which should always be 0 using this
334b9b1f8d5SDavid Howells 		 * client) */
33508e0e7c8SDavid Howells 	case 1:
336b9b1f8d5SDavid Howells 		_debug("extract data length (MSW)");
337b9b1f8d5SDavid Howells 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
338b9b1f8d5SDavid Howells 		switch (ret) {
339b9b1f8d5SDavid Howells 		case 0:		break;
340b9b1f8d5SDavid Howells 		case -EAGAIN:	return 0;
341b9b1f8d5SDavid Howells 		default:	return ret;
342b9b1f8d5SDavid Howells 		}
343b9b1f8d5SDavid Howells 
344b9b1f8d5SDavid Howells 		call->count = ntohl(call->tmp);
345b9b1f8d5SDavid Howells 		_debug("DATA length MSW: %u", call->count);
346b9b1f8d5SDavid Howells 		if (call->count > 0)
347b9b1f8d5SDavid Howells 			return -EBADMSG;
348b9b1f8d5SDavid Howells 		call->offset = 0;
349b9b1f8d5SDavid Howells 		call->unmarshall++;
350b9b1f8d5SDavid Howells 
351b9b1f8d5SDavid Howells 	no_msw:
352b9b1f8d5SDavid Howells 		/* extract the returned data length */
353b9b1f8d5SDavid Howells 	case 2:
35408e0e7c8SDavid Howells 		_debug("extract data length");
35508e0e7c8SDavid Howells 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
35608e0e7c8SDavid Howells 		switch (ret) {
35708e0e7c8SDavid Howells 		case 0:		break;
35808e0e7c8SDavid Howells 		case -EAGAIN:	return 0;
35908e0e7c8SDavid Howells 		default:	return ret;
3601da177e4SLinus Torvalds 		}
3611da177e4SLinus Torvalds 
36208e0e7c8SDavid Howells 		call->count = ntohl(call->tmp);
36308e0e7c8SDavid Howells 		_debug("DATA length: %u", call->count);
36408e0e7c8SDavid Howells 		if (call->count > PAGE_SIZE)
36508e0e7c8SDavid Howells 			return -EBADMSG;
36608e0e7c8SDavid Howells 		call->offset = 0;
36708e0e7c8SDavid Howells 		call->unmarshall++;
3681da177e4SLinus Torvalds 
36908e0e7c8SDavid Howells 		/* extract the returned data */
370b9b1f8d5SDavid Howells 	case 3:
37108e0e7c8SDavid Howells 		_debug("extract data");
372416351f2SDavid Howells 		if (call->count > 0) {
37308e0e7c8SDavid Howells 			page = call->reply3;
374da4aa36dSCong Wang 			buffer = kmap_atomic(page);
375416351f2SDavid Howells 			ret = afs_extract_data(call, skb, last, buffer,
376416351f2SDavid Howells 					       call->count);
377da4aa36dSCong Wang 			kunmap_atomic(buffer);
37808e0e7c8SDavid Howells 			switch (ret) {
37908e0e7c8SDavid Howells 			case 0:		break;
38008e0e7c8SDavid Howells 			case -EAGAIN:	return 0;
38108e0e7c8SDavid Howells 			default:	return ret;
3821da177e4SLinus Torvalds 			}
383416351f2SDavid Howells 		}
3841da177e4SLinus Torvalds 
38508e0e7c8SDavid Howells 		call->offset = 0;
38608e0e7c8SDavid Howells 		call->unmarshall++;
38708e0e7c8SDavid Howells 
38808e0e7c8SDavid Howells 		/* extract the metadata */
389b9b1f8d5SDavid Howells 	case 4:
390260a9803SDavid Howells 		ret = afs_extract_data(call, skb, last, call->buffer,
391260a9803SDavid Howells 				       (21 + 3 + 6) * 4);
39208e0e7c8SDavid Howells 		switch (ret) {
39308e0e7c8SDavid Howells 		case 0:		break;
39408e0e7c8SDavid Howells 		case -EAGAIN:	return 0;
39508e0e7c8SDavid Howells 		default:	return ret;
396ec26815aSDavid Howells 		}
3971da177e4SLinus Torvalds 
39808e0e7c8SDavid Howells 		bp = call->buffer;
39931143d5dSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
400260a9803SDavid Howells 		xdr_decode_AFSCallBack(&bp, vnode);
40108e0e7c8SDavid Howells 		if (call->reply2)
40208e0e7c8SDavid Howells 			xdr_decode_AFSVolSync(&bp, call->reply2);
4031da177e4SLinus Torvalds 
40408e0e7c8SDavid Howells 		call->offset = 0;
40508e0e7c8SDavid Howells 		call->unmarshall++;
4061da177e4SLinus Torvalds 
407b9b1f8d5SDavid Howells 	case 5:
40808e0e7c8SDavid Howells 		_debug("trailer");
40908e0e7c8SDavid Howells 		if (skb->len != 0)
41008e0e7c8SDavid Howells 			return -EBADMSG;
4111da177e4SLinus Torvalds 		break;
4121da177e4SLinus Torvalds 	}
4131da177e4SLinus Torvalds 
41408e0e7c8SDavid Howells 	if (!last)
41508e0e7c8SDavid Howells 		return 0;
4161da177e4SLinus Torvalds 
417416351f2SDavid Howells 	if (call->count < PAGE_SIZE) {
418416351f2SDavid Howells 		_debug("clear");
419416351f2SDavid Howells 		page = call->reply3;
420da4aa36dSCong Wang 		buffer = kmap_atomic(page);
421416351f2SDavid Howells 		memset(buffer + call->count, 0, PAGE_SIZE - call->count);
422da4aa36dSCong Wang 		kunmap_atomic(buffer);
423416351f2SDavid Howells 	}
424416351f2SDavid Howells 
42508e0e7c8SDavid Howells 	_leave(" = 0 [done]");
42608e0e7c8SDavid Howells 	return 0;
427ec26815aSDavid Howells }
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds /*
43008e0e7c8SDavid Howells  * FS.FetchData operation type
4311da177e4SLinus Torvalds  */
43208e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSFetchData = {
43300d3b7a4SDavid Howells 	.name		= "FS.FetchData",
43408e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
43508e0e7c8SDavid Howells 	.abort_to_error	= afs_abort_to_error,
43608e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
43708e0e7c8SDavid Howells };
43808e0e7c8SDavid Howells 
439b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSFetchData64 = {
440b9b1f8d5SDavid Howells 	.name		= "FS.FetchData64",
441b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_fetch_data,
442b9b1f8d5SDavid Howells 	.abort_to_error	= afs_abort_to_error,
443b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
444b9b1f8d5SDavid Howells };
445b9b1f8d5SDavid Howells 
446b9b1f8d5SDavid Howells /*
447b9b1f8d5SDavid Howells  * fetch data from a very large file
448b9b1f8d5SDavid Howells  */
449b9b1f8d5SDavid Howells static int afs_fs_fetch_data64(struct afs_server *server,
450b9b1f8d5SDavid Howells 			       struct key *key,
451b9b1f8d5SDavid Howells 			       struct afs_vnode *vnode,
452b9b1f8d5SDavid Howells 			       off_t offset, size_t length,
453b9b1f8d5SDavid Howells 			       struct page *buffer,
454b9b1f8d5SDavid Howells 			       const struct afs_wait_mode *wait_mode)
455b9b1f8d5SDavid Howells {
456b9b1f8d5SDavid Howells 	struct afs_call *call;
457b9b1f8d5SDavid Howells 	__be32 *bp;
458b9b1f8d5SDavid Howells 
459b9b1f8d5SDavid Howells 	_enter("");
460b9b1f8d5SDavid Howells 
461b9b1f8d5SDavid Howells 	ASSERTCMP(length, <, ULONG_MAX);
462b9b1f8d5SDavid Howells 
463b9b1f8d5SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
464b9b1f8d5SDavid Howells 	if (!call)
465b9b1f8d5SDavid Howells 		return -ENOMEM;
466b9b1f8d5SDavid Howells 
467b9b1f8d5SDavid Howells 	call->key = key;
468b9b1f8d5SDavid Howells 	call->reply = vnode;
469b9b1f8d5SDavid Howells 	call->reply2 = NULL; /* volsync */
470b9b1f8d5SDavid Howells 	call->reply3 = buffer;
471b9b1f8d5SDavid Howells 	call->service_id = FS_SERVICE;
472b9b1f8d5SDavid Howells 	call->port = htons(AFS_FS_PORT);
473b9b1f8d5SDavid Howells 	call->operation_ID = FSFETCHDATA64;
474b9b1f8d5SDavid Howells 
475b9b1f8d5SDavid Howells 	/* marshall the parameters */
476b9b1f8d5SDavid Howells 	bp = call->request;
477b9b1f8d5SDavid Howells 	bp[0] = htonl(FSFETCHDATA64);
478b9b1f8d5SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
479b9b1f8d5SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
480b9b1f8d5SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
481b9b1f8d5SDavid Howells 	bp[4] = htonl(upper_32_bits(offset));
482b9b1f8d5SDavid Howells 	bp[5] = htonl((u32) offset);
483b9b1f8d5SDavid Howells 	bp[6] = 0;
484b9b1f8d5SDavid Howells 	bp[7] = htonl((u32) length);
485b9b1f8d5SDavid Howells 
486b9b1f8d5SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
487b9b1f8d5SDavid Howells }
488b9b1f8d5SDavid Howells 
48908e0e7c8SDavid Howells /*
49008e0e7c8SDavid Howells  * fetch data from a file
49108e0e7c8SDavid Howells  */
49208e0e7c8SDavid Howells int afs_fs_fetch_data(struct afs_server *server,
49300d3b7a4SDavid Howells 		      struct key *key,
4941da177e4SLinus Torvalds 		      struct afs_vnode *vnode,
49508e0e7c8SDavid Howells 		      off_t offset, size_t length,
49608e0e7c8SDavid Howells 		      struct page *buffer,
49708e0e7c8SDavid Howells 		      const struct afs_wait_mode *wait_mode)
4981da177e4SLinus Torvalds {
49908e0e7c8SDavid Howells 	struct afs_call *call;
50008e0e7c8SDavid Howells 	__be32 *bp;
5011da177e4SLinus Torvalds 
502b9b1f8d5SDavid Howells 	if (upper_32_bits(offset) || upper_32_bits(offset + length))
503b9b1f8d5SDavid Howells 		return afs_fs_fetch_data64(server, key, vnode, offset, length,
504b9b1f8d5SDavid Howells 					   buffer, wait_mode);
505b9b1f8d5SDavid Howells 
50608e0e7c8SDavid Howells 	_enter("");
5071da177e4SLinus Torvalds 
508260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
50908e0e7c8SDavid Howells 	if (!call)
51008e0e7c8SDavid Howells 		return -ENOMEM;
5111da177e4SLinus Torvalds 
51200d3b7a4SDavid Howells 	call->key = key;
51308e0e7c8SDavid Howells 	call->reply = vnode;
514260a9803SDavid Howells 	call->reply2 = NULL; /* volsync */
51508e0e7c8SDavid Howells 	call->reply3 = buffer;
51608e0e7c8SDavid Howells 	call->service_id = FS_SERVICE;
51708e0e7c8SDavid Howells 	call->port = htons(AFS_FS_PORT);
518b9b1f8d5SDavid Howells 	call->operation_ID = FSFETCHDATA;
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 	/* marshall the parameters */
52108e0e7c8SDavid Howells 	bp = call->request;
52208e0e7c8SDavid Howells 	bp[0] = htonl(FSFETCHDATA);
52308e0e7c8SDavid Howells 	bp[1] = htonl(vnode->fid.vid);
52408e0e7c8SDavid Howells 	bp[2] = htonl(vnode->fid.vnode);
52508e0e7c8SDavid Howells 	bp[3] = htonl(vnode->fid.unique);
52608e0e7c8SDavid Howells 	bp[4] = htonl(offset);
52708e0e7c8SDavid Howells 	bp[5] = htonl(length);
5281da177e4SLinus Torvalds 
52908e0e7c8SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds 
53208e0e7c8SDavid Howells /*
53308e0e7c8SDavid Howells  * deliver reply data to an FS.GiveUpCallBacks
53408e0e7c8SDavid Howells  */
53508e0e7c8SDavid Howells static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
53608e0e7c8SDavid Howells 					    struct sk_buff *skb, bool last)
53708e0e7c8SDavid Howells {
53808e0e7c8SDavid Howells 	_enter(",{%u},%d", skb->len, last);
5391da177e4SLinus Torvalds 
54008e0e7c8SDavid Howells 	if (skb->len > 0)
54108e0e7c8SDavid Howells 		return -EBADMSG; /* shouldn't be any reply data */
54208e0e7c8SDavid Howells 	return 0;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
54508e0e7c8SDavid Howells /*
54608e0e7c8SDavid Howells  * FS.GiveUpCallBacks operation type
54708e0e7c8SDavid Howells  */
54808e0e7c8SDavid Howells static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
54900d3b7a4SDavid Howells 	.name		= "FS.GiveUpCallBacks",
55008e0e7c8SDavid Howells 	.deliver	= afs_deliver_fs_give_up_callbacks,
55108e0e7c8SDavid Howells 	.abort_to_error	= afs_abort_to_error,
55208e0e7c8SDavid Howells 	.destructor	= afs_flat_call_destructor,
55308e0e7c8SDavid Howells };
5541da177e4SLinus Torvalds 
55508e0e7c8SDavid Howells /*
55608e0e7c8SDavid Howells  * give up a set of callbacks
55708e0e7c8SDavid Howells  * - the callbacks are held in the server->cb_break ring
55808e0e7c8SDavid Howells  */
55908e0e7c8SDavid Howells int afs_fs_give_up_callbacks(struct afs_server *server,
56008e0e7c8SDavid Howells 			     const struct afs_wait_mode *wait_mode)
56108e0e7c8SDavid Howells {
56208e0e7c8SDavid Howells 	struct afs_call *call;
56308e0e7c8SDavid Howells 	size_t ncallbacks;
56408e0e7c8SDavid Howells 	__be32 *bp, *tp;
56508e0e7c8SDavid Howells 	int loop;
5661da177e4SLinus Torvalds 
56708e0e7c8SDavid Howells 	ncallbacks = CIRC_CNT(server->cb_break_head, server->cb_break_tail,
56808e0e7c8SDavid Howells 			      ARRAY_SIZE(server->cb_break));
56908e0e7c8SDavid Howells 
57008e0e7c8SDavid Howells 	_enter("{%zu},", ncallbacks);
57108e0e7c8SDavid Howells 
57208e0e7c8SDavid Howells 	if (ncallbacks == 0)
57308e0e7c8SDavid Howells 		return 0;
57408e0e7c8SDavid Howells 	if (ncallbacks > AFSCBMAX)
57508e0e7c8SDavid Howells 		ncallbacks = AFSCBMAX;
57608e0e7c8SDavid Howells 
57708e0e7c8SDavid Howells 	_debug("break %zu callbacks", ncallbacks);
57808e0e7c8SDavid Howells 
57908e0e7c8SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSGiveUpCallBacks,
58008e0e7c8SDavid Howells 				   12 + ncallbacks * 6 * 4, 0);
58108e0e7c8SDavid Howells 	if (!call)
58208e0e7c8SDavid Howells 		return -ENOMEM;
58308e0e7c8SDavid Howells 
58408e0e7c8SDavid Howells 	call->service_id = FS_SERVICE;
58508e0e7c8SDavid Howells 	call->port = htons(AFS_FS_PORT);
58608e0e7c8SDavid Howells 
58708e0e7c8SDavid Howells 	/* marshall the parameters */
58808e0e7c8SDavid Howells 	bp = call->request;
58908e0e7c8SDavid Howells 	tp = bp + 2 + ncallbacks * 3;
59008e0e7c8SDavid Howells 	*bp++ = htonl(FSGIVEUPCALLBACKS);
59108e0e7c8SDavid Howells 	*bp++ = htonl(ncallbacks);
59208e0e7c8SDavid Howells 	*tp++ = htonl(ncallbacks);
59308e0e7c8SDavid Howells 
59408e0e7c8SDavid Howells 	atomic_sub(ncallbacks, &server->cb_break_n);
59508e0e7c8SDavid Howells 	for (loop = ncallbacks; loop > 0; loop--) {
59608e0e7c8SDavid Howells 		struct afs_callback *cb =
59708e0e7c8SDavid Howells 			&server->cb_break[server->cb_break_tail];
59808e0e7c8SDavid Howells 
59908e0e7c8SDavid Howells 		*bp++ = htonl(cb->fid.vid);
60008e0e7c8SDavid Howells 		*bp++ = htonl(cb->fid.vnode);
60108e0e7c8SDavid Howells 		*bp++ = htonl(cb->fid.unique);
60208e0e7c8SDavid Howells 		*tp++ = htonl(cb->version);
60308e0e7c8SDavid Howells 		*tp++ = htonl(cb->expiry);
60408e0e7c8SDavid Howells 		*tp++ = htonl(cb->type);
60508e0e7c8SDavid Howells 		smp_mb();
60608e0e7c8SDavid Howells 		server->cb_break_tail =
60708e0e7c8SDavid Howells 			(server->cb_break_tail + 1) &
60808e0e7c8SDavid Howells 			(ARRAY_SIZE(server->cb_break) - 1);
609ec26815aSDavid Howells 	}
61008e0e7c8SDavid Howells 
61108e0e7c8SDavid Howells 	ASSERT(ncallbacks > 0);
61208e0e7c8SDavid Howells 	wake_up_nr(&server->cb_break_waitq, ncallbacks);
61308e0e7c8SDavid Howells 
61408e0e7c8SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
61508e0e7c8SDavid Howells }
616260a9803SDavid Howells 
617260a9803SDavid Howells /*
618260a9803SDavid Howells  * deliver reply data to an FS.CreateFile or an FS.MakeDir
619260a9803SDavid Howells  */
620260a9803SDavid Howells static int afs_deliver_fs_create_vnode(struct afs_call *call,
621260a9803SDavid Howells 				       struct sk_buff *skb, bool last)
622260a9803SDavid Howells {
623260a9803SDavid Howells 	struct afs_vnode *vnode = call->reply;
624260a9803SDavid Howells 	const __be32 *bp;
625260a9803SDavid Howells 
626260a9803SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
627260a9803SDavid Howells 
628260a9803SDavid Howells 	afs_transfer_reply(call, skb);
629260a9803SDavid Howells 	if (!last)
630260a9803SDavid Howells 		return 0;
631260a9803SDavid Howells 
632260a9803SDavid Howells 	if (call->reply_size != call->reply_max)
633260a9803SDavid Howells 		return -EBADMSG;
634260a9803SDavid Howells 
635260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
636260a9803SDavid Howells 	bp = call->buffer;
637260a9803SDavid Howells 	xdr_decode_AFSFid(&bp, call->reply2);
63831143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
63931143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
640260a9803SDavid Howells 	xdr_decode_AFSCallBack_raw(&bp, call->reply4);
641260a9803SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
642260a9803SDavid Howells 
643260a9803SDavid Howells 	_leave(" = 0 [done]");
644260a9803SDavid Howells 	return 0;
645260a9803SDavid Howells }
646260a9803SDavid Howells 
647260a9803SDavid Howells /*
648260a9803SDavid Howells  * FS.CreateFile and FS.MakeDir operation type
649260a9803SDavid Howells  */
650260a9803SDavid Howells static const struct afs_call_type afs_RXFSCreateXXXX = {
651260a9803SDavid Howells 	.name		= "FS.CreateXXXX",
652260a9803SDavid Howells 	.deliver	= afs_deliver_fs_create_vnode,
653260a9803SDavid Howells 	.abort_to_error	= afs_abort_to_error,
654260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
655260a9803SDavid Howells };
656260a9803SDavid Howells 
657260a9803SDavid Howells /*
658260a9803SDavid Howells  * create a file or make a directory
659260a9803SDavid Howells  */
660260a9803SDavid Howells int afs_fs_create(struct afs_server *server,
661260a9803SDavid Howells 		  struct key *key,
662260a9803SDavid Howells 		  struct afs_vnode *vnode,
663260a9803SDavid Howells 		  const char *name,
664260a9803SDavid Howells 		  umode_t mode,
665260a9803SDavid Howells 		  struct afs_fid *newfid,
666260a9803SDavid Howells 		  struct afs_file_status *newstatus,
667260a9803SDavid Howells 		  struct afs_callback *newcb,
668260a9803SDavid Howells 		  const struct afs_wait_mode *wait_mode)
669260a9803SDavid Howells {
670260a9803SDavid Howells 	struct afs_call *call;
671260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
672260a9803SDavid Howells 	__be32 *bp;
673260a9803SDavid Howells 
674260a9803SDavid Howells 	_enter("");
675260a9803SDavid Howells 
676260a9803SDavid Howells 	namesz = strlen(name);
677260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
678260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (6 * 4);
679260a9803SDavid Howells 
680260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSCreateXXXX, reqsz,
681260a9803SDavid Howells 				   (3 + 21 + 21 + 3 + 6) * 4);
682260a9803SDavid Howells 	if (!call)
683260a9803SDavid Howells 		return -ENOMEM;
684260a9803SDavid Howells 
685260a9803SDavid Howells 	call->key = key;
686260a9803SDavid Howells 	call->reply = vnode;
687260a9803SDavid Howells 	call->reply2 = newfid;
688260a9803SDavid Howells 	call->reply3 = newstatus;
689260a9803SDavid Howells 	call->reply4 = newcb;
690260a9803SDavid Howells 	call->service_id = FS_SERVICE;
691260a9803SDavid Howells 	call->port = htons(AFS_FS_PORT);
692260a9803SDavid Howells 
693260a9803SDavid Howells 	/* marshall the parameters */
694260a9803SDavid Howells 	bp = call->request;
695260a9803SDavid Howells 	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
696260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
697260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
698260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
699260a9803SDavid Howells 	*bp++ = htonl(namesz);
700260a9803SDavid Howells 	memcpy(bp, name, namesz);
701260a9803SDavid Howells 	bp = (void *) bp + namesz;
702260a9803SDavid Howells 	if (padsz > 0) {
703260a9803SDavid Howells 		memset(bp, 0, padsz);
704260a9803SDavid Howells 		bp = (void *) bp + padsz;
705260a9803SDavid Howells 	}
706260a9803SDavid Howells 	*bp++ = htonl(AFS_SET_MODE);
707260a9803SDavid Howells 	*bp++ = 0; /* mtime */
708260a9803SDavid Howells 	*bp++ = 0; /* owner */
709260a9803SDavid Howells 	*bp++ = 0; /* group */
710260a9803SDavid Howells 	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
711260a9803SDavid Howells 	*bp++ = 0; /* segment size */
712260a9803SDavid Howells 
713260a9803SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
714260a9803SDavid Howells }
715260a9803SDavid Howells 
716260a9803SDavid Howells /*
717260a9803SDavid Howells  * deliver reply data to an FS.RemoveFile or FS.RemoveDir
718260a9803SDavid Howells  */
719260a9803SDavid Howells static int afs_deliver_fs_remove(struct afs_call *call,
720260a9803SDavid Howells 				 struct sk_buff *skb, bool last)
721260a9803SDavid Howells {
722260a9803SDavid Howells 	struct afs_vnode *vnode = call->reply;
723260a9803SDavid Howells 	const __be32 *bp;
724260a9803SDavid Howells 
725260a9803SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
726260a9803SDavid Howells 
727260a9803SDavid Howells 	afs_transfer_reply(call, skb);
728260a9803SDavid Howells 	if (!last)
729260a9803SDavid Howells 		return 0;
730260a9803SDavid Howells 
731260a9803SDavid Howells 	if (call->reply_size != call->reply_max)
732260a9803SDavid Howells 		return -EBADMSG;
733260a9803SDavid Howells 
734260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
735260a9803SDavid Howells 	bp = call->buffer;
73631143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
737260a9803SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
738260a9803SDavid Howells 
739260a9803SDavid Howells 	_leave(" = 0 [done]");
740260a9803SDavid Howells 	return 0;
741260a9803SDavid Howells }
742260a9803SDavid Howells 
743260a9803SDavid Howells /*
744260a9803SDavid Howells  * FS.RemoveDir/FS.RemoveFile operation type
745260a9803SDavid Howells  */
746260a9803SDavid Howells static const struct afs_call_type afs_RXFSRemoveXXXX = {
747260a9803SDavid Howells 	.name		= "FS.RemoveXXXX",
748260a9803SDavid Howells 	.deliver	= afs_deliver_fs_remove,
749260a9803SDavid Howells 	.abort_to_error	= afs_abort_to_error,
750260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
751260a9803SDavid Howells };
752260a9803SDavid Howells 
753260a9803SDavid Howells /*
754260a9803SDavid Howells  * remove a file or directory
755260a9803SDavid Howells  */
756260a9803SDavid Howells int afs_fs_remove(struct afs_server *server,
757260a9803SDavid Howells 		  struct key *key,
758260a9803SDavid Howells 		  struct afs_vnode *vnode,
759260a9803SDavid Howells 		  const char *name,
760260a9803SDavid Howells 		  bool isdir,
761260a9803SDavid Howells 		  const struct afs_wait_mode *wait_mode)
762260a9803SDavid Howells {
763260a9803SDavid Howells 	struct afs_call *call;
764260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
765260a9803SDavid Howells 	__be32 *bp;
766260a9803SDavid Howells 
767260a9803SDavid Howells 	_enter("");
768260a9803SDavid Howells 
769260a9803SDavid Howells 	namesz = strlen(name);
770260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
771260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz;
772260a9803SDavid Howells 
773260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSRemoveXXXX, reqsz, (21 + 6) * 4);
774260a9803SDavid Howells 	if (!call)
775260a9803SDavid Howells 		return -ENOMEM;
776260a9803SDavid Howells 
777260a9803SDavid Howells 	call->key = key;
778260a9803SDavid Howells 	call->reply = vnode;
779260a9803SDavid Howells 	call->service_id = FS_SERVICE;
780260a9803SDavid Howells 	call->port = htons(AFS_FS_PORT);
781260a9803SDavid Howells 
782260a9803SDavid Howells 	/* marshall the parameters */
783260a9803SDavid Howells 	bp = call->request;
784260a9803SDavid Howells 	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
785260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
786260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
787260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
788260a9803SDavid Howells 	*bp++ = htonl(namesz);
789260a9803SDavid Howells 	memcpy(bp, name, namesz);
790260a9803SDavid Howells 	bp = (void *) bp + namesz;
791260a9803SDavid Howells 	if (padsz > 0) {
792260a9803SDavid Howells 		memset(bp, 0, padsz);
793260a9803SDavid Howells 		bp = (void *) bp + padsz;
794260a9803SDavid Howells 	}
795260a9803SDavid Howells 
796260a9803SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
797260a9803SDavid Howells }
798260a9803SDavid Howells 
799260a9803SDavid Howells /*
800260a9803SDavid Howells  * deliver reply data to an FS.Link
801260a9803SDavid Howells  */
802260a9803SDavid Howells static int afs_deliver_fs_link(struct afs_call *call,
803260a9803SDavid Howells 			       struct sk_buff *skb, bool last)
804260a9803SDavid Howells {
805260a9803SDavid Howells 	struct afs_vnode *dvnode = call->reply, *vnode = call->reply2;
806260a9803SDavid Howells 	const __be32 *bp;
807260a9803SDavid Howells 
808260a9803SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
809260a9803SDavid Howells 
810260a9803SDavid Howells 	afs_transfer_reply(call, skb);
811260a9803SDavid Howells 	if (!last)
812260a9803SDavid Howells 		return 0;
813260a9803SDavid Howells 
814260a9803SDavid Howells 	if (call->reply_size != call->reply_max)
815260a9803SDavid Howells 		return -EBADMSG;
816260a9803SDavid Howells 
817260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
818260a9803SDavid Howells 	bp = call->buffer;
81931143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
82031143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
821260a9803SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
822260a9803SDavid Howells 
823260a9803SDavid Howells 	_leave(" = 0 [done]");
824260a9803SDavid Howells 	return 0;
825260a9803SDavid Howells }
826260a9803SDavid Howells 
827260a9803SDavid Howells /*
828260a9803SDavid Howells  * FS.Link operation type
829260a9803SDavid Howells  */
830260a9803SDavid Howells static const struct afs_call_type afs_RXFSLink = {
831260a9803SDavid Howells 	.name		= "FS.Link",
832260a9803SDavid Howells 	.deliver	= afs_deliver_fs_link,
833260a9803SDavid Howells 	.abort_to_error	= afs_abort_to_error,
834260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
835260a9803SDavid Howells };
836260a9803SDavid Howells 
837260a9803SDavid Howells /*
838260a9803SDavid Howells  * make a hard link
839260a9803SDavid Howells  */
840260a9803SDavid Howells int afs_fs_link(struct afs_server *server,
841260a9803SDavid Howells 		struct key *key,
842260a9803SDavid Howells 		struct afs_vnode *dvnode,
843260a9803SDavid Howells 		struct afs_vnode *vnode,
844260a9803SDavid Howells 		const char *name,
845260a9803SDavid Howells 		const struct afs_wait_mode *wait_mode)
846260a9803SDavid Howells {
847260a9803SDavid Howells 	struct afs_call *call;
848260a9803SDavid Howells 	size_t namesz, reqsz, padsz;
849260a9803SDavid Howells 	__be32 *bp;
850260a9803SDavid Howells 
851260a9803SDavid Howells 	_enter("");
852260a9803SDavid Howells 
853260a9803SDavid Howells 	namesz = strlen(name);
854260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
855260a9803SDavid Howells 	reqsz = (5 * 4) + namesz + padsz + (3 * 4);
856260a9803SDavid Howells 
857260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
858260a9803SDavid Howells 	if (!call)
859260a9803SDavid Howells 		return -ENOMEM;
860260a9803SDavid Howells 
861260a9803SDavid Howells 	call->key = key;
862260a9803SDavid Howells 	call->reply = dvnode;
863260a9803SDavid Howells 	call->reply2 = vnode;
864260a9803SDavid Howells 	call->service_id = FS_SERVICE;
865260a9803SDavid Howells 	call->port = htons(AFS_FS_PORT);
866260a9803SDavid Howells 
867260a9803SDavid Howells 	/* marshall the parameters */
868260a9803SDavid Howells 	bp = call->request;
869260a9803SDavid Howells 	*bp++ = htonl(FSLINK);
870260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vid);
871260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.vnode);
872260a9803SDavid Howells 	*bp++ = htonl(dvnode->fid.unique);
873260a9803SDavid Howells 	*bp++ = htonl(namesz);
874260a9803SDavid Howells 	memcpy(bp, name, namesz);
875260a9803SDavid Howells 	bp = (void *) bp + namesz;
876260a9803SDavid Howells 	if (padsz > 0) {
877260a9803SDavid Howells 		memset(bp, 0, padsz);
878260a9803SDavid Howells 		bp = (void *) bp + padsz;
879260a9803SDavid Howells 	}
880260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
881260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
882260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
883260a9803SDavid Howells 
884260a9803SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
885260a9803SDavid Howells }
886260a9803SDavid Howells 
887260a9803SDavid Howells /*
888260a9803SDavid Howells  * deliver reply data to an FS.Symlink
889260a9803SDavid Howells  */
890260a9803SDavid Howells static int afs_deliver_fs_symlink(struct afs_call *call,
891260a9803SDavid Howells 				  struct sk_buff *skb, bool last)
892260a9803SDavid Howells {
893260a9803SDavid Howells 	struct afs_vnode *vnode = call->reply;
894260a9803SDavid Howells 	const __be32 *bp;
895260a9803SDavid Howells 
896260a9803SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
897260a9803SDavid Howells 
898260a9803SDavid Howells 	afs_transfer_reply(call, skb);
899260a9803SDavid Howells 	if (!last)
900260a9803SDavid Howells 		return 0;
901260a9803SDavid Howells 
902260a9803SDavid Howells 	if (call->reply_size != call->reply_max)
903260a9803SDavid Howells 		return -EBADMSG;
904260a9803SDavid Howells 
905260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
906260a9803SDavid Howells 	bp = call->buffer;
907260a9803SDavid Howells 	xdr_decode_AFSFid(&bp, call->reply2);
90831143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
90931143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
910260a9803SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
911260a9803SDavid Howells 
912260a9803SDavid Howells 	_leave(" = 0 [done]");
913260a9803SDavid Howells 	return 0;
914260a9803SDavid Howells }
915260a9803SDavid Howells 
916260a9803SDavid Howells /*
917260a9803SDavid Howells  * FS.Symlink operation type
918260a9803SDavid Howells  */
919260a9803SDavid Howells static const struct afs_call_type afs_RXFSSymlink = {
920260a9803SDavid Howells 	.name		= "FS.Symlink",
921260a9803SDavid Howells 	.deliver	= afs_deliver_fs_symlink,
922260a9803SDavid Howells 	.abort_to_error	= afs_abort_to_error,
923260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
924260a9803SDavid Howells };
925260a9803SDavid Howells 
926260a9803SDavid Howells /*
927260a9803SDavid Howells  * create a symbolic link
928260a9803SDavid Howells  */
929260a9803SDavid Howells int afs_fs_symlink(struct afs_server *server,
930260a9803SDavid Howells 		   struct key *key,
931260a9803SDavid Howells 		   struct afs_vnode *vnode,
932260a9803SDavid Howells 		   const char *name,
933260a9803SDavid Howells 		   const char *contents,
934260a9803SDavid Howells 		   struct afs_fid *newfid,
935260a9803SDavid Howells 		   struct afs_file_status *newstatus,
936260a9803SDavid Howells 		   const struct afs_wait_mode *wait_mode)
937260a9803SDavid Howells {
938260a9803SDavid Howells 	struct afs_call *call;
939260a9803SDavid Howells 	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
940260a9803SDavid Howells 	__be32 *bp;
941260a9803SDavid Howells 
942260a9803SDavid Howells 	_enter("");
943260a9803SDavid Howells 
944260a9803SDavid Howells 	namesz = strlen(name);
945260a9803SDavid Howells 	padsz = (4 - (namesz & 3)) & 3;
946260a9803SDavid Howells 
947260a9803SDavid Howells 	c_namesz = strlen(contents);
948260a9803SDavid Howells 	c_padsz = (4 - (c_namesz & 3)) & 3;
949260a9803SDavid Howells 
950260a9803SDavid Howells 	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);
951260a9803SDavid Howells 
952260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSSymlink, reqsz,
953260a9803SDavid Howells 				   (3 + 21 + 21 + 6) * 4);
954260a9803SDavid Howells 	if (!call)
955260a9803SDavid Howells 		return -ENOMEM;
956260a9803SDavid Howells 
957260a9803SDavid Howells 	call->key = key;
958260a9803SDavid Howells 	call->reply = vnode;
959260a9803SDavid Howells 	call->reply2 = newfid;
960260a9803SDavid Howells 	call->reply3 = newstatus;
961260a9803SDavid Howells 	call->service_id = FS_SERVICE;
962260a9803SDavid Howells 	call->port = htons(AFS_FS_PORT);
963260a9803SDavid Howells 
964260a9803SDavid Howells 	/* marshall the parameters */
965260a9803SDavid Howells 	bp = call->request;
966260a9803SDavid Howells 	*bp++ = htonl(FSSYMLINK);
967260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
968260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
969260a9803SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
970260a9803SDavid Howells 	*bp++ = htonl(namesz);
971260a9803SDavid Howells 	memcpy(bp, name, namesz);
972260a9803SDavid Howells 	bp = (void *) bp + namesz;
973260a9803SDavid Howells 	if (padsz > 0) {
974260a9803SDavid Howells 		memset(bp, 0, padsz);
975260a9803SDavid Howells 		bp = (void *) bp + padsz;
976260a9803SDavid Howells 	}
977260a9803SDavid Howells 	*bp++ = htonl(c_namesz);
978260a9803SDavid Howells 	memcpy(bp, contents, c_namesz);
979260a9803SDavid Howells 	bp = (void *) bp + c_namesz;
980260a9803SDavid Howells 	if (c_padsz > 0) {
981260a9803SDavid Howells 		memset(bp, 0, c_padsz);
982260a9803SDavid Howells 		bp = (void *) bp + c_padsz;
983260a9803SDavid Howells 	}
984260a9803SDavid Howells 	*bp++ = htonl(AFS_SET_MODE);
985260a9803SDavid Howells 	*bp++ = 0; /* mtime */
986260a9803SDavid Howells 	*bp++ = 0; /* owner */
987260a9803SDavid Howells 	*bp++ = 0; /* group */
988260a9803SDavid Howells 	*bp++ = htonl(S_IRWXUGO); /* unix mode */
989260a9803SDavid Howells 	*bp++ = 0; /* segment size */
990260a9803SDavid Howells 
991260a9803SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
992260a9803SDavid Howells }
993260a9803SDavid Howells 
994260a9803SDavid Howells /*
995260a9803SDavid Howells  * deliver reply data to an FS.Rename
996260a9803SDavid Howells  */
997260a9803SDavid Howells static int afs_deliver_fs_rename(struct afs_call *call,
998260a9803SDavid Howells 				  struct sk_buff *skb, bool last)
999260a9803SDavid Howells {
1000260a9803SDavid Howells 	struct afs_vnode *orig_dvnode = call->reply, *new_dvnode = call->reply2;
1001260a9803SDavid Howells 	const __be32 *bp;
1002260a9803SDavid Howells 
1003260a9803SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
1004260a9803SDavid Howells 
1005260a9803SDavid Howells 	afs_transfer_reply(call, skb);
1006260a9803SDavid Howells 	if (!last)
1007260a9803SDavid Howells 		return 0;
1008260a9803SDavid Howells 
1009260a9803SDavid Howells 	if (call->reply_size != call->reply_max)
1010260a9803SDavid Howells 		return -EBADMSG;
1011260a9803SDavid Howells 
1012260a9803SDavid Howells 	/* unmarshall the reply once we've received all of it */
1013260a9803SDavid Howells 	bp = call->buffer;
101431143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
1015260a9803SDavid Howells 	if (new_dvnode != orig_dvnode)
101631143d5dSDavid Howells 		xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
101731143d5dSDavid Howells 					  NULL);
1018260a9803SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
1019260a9803SDavid Howells 
1020260a9803SDavid Howells 	_leave(" = 0 [done]");
1021260a9803SDavid Howells 	return 0;
1022260a9803SDavid Howells }
1023260a9803SDavid Howells 
1024260a9803SDavid Howells /*
1025260a9803SDavid Howells  * FS.Rename operation type
1026260a9803SDavid Howells  */
1027260a9803SDavid Howells static const struct afs_call_type afs_RXFSRename = {
1028260a9803SDavid Howells 	.name		= "FS.Rename",
1029260a9803SDavid Howells 	.deliver	= afs_deliver_fs_rename,
1030260a9803SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1031260a9803SDavid Howells 	.destructor	= afs_flat_call_destructor,
1032260a9803SDavid Howells };
1033260a9803SDavid Howells 
1034260a9803SDavid Howells /*
1035260a9803SDavid Howells  * create a symbolic link
1036260a9803SDavid Howells  */
1037260a9803SDavid Howells int afs_fs_rename(struct afs_server *server,
1038260a9803SDavid Howells 		  struct key *key,
1039260a9803SDavid Howells 		  struct afs_vnode *orig_dvnode,
1040260a9803SDavid Howells 		  const char *orig_name,
1041260a9803SDavid Howells 		  struct afs_vnode *new_dvnode,
1042260a9803SDavid Howells 		  const char *new_name,
1043260a9803SDavid Howells 		  const struct afs_wait_mode *wait_mode)
1044260a9803SDavid Howells {
1045260a9803SDavid Howells 	struct afs_call *call;
1046260a9803SDavid Howells 	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
1047260a9803SDavid Howells 	__be32 *bp;
1048260a9803SDavid Howells 
1049260a9803SDavid Howells 	_enter("");
1050260a9803SDavid Howells 
1051260a9803SDavid Howells 	o_namesz = strlen(orig_name);
1052260a9803SDavid Howells 	o_padsz = (4 - (o_namesz & 3)) & 3;
1053260a9803SDavid Howells 
1054260a9803SDavid Howells 	n_namesz = strlen(new_name);
1055260a9803SDavid Howells 	n_padsz = (4 - (n_namesz & 3)) & 3;
1056260a9803SDavid Howells 
1057260a9803SDavid Howells 	reqsz = (4 * 4) +
1058260a9803SDavid Howells 		4 + o_namesz + o_padsz +
1059260a9803SDavid Howells 		(3 * 4) +
1060260a9803SDavid Howells 		4 + n_namesz + n_padsz;
1061260a9803SDavid Howells 
1062260a9803SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1063260a9803SDavid Howells 	if (!call)
1064260a9803SDavid Howells 		return -ENOMEM;
1065260a9803SDavid Howells 
1066260a9803SDavid Howells 	call->key = key;
1067260a9803SDavid Howells 	call->reply = orig_dvnode;
1068260a9803SDavid Howells 	call->reply2 = new_dvnode;
1069260a9803SDavid Howells 	call->service_id = FS_SERVICE;
1070260a9803SDavid Howells 	call->port = htons(AFS_FS_PORT);
1071260a9803SDavid Howells 
1072260a9803SDavid Howells 	/* marshall the parameters */
1073260a9803SDavid Howells 	bp = call->request;
1074260a9803SDavid Howells 	*bp++ = htonl(FSRENAME);
1075260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vid);
1076260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.vnode);
1077260a9803SDavid Howells 	*bp++ = htonl(orig_dvnode->fid.unique);
1078260a9803SDavid Howells 	*bp++ = htonl(o_namesz);
1079260a9803SDavid Howells 	memcpy(bp, orig_name, o_namesz);
1080260a9803SDavid Howells 	bp = (void *) bp + o_namesz;
1081260a9803SDavid Howells 	if (o_padsz > 0) {
1082260a9803SDavid Howells 		memset(bp, 0, o_padsz);
1083260a9803SDavid Howells 		bp = (void *) bp + o_padsz;
1084260a9803SDavid Howells 	}
1085260a9803SDavid Howells 
1086260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vid);
1087260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.vnode);
1088260a9803SDavid Howells 	*bp++ = htonl(new_dvnode->fid.unique);
1089260a9803SDavid Howells 	*bp++ = htonl(n_namesz);
1090260a9803SDavid Howells 	memcpy(bp, new_name, n_namesz);
1091260a9803SDavid Howells 	bp = (void *) bp + n_namesz;
1092260a9803SDavid Howells 	if (n_padsz > 0) {
1093260a9803SDavid Howells 		memset(bp, 0, n_padsz);
1094260a9803SDavid Howells 		bp = (void *) bp + n_padsz;
1095260a9803SDavid Howells 	}
1096260a9803SDavid Howells 
1097260a9803SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1098260a9803SDavid Howells }
109931143d5dSDavid Howells 
110031143d5dSDavid Howells /*
110131143d5dSDavid Howells  * deliver reply data to an FS.StoreData
110231143d5dSDavid Howells  */
110331143d5dSDavid Howells static int afs_deliver_fs_store_data(struct afs_call *call,
110431143d5dSDavid Howells 				     struct sk_buff *skb, bool last)
110531143d5dSDavid Howells {
110631143d5dSDavid Howells 	struct afs_vnode *vnode = call->reply;
110731143d5dSDavid Howells 	const __be32 *bp;
110831143d5dSDavid Howells 
110931143d5dSDavid Howells 	_enter(",,%u", last);
111031143d5dSDavid Howells 
111131143d5dSDavid Howells 	afs_transfer_reply(call, skb);
111231143d5dSDavid Howells 	if (!last) {
111331143d5dSDavid Howells 		_leave(" = 0 [more]");
111431143d5dSDavid Howells 		return 0;
111531143d5dSDavid Howells 	}
111631143d5dSDavid Howells 
111731143d5dSDavid Howells 	if (call->reply_size != call->reply_max) {
111831143d5dSDavid Howells 		_leave(" = -EBADMSG [%u != %u]",
111931143d5dSDavid Howells 		       call->reply_size, call->reply_max);
112031143d5dSDavid Howells 		return -EBADMSG;
112131143d5dSDavid Howells 	}
112231143d5dSDavid Howells 
112331143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
112431143d5dSDavid Howells 	bp = call->buffer;
112531143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
112631143d5dSDavid Howells 				  &call->store_version);
112731143d5dSDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
112831143d5dSDavid Howells 
112931143d5dSDavid Howells 	afs_pages_written_back(vnode, call);
113031143d5dSDavid Howells 
113131143d5dSDavid Howells 	_leave(" = 0 [done]");
113231143d5dSDavid Howells 	return 0;
113331143d5dSDavid Howells }
113431143d5dSDavid Howells 
113531143d5dSDavid Howells /*
113631143d5dSDavid Howells  * FS.StoreData operation type
113731143d5dSDavid Howells  */
113831143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData = {
113931143d5dSDavid Howells 	.name		= "FS.StoreData",
114031143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_data,
114131143d5dSDavid Howells 	.abort_to_error	= afs_abort_to_error,
114231143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
114331143d5dSDavid Howells };
114431143d5dSDavid Howells 
1145b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64 = {
1146b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1147b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_data,
1148b9b1f8d5SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1149b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1150b9b1f8d5SDavid Howells };
1151b9b1f8d5SDavid Howells 
1152b9b1f8d5SDavid Howells /*
1153b9b1f8d5SDavid Howells  * store a set of pages to a very large file
1154b9b1f8d5SDavid Howells  */
1155b9b1f8d5SDavid Howells static int afs_fs_store_data64(struct afs_server *server,
1156b9b1f8d5SDavid Howells 			       struct afs_writeback *wb,
1157b9b1f8d5SDavid Howells 			       pgoff_t first, pgoff_t last,
1158b9b1f8d5SDavid Howells 			       unsigned offset, unsigned to,
1159b9b1f8d5SDavid Howells 			       loff_t size, loff_t pos, loff_t i_size,
1160b9b1f8d5SDavid Howells 			       const struct afs_wait_mode *wait_mode)
1161b9b1f8d5SDavid Howells {
1162b9b1f8d5SDavid Howells 	struct afs_vnode *vnode = wb->vnode;
1163b9b1f8d5SDavid Howells 	struct afs_call *call;
1164b9b1f8d5SDavid Howells 	__be32 *bp;
1165b9b1f8d5SDavid Howells 
1166b9b1f8d5SDavid Howells 	_enter(",%x,{%x:%u},,",
1167b9b1f8d5SDavid Howells 	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
1168b9b1f8d5SDavid Howells 
1169b9b1f8d5SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSStoreData64,
1170b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1171b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1172b9b1f8d5SDavid Howells 	if (!call)
1173b9b1f8d5SDavid Howells 		return -ENOMEM;
1174b9b1f8d5SDavid Howells 
1175b9b1f8d5SDavid Howells 	call->wb = wb;
1176b9b1f8d5SDavid Howells 	call->key = wb->key;
1177b9b1f8d5SDavid Howells 	call->reply = vnode;
1178b9b1f8d5SDavid Howells 	call->service_id = FS_SERVICE;
1179b9b1f8d5SDavid Howells 	call->port = htons(AFS_FS_PORT);
1180b9b1f8d5SDavid Howells 	call->mapping = vnode->vfs_inode.i_mapping;
1181b9b1f8d5SDavid Howells 	call->first = first;
1182b9b1f8d5SDavid Howells 	call->last = last;
1183b9b1f8d5SDavid Howells 	call->first_offset = offset;
1184b9b1f8d5SDavid Howells 	call->last_to = to;
1185b9b1f8d5SDavid Howells 	call->send_pages = true;
1186b9b1f8d5SDavid Howells 	call->store_version = vnode->status.data_version + 1;
1187b9b1f8d5SDavid Howells 
1188b9b1f8d5SDavid Howells 	/* marshall the parameters */
1189b9b1f8d5SDavid Howells 	bp = call->request;
1190b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1191b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1192b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1193b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1194b9b1f8d5SDavid Howells 
1195b9b1f8d5SDavid Howells 	*bp++ = 0; /* mask */
1196b9b1f8d5SDavid Howells 	*bp++ = 0; /* mtime */
1197b9b1f8d5SDavid Howells 	*bp++ = 0; /* owner */
1198b9b1f8d5SDavid Howells 	*bp++ = 0; /* group */
1199b9b1f8d5SDavid Howells 	*bp++ = 0; /* unix mode */
1200b9b1f8d5SDavid Howells 	*bp++ = 0; /* segment size */
1201b9b1f8d5SDavid Howells 
1202b9b1f8d5SDavid Howells 	*bp++ = htonl(pos >> 32);
1203b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) pos);
1204b9b1f8d5SDavid Howells 	*bp++ = htonl(size >> 32);
1205b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) size);
1206b9b1f8d5SDavid Howells 	*bp++ = htonl(i_size >> 32);
1207b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) i_size);
1208b9b1f8d5SDavid Howells 
1209b9b1f8d5SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1210b9b1f8d5SDavid Howells }
1211b9b1f8d5SDavid Howells 
121231143d5dSDavid Howells /*
121331143d5dSDavid Howells  * store a set of pages
121431143d5dSDavid Howells  */
121531143d5dSDavid Howells int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
121631143d5dSDavid Howells 		      pgoff_t first, pgoff_t last,
121731143d5dSDavid Howells 		      unsigned offset, unsigned to,
121831143d5dSDavid Howells 		      const struct afs_wait_mode *wait_mode)
121931143d5dSDavid Howells {
122031143d5dSDavid Howells 	struct afs_vnode *vnode = wb->vnode;
122131143d5dSDavid Howells 	struct afs_call *call;
122231143d5dSDavid Howells 	loff_t size, pos, i_size;
122331143d5dSDavid Howells 	__be32 *bp;
122431143d5dSDavid Howells 
122531143d5dSDavid Howells 	_enter(",%x,{%x:%u},,",
122631143d5dSDavid Howells 	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
122731143d5dSDavid Howells 
122831143d5dSDavid Howells 	size = to - offset;
122931143d5dSDavid Howells 	if (first != last)
123031143d5dSDavid Howells 		size += (loff_t)(last - first) << PAGE_SHIFT;
123131143d5dSDavid Howells 	pos = (loff_t)first << PAGE_SHIFT;
123231143d5dSDavid Howells 	pos += offset;
123331143d5dSDavid Howells 
123431143d5dSDavid Howells 	i_size = i_size_read(&vnode->vfs_inode);
123531143d5dSDavid Howells 	if (pos + size > i_size)
123631143d5dSDavid Howells 		i_size = size + pos;
123731143d5dSDavid Howells 
123831143d5dSDavid Howells 	_debug("size %llx, at %llx, i_size %llx",
123931143d5dSDavid Howells 	       (unsigned long long) size, (unsigned long long) pos,
124031143d5dSDavid Howells 	       (unsigned long long) i_size);
124131143d5dSDavid Howells 
1242b9b1f8d5SDavid Howells 	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1243b9b1f8d5SDavid Howells 		return afs_fs_store_data64(server, wb, first, last, offset, to,
1244b9b1f8d5SDavid Howells 					   size, pos, i_size, wait_mode);
124531143d5dSDavid Howells 
124631143d5dSDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSStoreData,
124731143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
124831143d5dSDavid Howells 				   (21 + 6) * 4);
124931143d5dSDavid Howells 	if (!call)
125031143d5dSDavid Howells 		return -ENOMEM;
125131143d5dSDavid Howells 
125231143d5dSDavid Howells 	call->wb = wb;
125331143d5dSDavid Howells 	call->key = wb->key;
125431143d5dSDavid Howells 	call->reply = vnode;
125531143d5dSDavid Howells 	call->service_id = FS_SERVICE;
125631143d5dSDavid Howells 	call->port = htons(AFS_FS_PORT);
125731143d5dSDavid Howells 	call->mapping = vnode->vfs_inode.i_mapping;
125831143d5dSDavid Howells 	call->first = first;
125931143d5dSDavid Howells 	call->last = last;
126031143d5dSDavid Howells 	call->first_offset = offset;
126131143d5dSDavid Howells 	call->last_to = to;
126231143d5dSDavid Howells 	call->send_pages = true;
126331143d5dSDavid Howells 	call->store_version = vnode->status.data_version + 1;
126431143d5dSDavid Howells 
126531143d5dSDavid Howells 	/* marshall the parameters */
126631143d5dSDavid Howells 	bp = call->request;
126731143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
126831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
126931143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
127031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
127131143d5dSDavid Howells 
127231143d5dSDavid Howells 	*bp++ = 0; /* mask */
127331143d5dSDavid Howells 	*bp++ = 0; /* mtime */
127431143d5dSDavid Howells 	*bp++ = 0; /* owner */
127531143d5dSDavid Howells 	*bp++ = 0; /* group */
127631143d5dSDavid Howells 	*bp++ = 0; /* unix mode */
127731143d5dSDavid Howells 	*bp++ = 0; /* segment size */
127831143d5dSDavid Howells 
127931143d5dSDavid Howells 	*bp++ = htonl(pos);
128031143d5dSDavid Howells 	*bp++ = htonl(size);
128131143d5dSDavid Howells 	*bp++ = htonl(i_size);
128231143d5dSDavid Howells 
128331143d5dSDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
128431143d5dSDavid Howells }
128531143d5dSDavid Howells 
128631143d5dSDavid Howells /*
128731143d5dSDavid Howells  * deliver reply data to an FS.StoreStatus
128831143d5dSDavid Howells  */
128931143d5dSDavid Howells static int afs_deliver_fs_store_status(struct afs_call *call,
129031143d5dSDavid Howells 				       struct sk_buff *skb, bool last)
129131143d5dSDavid Howells {
129231143d5dSDavid Howells 	afs_dataversion_t *store_version;
129331143d5dSDavid Howells 	struct afs_vnode *vnode = call->reply;
129431143d5dSDavid Howells 	const __be32 *bp;
129531143d5dSDavid Howells 
129631143d5dSDavid Howells 	_enter(",,%u", last);
129731143d5dSDavid Howells 
129831143d5dSDavid Howells 	afs_transfer_reply(call, skb);
129931143d5dSDavid Howells 	if (!last) {
130031143d5dSDavid Howells 		_leave(" = 0 [more]");
130131143d5dSDavid Howells 		return 0;
130231143d5dSDavid Howells 	}
130331143d5dSDavid Howells 
130431143d5dSDavid Howells 	if (call->reply_size != call->reply_max) {
130531143d5dSDavid Howells 		_leave(" = -EBADMSG [%u != %u]",
130631143d5dSDavid Howells 		       call->reply_size, call->reply_max);
130731143d5dSDavid Howells 		return -EBADMSG;
130831143d5dSDavid Howells 	}
130931143d5dSDavid Howells 
131031143d5dSDavid Howells 	/* unmarshall the reply once we've received all of it */
131131143d5dSDavid Howells 	store_version = NULL;
131231143d5dSDavid Howells 	if (call->operation_ID == FSSTOREDATA)
131331143d5dSDavid Howells 		store_version = &call->store_version;
131431143d5dSDavid Howells 
131531143d5dSDavid Howells 	bp = call->buffer;
131631143d5dSDavid Howells 	xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
131731143d5dSDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
131831143d5dSDavid Howells 
131931143d5dSDavid Howells 	_leave(" = 0 [done]");
132031143d5dSDavid Howells 	return 0;
132131143d5dSDavid Howells }
132231143d5dSDavid Howells 
132331143d5dSDavid Howells /*
132431143d5dSDavid Howells  * FS.StoreStatus operation type
132531143d5dSDavid Howells  */
132631143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreStatus = {
132731143d5dSDavid Howells 	.name		= "FS.StoreStatus",
132831143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
132931143d5dSDavid Howells 	.abort_to_error	= afs_abort_to_error,
133031143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
133131143d5dSDavid Howells };
133231143d5dSDavid Howells 
133331143d5dSDavid Howells static const struct afs_call_type afs_RXFSStoreData_as_Status = {
133431143d5dSDavid Howells 	.name		= "FS.StoreData",
133531143d5dSDavid Howells 	.deliver	= afs_deliver_fs_store_status,
133631143d5dSDavid Howells 	.abort_to_error	= afs_abort_to_error,
133731143d5dSDavid Howells 	.destructor	= afs_flat_call_destructor,
133831143d5dSDavid Howells };
133931143d5dSDavid Howells 
1340b9b1f8d5SDavid Howells static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
1341b9b1f8d5SDavid Howells 	.name		= "FS.StoreData64",
1342b9b1f8d5SDavid Howells 	.deliver	= afs_deliver_fs_store_status,
1343b9b1f8d5SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1344b9b1f8d5SDavid Howells 	.destructor	= afs_flat_call_destructor,
1345b9b1f8d5SDavid Howells };
1346b9b1f8d5SDavid Howells 
1347b9b1f8d5SDavid Howells /*
1348b9b1f8d5SDavid Howells  * set the attributes on a very large file, using FS.StoreData rather than
1349b9b1f8d5SDavid Howells  * FS.StoreStatus so as to alter the file size also
1350b9b1f8d5SDavid Howells  */
1351b9b1f8d5SDavid Howells static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
1352b9b1f8d5SDavid Howells 				 struct afs_vnode *vnode, struct iattr *attr,
1353b9b1f8d5SDavid Howells 				 const struct afs_wait_mode *wait_mode)
1354b9b1f8d5SDavid Howells {
1355b9b1f8d5SDavid Howells 	struct afs_call *call;
1356b9b1f8d5SDavid Howells 	__be32 *bp;
1357b9b1f8d5SDavid Howells 
1358b9b1f8d5SDavid Howells 	_enter(",%x,{%x:%u},,",
1359b9b1f8d5SDavid Howells 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
1360b9b1f8d5SDavid Howells 
1361b9b1f8d5SDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1362b9b1f8d5SDavid Howells 
1363b9b1f8d5SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
1364b9b1f8d5SDavid Howells 				   (4 + 6 + 3 * 2) * 4,
1365b9b1f8d5SDavid Howells 				   (21 + 6) * 4);
1366b9b1f8d5SDavid Howells 	if (!call)
1367b9b1f8d5SDavid Howells 		return -ENOMEM;
1368b9b1f8d5SDavid Howells 
1369b9b1f8d5SDavid Howells 	call->key = key;
1370b9b1f8d5SDavid Howells 	call->reply = vnode;
1371b9b1f8d5SDavid Howells 	call->service_id = FS_SERVICE;
1372b9b1f8d5SDavid Howells 	call->port = htons(AFS_FS_PORT);
1373b9b1f8d5SDavid Howells 	call->store_version = vnode->status.data_version + 1;
1374b9b1f8d5SDavid Howells 	call->operation_ID = FSSTOREDATA;
1375b9b1f8d5SDavid Howells 
1376b9b1f8d5SDavid Howells 	/* marshall the parameters */
1377b9b1f8d5SDavid Howells 	bp = call->request;
1378b9b1f8d5SDavid Howells 	*bp++ = htonl(FSSTOREDATA64);
1379b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1380b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1381b9b1f8d5SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1382b9b1f8d5SDavid Howells 
1383b9b1f8d5SDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
1384b9b1f8d5SDavid Howells 
1385b9b1f8d5SDavid Howells 	*bp++ = 0;				/* position of start of write */
1386b9b1f8d5SDavid Howells 	*bp++ = 0;
1387b9b1f8d5SDavid Howells 	*bp++ = 0;				/* size of write */
1388b9b1f8d5SDavid Howells 	*bp++ = 0;
1389b9b1f8d5SDavid Howells 	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
1390b9b1f8d5SDavid Howells 	*bp++ = htonl((u32) attr->ia_size);
1391b9b1f8d5SDavid Howells 
1392b9b1f8d5SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1393b9b1f8d5SDavid Howells }
1394b9b1f8d5SDavid Howells 
139531143d5dSDavid Howells /*
139631143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
139731143d5dSDavid Howells  * so as to alter the file size also
139831143d5dSDavid Howells  */
139931143d5dSDavid Howells static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
140031143d5dSDavid Howells 			       struct afs_vnode *vnode, struct iattr *attr,
140131143d5dSDavid Howells 			       const struct afs_wait_mode *wait_mode)
140231143d5dSDavid Howells {
140331143d5dSDavid Howells 	struct afs_call *call;
140431143d5dSDavid Howells 	__be32 *bp;
140531143d5dSDavid Howells 
140631143d5dSDavid Howells 	_enter(",%x,{%x:%u},,",
140731143d5dSDavid Howells 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
140831143d5dSDavid Howells 
140931143d5dSDavid Howells 	ASSERT(attr->ia_valid & ATTR_SIZE);
1410b9b1f8d5SDavid Howells 	if (attr->ia_size >> 32)
1411b9b1f8d5SDavid Howells 		return afs_fs_setattr_size64(server, key, vnode, attr,
1412b9b1f8d5SDavid Howells 					     wait_mode);
141331143d5dSDavid Howells 
141431143d5dSDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
141531143d5dSDavid Howells 				   (4 + 6 + 3) * 4,
141631143d5dSDavid Howells 				   (21 + 6) * 4);
141731143d5dSDavid Howells 	if (!call)
141831143d5dSDavid Howells 		return -ENOMEM;
141931143d5dSDavid Howells 
142031143d5dSDavid Howells 	call->key = key;
142131143d5dSDavid Howells 	call->reply = vnode;
142231143d5dSDavid Howells 	call->service_id = FS_SERVICE;
142331143d5dSDavid Howells 	call->port = htons(AFS_FS_PORT);
142431143d5dSDavid Howells 	call->store_version = vnode->status.data_version + 1;
142531143d5dSDavid Howells 	call->operation_ID = FSSTOREDATA;
142631143d5dSDavid Howells 
142731143d5dSDavid Howells 	/* marshall the parameters */
142831143d5dSDavid Howells 	bp = call->request;
142931143d5dSDavid Howells 	*bp++ = htonl(FSSTOREDATA);
143031143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
143131143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
143231143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
143331143d5dSDavid Howells 
143431143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
143531143d5dSDavid Howells 
143631143d5dSDavid Howells 	*bp++ = 0;				/* position of start of write */
143731143d5dSDavid Howells 	*bp++ = 0;				/* size of write */
143831143d5dSDavid Howells 	*bp++ = htonl(attr->ia_size);		/* new file length */
143931143d5dSDavid Howells 
144031143d5dSDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
144131143d5dSDavid Howells }
144231143d5dSDavid Howells 
144331143d5dSDavid Howells /*
144431143d5dSDavid Howells  * set the attributes on a file, using FS.StoreData if there's a change in file
144531143d5dSDavid Howells  * size, and FS.StoreStatus otherwise
144631143d5dSDavid Howells  */
144731143d5dSDavid Howells int afs_fs_setattr(struct afs_server *server, struct key *key,
144831143d5dSDavid Howells 		   struct afs_vnode *vnode, struct iattr *attr,
144931143d5dSDavid Howells 		   const struct afs_wait_mode *wait_mode)
145031143d5dSDavid Howells {
145131143d5dSDavid Howells 	struct afs_call *call;
145231143d5dSDavid Howells 	__be32 *bp;
145331143d5dSDavid Howells 
145431143d5dSDavid Howells 	if (attr->ia_valid & ATTR_SIZE)
145531143d5dSDavid Howells 		return afs_fs_setattr_size(server, key, vnode, attr,
145631143d5dSDavid Howells 					   wait_mode);
145731143d5dSDavid Howells 
145831143d5dSDavid Howells 	_enter(",%x,{%x:%u},,",
145931143d5dSDavid Howells 	       key_serial(key), vnode->fid.vid, vnode->fid.vnode);
146031143d5dSDavid Howells 
146131143d5dSDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
146231143d5dSDavid Howells 				   (4 + 6) * 4,
146331143d5dSDavid Howells 				   (21 + 6) * 4);
146431143d5dSDavid Howells 	if (!call)
146531143d5dSDavid Howells 		return -ENOMEM;
146631143d5dSDavid Howells 
146731143d5dSDavid Howells 	call->key = key;
146831143d5dSDavid Howells 	call->reply = vnode;
146931143d5dSDavid Howells 	call->service_id = FS_SERVICE;
147031143d5dSDavid Howells 	call->port = htons(AFS_FS_PORT);
147131143d5dSDavid Howells 	call->operation_ID = FSSTORESTATUS;
147231143d5dSDavid Howells 
147331143d5dSDavid Howells 	/* marshall the parameters */
147431143d5dSDavid Howells 	bp = call->request;
147531143d5dSDavid Howells 	*bp++ = htonl(FSSTORESTATUS);
147631143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vid);
147731143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
147831143d5dSDavid Howells 	*bp++ = htonl(vnode->fid.unique);
147931143d5dSDavid Howells 
148031143d5dSDavid Howells 	xdr_encode_AFS_StoreStatus(&bp, attr);
148131143d5dSDavid Howells 
148231143d5dSDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
148331143d5dSDavid Howells }
148445222b9eSDavid Howells 
148545222b9eSDavid Howells /*
148645222b9eSDavid Howells  * deliver reply data to an FS.GetVolumeStatus
148745222b9eSDavid Howells  */
148845222b9eSDavid Howells static int afs_deliver_fs_get_volume_status(struct afs_call *call,
148945222b9eSDavid Howells 					    struct sk_buff *skb, bool last)
149045222b9eSDavid Howells {
149145222b9eSDavid Howells 	const __be32 *bp;
149245222b9eSDavid Howells 	char *p;
149345222b9eSDavid Howells 	int ret;
149445222b9eSDavid Howells 
149545222b9eSDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
149645222b9eSDavid Howells 
149745222b9eSDavid Howells 	switch (call->unmarshall) {
149845222b9eSDavid Howells 	case 0:
149945222b9eSDavid Howells 		call->offset = 0;
150045222b9eSDavid Howells 		call->unmarshall++;
150145222b9eSDavid Howells 
150245222b9eSDavid Howells 		/* extract the returned status record */
150345222b9eSDavid Howells 	case 1:
150445222b9eSDavid Howells 		_debug("extract status");
150545222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, call->buffer,
150645222b9eSDavid Howells 				       12 * 4);
150745222b9eSDavid Howells 		switch (ret) {
150845222b9eSDavid Howells 		case 0:		break;
150945222b9eSDavid Howells 		case -EAGAIN:	return 0;
151045222b9eSDavid Howells 		default:	return ret;
151145222b9eSDavid Howells 		}
151245222b9eSDavid Howells 
151345222b9eSDavid Howells 		bp = call->buffer;
151445222b9eSDavid Howells 		xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
151545222b9eSDavid Howells 		call->offset = 0;
151645222b9eSDavid Howells 		call->unmarshall++;
151745222b9eSDavid Howells 
151845222b9eSDavid Howells 		/* extract the volume name length */
151945222b9eSDavid Howells 	case 2:
152045222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
152145222b9eSDavid Howells 		switch (ret) {
152245222b9eSDavid Howells 		case 0:		break;
152345222b9eSDavid Howells 		case -EAGAIN:	return 0;
152445222b9eSDavid Howells 		default:	return ret;
152545222b9eSDavid Howells 		}
152645222b9eSDavid Howells 
152745222b9eSDavid Howells 		call->count = ntohl(call->tmp);
152845222b9eSDavid Howells 		_debug("volname length: %u", call->count);
152945222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
153045222b9eSDavid Howells 			return -EBADMSG;
153145222b9eSDavid Howells 		call->offset = 0;
153245222b9eSDavid Howells 		call->unmarshall++;
153345222b9eSDavid Howells 
153445222b9eSDavid Howells 		/* extract the volume name */
153545222b9eSDavid Howells 	case 3:
153645222b9eSDavid Howells 		_debug("extract volname");
153745222b9eSDavid Howells 		if (call->count > 0) {
153845222b9eSDavid Howells 			ret = afs_extract_data(call, skb, last, call->reply3,
153945222b9eSDavid Howells 					       call->count);
154045222b9eSDavid Howells 			switch (ret) {
154145222b9eSDavid Howells 			case 0:		break;
154245222b9eSDavid Howells 			case -EAGAIN:	return 0;
154345222b9eSDavid Howells 			default:	return ret;
154445222b9eSDavid Howells 			}
154545222b9eSDavid Howells 		}
154645222b9eSDavid Howells 
154745222b9eSDavid Howells 		p = call->reply3;
154845222b9eSDavid Howells 		p[call->count] = 0;
154945222b9eSDavid Howells 		_debug("volname '%s'", p);
155045222b9eSDavid Howells 
155145222b9eSDavid Howells 		call->offset = 0;
155245222b9eSDavid Howells 		call->unmarshall++;
155345222b9eSDavid Howells 
155445222b9eSDavid Howells 		/* extract the volume name padding */
155545222b9eSDavid Howells 		if ((call->count & 3) == 0) {
155645222b9eSDavid Howells 			call->unmarshall++;
155745222b9eSDavid Howells 			goto no_volname_padding;
155845222b9eSDavid Howells 		}
155945222b9eSDavid Howells 		call->count = 4 - (call->count & 3);
156045222b9eSDavid Howells 
156145222b9eSDavid Howells 	case 4:
156245222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, call->buffer,
156345222b9eSDavid Howells 				       call->count);
156445222b9eSDavid Howells 		switch (ret) {
156545222b9eSDavid Howells 		case 0:		break;
156645222b9eSDavid Howells 		case -EAGAIN:	return 0;
156745222b9eSDavid Howells 		default:	return ret;
156845222b9eSDavid Howells 		}
156945222b9eSDavid Howells 
157045222b9eSDavid Howells 		call->offset = 0;
157145222b9eSDavid Howells 		call->unmarshall++;
157245222b9eSDavid Howells 	no_volname_padding:
157345222b9eSDavid Howells 
157445222b9eSDavid Howells 		/* extract the offline message length */
157545222b9eSDavid Howells 	case 5:
157645222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
157745222b9eSDavid Howells 		switch (ret) {
157845222b9eSDavid Howells 		case 0:		break;
157945222b9eSDavid Howells 		case -EAGAIN:	return 0;
158045222b9eSDavid Howells 		default:	return ret;
158145222b9eSDavid Howells 		}
158245222b9eSDavid Howells 
158345222b9eSDavid Howells 		call->count = ntohl(call->tmp);
158445222b9eSDavid Howells 		_debug("offline msg length: %u", call->count);
158545222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
158645222b9eSDavid Howells 			return -EBADMSG;
158745222b9eSDavid Howells 		call->offset = 0;
158845222b9eSDavid Howells 		call->unmarshall++;
158945222b9eSDavid Howells 
159045222b9eSDavid Howells 		/* extract the offline message */
159145222b9eSDavid Howells 	case 6:
159245222b9eSDavid Howells 		_debug("extract offline");
159345222b9eSDavid Howells 		if (call->count > 0) {
159445222b9eSDavid Howells 			ret = afs_extract_data(call, skb, last, call->reply3,
159545222b9eSDavid Howells 					       call->count);
159645222b9eSDavid Howells 			switch (ret) {
159745222b9eSDavid Howells 			case 0:		break;
159845222b9eSDavid Howells 			case -EAGAIN:	return 0;
159945222b9eSDavid Howells 			default:	return ret;
160045222b9eSDavid Howells 			}
160145222b9eSDavid Howells 		}
160245222b9eSDavid Howells 
160345222b9eSDavid Howells 		p = call->reply3;
160445222b9eSDavid Howells 		p[call->count] = 0;
160545222b9eSDavid Howells 		_debug("offline '%s'", p);
160645222b9eSDavid Howells 
160745222b9eSDavid Howells 		call->offset = 0;
160845222b9eSDavid Howells 		call->unmarshall++;
160945222b9eSDavid Howells 
161045222b9eSDavid Howells 		/* extract the offline message padding */
161145222b9eSDavid Howells 		if ((call->count & 3) == 0) {
161245222b9eSDavid Howells 			call->unmarshall++;
161345222b9eSDavid Howells 			goto no_offline_padding;
161445222b9eSDavid Howells 		}
161545222b9eSDavid Howells 		call->count = 4 - (call->count & 3);
161645222b9eSDavid Howells 
161745222b9eSDavid Howells 	case 7:
161845222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, call->buffer,
161945222b9eSDavid Howells 				       call->count);
162045222b9eSDavid Howells 		switch (ret) {
162145222b9eSDavid Howells 		case 0:		break;
162245222b9eSDavid Howells 		case -EAGAIN:	return 0;
162345222b9eSDavid Howells 		default:	return ret;
162445222b9eSDavid Howells 		}
162545222b9eSDavid Howells 
162645222b9eSDavid Howells 		call->offset = 0;
162745222b9eSDavid Howells 		call->unmarshall++;
162845222b9eSDavid Howells 	no_offline_padding:
162945222b9eSDavid Howells 
163045222b9eSDavid Howells 		/* extract the message of the day length */
163145222b9eSDavid Howells 	case 8:
163245222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, &call->tmp, 4);
163345222b9eSDavid Howells 		switch (ret) {
163445222b9eSDavid Howells 		case 0:		break;
163545222b9eSDavid Howells 		case -EAGAIN:	return 0;
163645222b9eSDavid Howells 		default:	return ret;
163745222b9eSDavid Howells 		}
163845222b9eSDavid Howells 
163945222b9eSDavid Howells 		call->count = ntohl(call->tmp);
164045222b9eSDavid Howells 		_debug("motd length: %u", call->count);
164145222b9eSDavid Howells 		if (call->count >= AFSNAMEMAX)
164245222b9eSDavid Howells 			return -EBADMSG;
164345222b9eSDavid Howells 		call->offset = 0;
164445222b9eSDavid Howells 		call->unmarshall++;
164545222b9eSDavid Howells 
164645222b9eSDavid Howells 		/* extract the message of the day */
164745222b9eSDavid Howells 	case 9:
164845222b9eSDavid Howells 		_debug("extract motd");
164945222b9eSDavid Howells 		if (call->count > 0) {
165045222b9eSDavid Howells 			ret = afs_extract_data(call, skb, last, call->reply3,
165145222b9eSDavid Howells 					       call->count);
165245222b9eSDavid Howells 			switch (ret) {
165345222b9eSDavid Howells 			case 0:		break;
165445222b9eSDavid Howells 			case -EAGAIN:	return 0;
165545222b9eSDavid Howells 			default:	return ret;
165645222b9eSDavid Howells 			}
165745222b9eSDavid Howells 		}
165845222b9eSDavid Howells 
165945222b9eSDavid Howells 		p = call->reply3;
166045222b9eSDavid Howells 		p[call->count] = 0;
166145222b9eSDavid Howells 		_debug("motd '%s'", p);
166245222b9eSDavid Howells 
166345222b9eSDavid Howells 		call->offset = 0;
166445222b9eSDavid Howells 		call->unmarshall++;
166545222b9eSDavid Howells 
166645222b9eSDavid Howells 		/* extract the message of the day padding */
166745222b9eSDavid Howells 		if ((call->count & 3) == 0) {
166845222b9eSDavid Howells 			call->unmarshall++;
166945222b9eSDavid Howells 			goto no_motd_padding;
167045222b9eSDavid Howells 		}
167145222b9eSDavid Howells 		call->count = 4 - (call->count & 3);
167245222b9eSDavid Howells 
167345222b9eSDavid Howells 	case 10:
167445222b9eSDavid Howells 		ret = afs_extract_data(call, skb, last, call->buffer,
167545222b9eSDavid Howells 				       call->count);
167645222b9eSDavid Howells 		switch (ret) {
167745222b9eSDavid Howells 		case 0:		break;
167845222b9eSDavid Howells 		case -EAGAIN:	return 0;
167945222b9eSDavid Howells 		default:	return ret;
168045222b9eSDavid Howells 		}
168145222b9eSDavid Howells 
168245222b9eSDavid Howells 		call->offset = 0;
168345222b9eSDavid Howells 		call->unmarshall++;
168445222b9eSDavid Howells 	no_motd_padding:
168545222b9eSDavid Howells 
168645222b9eSDavid Howells 	case 11:
168745222b9eSDavid Howells 		_debug("trailer %d", skb->len);
168845222b9eSDavid Howells 		if (skb->len != 0)
168945222b9eSDavid Howells 			return -EBADMSG;
169045222b9eSDavid Howells 		break;
169145222b9eSDavid Howells 	}
169245222b9eSDavid Howells 
169345222b9eSDavid Howells 	if (!last)
169445222b9eSDavid Howells 		return 0;
169545222b9eSDavid Howells 
169645222b9eSDavid Howells 	_leave(" = 0 [done]");
169745222b9eSDavid Howells 	return 0;
169845222b9eSDavid Howells }
169945222b9eSDavid Howells 
170045222b9eSDavid Howells /*
170145222b9eSDavid Howells  * destroy an FS.GetVolumeStatus call
170245222b9eSDavid Howells  */
170345222b9eSDavid Howells static void afs_get_volume_status_call_destructor(struct afs_call *call)
170445222b9eSDavid Howells {
170545222b9eSDavid Howells 	kfree(call->reply3);
170645222b9eSDavid Howells 	call->reply3 = NULL;
170745222b9eSDavid Howells 	afs_flat_call_destructor(call);
170845222b9eSDavid Howells }
170945222b9eSDavid Howells 
171045222b9eSDavid Howells /*
171145222b9eSDavid Howells  * FS.GetVolumeStatus operation type
171245222b9eSDavid Howells  */
171345222b9eSDavid Howells static const struct afs_call_type afs_RXFSGetVolumeStatus = {
171445222b9eSDavid Howells 	.name		= "FS.GetVolumeStatus",
171545222b9eSDavid Howells 	.deliver	= afs_deliver_fs_get_volume_status,
171645222b9eSDavid Howells 	.abort_to_error	= afs_abort_to_error,
171745222b9eSDavid Howells 	.destructor	= afs_get_volume_status_call_destructor,
171845222b9eSDavid Howells };
171945222b9eSDavid Howells 
172045222b9eSDavid Howells /*
172145222b9eSDavid Howells  * fetch the status of a volume
172245222b9eSDavid Howells  */
172345222b9eSDavid Howells int afs_fs_get_volume_status(struct afs_server *server,
172445222b9eSDavid Howells 			     struct key *key,
172545222b9eSDavid Howells 			     struct afs_vnode *vnode,
172645222b9eSDavid Howells 			     struct afs_volume_status *vs,
172745222b9eSDavid Howells 			     const struct afs_wait_mode *wait_mode)
172845222b9eSDavid Howells {
172945222b9eSDavid Howells 	struct afs_call *call;
173045222b9eSDavid Howells 	__be32 *bp;
173145222b9eSDavid Howells 	void *tmpbuf;
173245222b9eSDavid Howells 
173345222b9eSDavid Howells 	_enter("");
173445222b9eSDavid Howells 
173545222b9eSDavid Howells 	tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
173645222b9eSDavid Howells 	if (!tmpbuf)
173745222b9eSDavid Howells 		return -ENOMEM;
173845222b9eSDavid Howells 
173945222b9eSDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
174045222b9eSDavid Howells 	if (!call) {
174145222b9eSDavid Howells 		kfree(tmpbuf);
174245222b9eSDavid Howells 		return -ENOMEM;
174345222b9eSDavid Howells 	}
174445222b9eSDavid Howells 
174545222b9eSDavid Howells 	call->key = key;
174645222b9eSDavid Howells 	call->reply = vnode;
174745222b9eSDavid Howells 	call->reply2 = vs;
174845222b9eSDavid Howells 	call->reply3 = tmpbuf;
174945222b9eSDavid Howells 	call->service_id = FS_SERVICE;
175045222b9eSDavid Howells 	call->port = htons(AFS_FS_PORT);
175145222b9eSDavid Howells 
175245222b9eSDavid Howells 	/* marshall the parameters */
175345222b9eSDavid Howells 	bp = call->request;
175445222b9eSDavid Howells 	bp[0] = htonl(FSGETVOLUMESTATUS);
175545222b9eSDavid Howells 	bp[1] = htonl(vnode->fid.vid);
175645222b9eSDavid Howells 
175745222b9eSDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
175845222b9eSDavid Howells }
1759e8d6c554SDavid Howells 
1760e8d6c554SDavid Howells /*
1761e8d6c554SDavid Howells  * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
1762e8d6c554SDavid Howells  */
1763e8d6c554SDavid Howells static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
1764e8d6c554SDavid Howells 				    struct sk_buff *skb, bool last)
1765e8d6c554SDavid Howells {
1766e8d6c554SDavid Howells 	const __be32 *bp;
1767e8d6c554SDavid Howells 
1768e8d6c554SDavid Howells 	_enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
1769e8d6c554SDavid Howells 
1770e8d6c554SDavid Howells 	afs_transfer_reply(call, skb);
1771e8d6c554SDavid Howells 	if (!last)
1772e8d6c554SDavid Howells 		return 0;
1773e8d6c554SDavid Howells 
1774e8d6c554SDavid Howells 	if (call->reply_size != call->reply_max)
1775e8d6c554SDavid Howells 		return -EBADMSG;
1776e8d6c554SDavid Howells 
1777e8d6c554SDavid Howells 	/* unmarshall the reply once we've received all of it */
1778e8d6c554SDavid Howells 	bp = call->buffer;
1779e8d6c554SDavid Howells 	/* xdr_decode_AFSVolSync(&bp, call->replyX); */
1780e8d6c554SDavid Howells 
1781e8d6c554SDavid Howells 	_leave(" = 0 [done]");
1782e8d6c554SDavid Howells 	return 0;
1783e8d6c554SDavid Howells }
1784e8d6c554SDavid Howells 
1785e8d6c554SDavid Howells /*
1786e8d6c554SDavid Howells  * FS.SetLock operation type
1787e8d6c554SDavid Howells  */
1788e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSSetLock = {
1789e8d6c554SDavid Howells 	.name		= "FS.SetLock",
1790e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1791e8d6c554SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1792e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1793e8d6c554SDavid Howells };
1794e8d6c554SDavid Howells 
1795e8d6c554SDavid Howells /*
1796e8d6c554SDavid Howells  * FS.ExtendLock operation type
1797e8d6c554SDavid Howells  */
1798e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSExtendLock = {
1799e8d6c554SDavid Howells 	.name		= "FS.ExtendLock",
1800e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1801e8d6c554SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1802e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1803e8d6c554SDavid Howells };
1804e8d6c554SDavid Howells 
1805e8d6c554SDavid Howells /*
1806e8d6c554SDavid Howells  * FS.ReleaseLock operation type
1807e8d6c554SDavid Howells  */
1808e8d6c554SDavid Howells static const struct afs_call_type afs_RXFSReleaseLock = {
1809e8d6c554SDavid Howells 	.name		= "FS.ReleaseLock",
1810e8d6c554SDavid Howells 	.deliver	= afs_deliver_fs_xxxx_lock,
1811e8d6c554SDavid Howells 	.abort_to_error	= afs_abort_to_error,
1812e8d6c554SDavid Howells 	.destructor	= afs_flat_call_destructor,
1813e8d6c554SDavid Howells };
1814e8d6c554SDavid Howells 
1815e8d6c554SDavid Howells /*
1816e8d6c554SDavid Howells  * get a lock on a file
1817e8d6c554SDavid Howells  */
1818e8d6c554SDavid Howells int afs_fs_set_lock(struct afs_server *server,
1819e8d6c554SDavid Howells 		    struct key *key,
1820e8d6c554SDavid Howells 		    struct afs_vnode *vnode,
1821e8d6c554SDavid Howells 		    afs_lock_type_t type,
1822e8d6c554SDavid Howells 		    const struct afs_wait_mode *wait_mode)
1823e8d6c554SDavid Howells {
1824e8d6c554SDavid Howells 	struct afs_call *call;
1825e8d6c554SDavid Howells 	__be32 *bp;
1826e8d6c554SDavid Howells 
1827e8d6c554SDavid Howells 	_enter("");
1828e8d6c554SDavid Howells 
1829e8d6c554SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
1830e8d6c554SDavid Howells 	if (!call)
1831e8d6c554SDavid Howells 		return -ENOMEM;
1832e8d6c554SDavid Howells 
1833e8d6c554SDavid Howells 	call->key = key;
1834e8d6c554SDavid Howells 	call->reply = vnode;
1835e8d6c554SDavid Howells 	call->service_id = FS_SERVICE;
1836e8d6c554SDavid Howells 	call->port = htons(AFS_FS_PORT);
1837e8d6c554SDavid Howells 
1838e8d6c554SDavid Howells 	/* marshall the parameters */
1839e8d6c554SDavid Howells 	bp = call->request;
1840e8d6c554SDavid Howells 	*bp++ = htonl(FSSETLOCK);
1841e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1842e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1843e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1844e8d6c554SDavid Howells 	*bp++ = htonl(type);
1845e8d6c554SDavid Howells 
1846e8d6c554SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1847e8d6c554SDavid Howells }
1848e8d6c554SDavid Howells 
1849e8d6c554SDavid Howells /*
1850e8d6c554SDavid Howells  * extend a lock on a file
1851e8d6c554SDavid Howells  */
1852e8d6c554SDavid Howells int afs_fs_extend_lock(struct afs_server *server,
1853e8d6c554SDavid Howells 		       struct key *key,
1854e8d6c554SDavid Howells 		       struct afs_vnode *vnode,
1855e8d6c554SDavid Howells 		       const struct afs_wait_mode *wait_mode)
1856e8d6c554SDavid Howells {
1857e8d6c554SDavid Howells 	struct afs_call *call;
1858e8d6c554SDavid Howells 	__be32 *bp;
1859e8d6c554SDavid Howells 
1860e8d6c554SDavid Howells 	_enter("");
1861e8d6c554SDavid Howells 
1862e8d6c554SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
1863e8d6c554SDavid Howells 	if (!call)
1864e8d6c554SDavid Howells 		return -ENOMEM;
1865e8d6c554SDavid Howells 
1866e8d6c554SDavid Howells 	call->key = key;
1867e8d6c554SDavid Howells 	call->reply = vnode;
1868e8d6c554SDavid Howells 	call->service_id = FS_SERVICE;
1869e8d6c554SDavid Howells 	call->port = htons(AFS_FS_PORT);
1870e8d6c554SDavid Howells 
1871e8d6c554SDavid Howells 	/* marshall the parameters */
1872e8d6c554SDavid Howells 	bp = call->request;
1873e8d6c554SDavid Howells 	*bp++ = htonl(FSEXTENDLOCK);
1874e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1875e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1876e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1877e8d6c554SDavid Howells 
1878e8d6c554SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1879e8d6c554SDavid Howells }
1880e8d6c554SDavid Howells 
1881e8d6c554SDavid Howells /*
1882e8d6c554SDavid Howells  * release a lock on a file
1883e8d6c554SDavid Howells  */
1884e8d6c554SDavid Howells int afs_fs_release_lock(struct afs_server *server,
1885e8d6c554SDavid Howells 			struct key *key,
1886e8d6c554SDavid Howells 			struct afs_vnode *vnode,
1887e8d6c554SDavid Howells 			const struct afs_wait_mode *wait_mode)
1888e8d6c554SDavid Howells {
1889e8d6c554SDavid Howells 	struct afs_call *call;
1890e8d6c554SDavid Howells 	__be32 *bp;
1891e8d6c554SDavid Howells 
1892e8d6c554SDavid Howells 	_enter("");
1893e8d6c554SDavid Howells 
1894e8d6c554SDavid Howells 	call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
1895e8d6c554SDavid Howells 	if (!call)
1896e8d6c554SDavid Howells 		return -ENOMEM;
1897e8d6c554SDavid Howells 
1898e8d6c554SDavid Howells 	call->key = key;
1899e8d6c554SDavid Howells 	call->reply = vnode;
1900e8d6c554SDavid Howells 	call->service_id = FS_SERVICE;
1901e8d6c554SDavid Howells 	call->port = htons(AFS_FS_PORT);
1902e8d6c554SDavid Howells 
1903e8d6c554SDavid Howells 	/* marshall the parameters */
1904e8d6c554SDavid Howells 	bp = call->request;
1905e8d6c554SDavid Howells 	*bp++ = htonl(FSRELEASELOCK);
1906e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vid);
1907e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.vnode);
1908e8d6c554SDavid Howells 	*bp++ = htonl(vnode->fid.unique);
1909e8d6c554SDavid Howells 
1910e8d6c554SDavid Howells 	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
1911e8d6c554SDavid Howells }
1912