fsclient.c 54.0 KB
Newer Older
1
/* AFS File Server client stubs
L
Linus Torvalds 已提交
2
 *
3
 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/init.h>
13
#include <linux/slab.h>
L
Linus Torvalds 已提交
14
#include <linux/sched.h>
15
#include <linux/circ_buf.h>
J
Jeff Layton 已提交
16
#include <linux/iversion.h>
L
Linus Torvalds 已提交
17
#include "internal.h"
18
#include "afs_fs.h"
D
David Howells 已提交
19
#include "xdr_fs.h"
L
Linus Torvalds 已提交
20

21 22
static const struct afs_fid afs_zero_fid;

23 24 25 26 27 28
/*
 * We need somewhere to discard into in case the server helpfully returns more
 * than we asked for in FS.FetchData{,64}.
 */
static u8 afs_discard_buffer[64];

29
static inline void afs_use_fs_server(struct afs_call *call, struct afs_cb_interest *cbi)
30
{
31
	call->cbi = afs_get_cb_interest(cbi);
32 33
}

34 35 36 37 38 39 40 41 42 43 44 45 46
/*
 * decode an AFSFid block
 */
static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
{
	const __be32 *bp = *_bp;

	fid->vid		= ntohl(*bp++);
	fid->vnode		= ntohl(*bp++);
	fid->unique		= ntohl(*bp++);
	*_bp = bp;
}

D
David Howells 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
/*
 * Dump a bad file status record.
 */
static void xdr_dump_bad(const __be32 *bp)
{
	__be32 x[4];
	int i;

	pr_notice("AFS XDR: Bad status record\n");
	for (i = 0; i < 5 * 4 * 4; i += 16) {
		memcpy(x, bp, 16);
		bp += 4;
		pr_notice("%03x: %08x %08x %08x %08x\n",
			  i, ntohl(x[0]), ntohl(x[1]), ntohl(x[2]), ntohl(x[3]));
	}

	memcpy(x, bp, 4);
	pr_notice("0x50: %08x\n", ntohl(x[0]));
}

L
Linus Torvalds 已提交
67
/*
D
David Howells 已提交
68
 * Update the core inode struct from a returned status record.
L
Linus Torvalds 已提交
69
 */
D
David Howells 已提交
70 71 72 73
void afs_update_inode_from_status(struct afs_vnode *vnode,
				  struct afs_file_status *status,
				  const afs_dataversion_t *expected_version,
				  u8 flags)
L
Linus Torvalds 已提交
74
{
D
David Howells 已提交
75
	struct timespec t;
76
	umode_t mode;
D
David Howells 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

	t.tv_sec = status->mtime_client;
	t.tv_nsec = 0;
	vnode->vfs_inode.i_ctime = t;
	vnode->vfs_inode.i_mtime = t;
	vnode->vfs_inode.i_atime = t;

	if (flags & (AFS_VNODE_META_CHANGED | AFS_VNODE_NOT_YET_SET)) {
		vnode->vfs_inode.i_uid = make_kuid(&init_user_ns, status->owner);
		vnode->vfs_inode.i_gid = make_kgid(&init_user_ns, status->group);
		set_nlink(&vnode->vfs_inode, status->nlink);

		mode = vnode->vfs_inode.i_mode;
		mode &= ~S_IALLUGO;
		mode |= status->mode;
		barrier();
		vnode->vfs_inode.i_mode = mode;
	}

	if (!(flags & AFS_VNODE_NOT_YET_SET)) {
		if (expected_version &&
		    *expected_version != status->data_version) {
			_debug("vnode modified %llx on {%x:%u} [exp %llx]",
			       (unsigned long long) status->data_version,
			       vnode->fid.vid, vnode->fid.vnode,
			       (unsigned long long) *expected_version);
			set_bit(AFS_VNODE_DIR_MODIFIED, &vnode->flags);
			set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
		}
	}

	if (flags & (AFS_VNODE_DATA_CHANGED | AFS_VNODE_NOT_YET_SET)) {
		inode_set_iversion_raw(&vnode->vfs_inode, status->data_version);
		i_size_write(&vnode->vfs_inode, status->size);
	}
}

/*
 * decode an AFSFetchStatus block
 */
static int xdr_decode_AFSFetchStatus(const __be32 **_bp,
				     struct afs_file_status *status,
				     struct afs_vnode *vnode,
				     const afs_dataversion_t *expected_version,
				     afs_dataversion_t *_version)
{
	const struct afs_xdr_AFSFetchStatus *xdr = (const void *)*_bp;
124
	u64 data_version, size;
D
David Howells 已提交
125 126 127
	u32 type, abort_code;
	u8 flags = 0;
	int ret;
128

129 130
	if (vnode)
		write_seqlock(&vnode->cb_lock);
131

D
David Howells 已提交
132 133 134 135
	if (xdr->if_version != htonl(AFS_FSTATUS_VERSION)) {
		pr_warn("Unknown AFSFetchStatus version %u\n", ntohl(xdr->if_version));
		goto bad;
	}
136

D
David Howells 已提交
137 138 139
	type = ntohl(xdr->type);
	abort_code = ntohl(xdr->abort_code);
	switch (type) {
D
David Howells 已提交
140 141 142
	case AFS_FTYPE_FILE:
	case AFS_FTYPE_DIR:
	case AFS_FTYPE_SYMLINK:
D
David Howells 已提交
143 144 145 146 147 148 149 150 151 152 153
		if (type != status->type &&
		    vnode &&
		    !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
			pr_warning("Vnode %x:%x:%x changed type %u to %u\n",
				   vnode->fid.vid,
				   vnode->fid.vnode,
				   vnode->fid.unique,
				   status->type, type);
			goto bad;
		}
		status->type = type;
D
David Howells 已提交
154 155
		break;
	case AFS_FTYPE_INVALID:
D
David Howells 已提交
156 157
		if (abort_code != 0) {
			status->abort_code = abort_code;
D
David Howells 已提交
158
			goto out;
D
David Howells 已提交
159
		}
D
David Howells 已提交
160 161
		/* Fall through */
	default:
D
David Howells 已提交
162
		goto bad;
D
David Howells 已提交
163 164
	}

D
David Howells 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
#define EXTRACT_M(FIELD)					\
	do {							\
		u32 x = ntohl(xdr->FIELD);			\
		if (status->FIELD != x) {			\
			flags |= AFS_VNODE_META_CHANGED;	\
			status->FIELD = x;			\
		}						\
	} while (0)

	EXTRACT_M(nlink);
	EXTRACT_M(author);
	EXTRACT_M(owner);
	EXTRACT_M(caller_access); /* call ticket dependent */
	EXTRACT_M(anon_access);
	EXTRACT_M(mode);
	EXTRACT_M(group);

	status->mtime_client = ntohl(xdr->mtime_client);
	status->mtime_server = ntohl(xdr->mtime_server);
	status->lock_count   = ntohl(xdr->lock_count);

	size  = (u64)ntohl(xdr->size_lo);
	size |= (u64)ntohl(xdr->size_hi) << 32;
188 189
	if (size != status->size) {
		status->size = size;
D
David Howells 已提交
190 191 192 193 194 195 196 197
		flags |= AFS_VNODE_DATA_CHANGED;
	}

	data_version  = (u64)ntohl(xdr->data_version_lo);
	data_version |= (u64)ntohl(xdr->data_version_hi) << 32;
	if (data_version != status->data_version) {
		status->data_version = data_version;
		flags |= AFS_VNODE_DATA_CHANGED;
198
	}
199 200
	if (_version)
		*_version = data_version;
201

D
David Howells 已提交
202
	*_bp = (const void *)*_bp + sizeof(*xdr);
203 204

	if (vnode) {
D
David Howells 已提交
205 206 207 208
		if (test_bit(AFS_VNODE_UNSET, &vnode->flags))
			flags |= AFS_VNODE_NOT_YET_SET;
		afs_update_inode_from_status(vnode, status, expected_version,
					     flags);
209 210
	}

D
David Howells 已提交
211
	ret = 0;
212

D
David Howells 已提交
213
out:
214 215
	if (vnode)
		write_sequnlock(&vnode->cb_lock);
D
David Howells 已提交
216 217 218 219 220 221
	return ret;

bad:
	xdr_dump_bad(*_bp);
	ret = -EBADMSG;
	goto out;
D
David Howells 已提交
222
}
L
Linus Torvalds 已提交
223 224

/*
225
 * decode an AFSCallBack block
L
Linus Torvalds 已提交
226
 */
227 228 229
static void xdr_decode_AFSCallBack(struct afs_call *call,
				   struct afs_vnode *vnode,
				   const __be32 **_bp)
L
Linus Torvalds 已提交
230
{
231
	struct afs_cb_interest *old, *cbi = call->cbi;
232
	const __be32 *bp = *_bp;
233 234 235 236
	u32 cb_expiry;

	write_seqlock(&vnode->cb_lock);

237
	if (call->cb_break == (vnode->cb_break + cbi->server->cb_s_break)) {
238 239 240 241
		vnode->cb_version	= ntohl(*bp++);
		cb_expiry		= ntohl(*bp++);
		vnode->cb_type		= ntohl(*bp++);
		vnode->cb_expires_at	= cb_expiry + ktime_get_real_seconds();
242 243 244 245 246
		old = vnode->cb_interest;
		if (old != call->cbi) {
			vnode->cb_interest = cbi;
			cbi = old;
		}
247 248 249 250
		set_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
	} else {
		bp += 3;
	}
L
Linus Torvalds 已提交
251

252
	write_sequnlock(&vnode->cb_lock);
253
	call->cbi = cbi;
254
	*_bp = bp;
D
David Howells 已提交
255
}
L
Linus Torvalds 已提交
256

257 258 259 260 261 262 263 264 265 266 267
static void xdr_decode_AFSCallBack_raw(const __be32 **_bp,
				       struct afs_callback *cb)
{
	const __be32 *bp = *_bp;

	cb->version	= ntohl(*bp++);
	cb->expiry	= ntohl(*bp++);
	cb->type	= ntohl(*bp++);
	*_bp = bp;
}

L
Linus Torvalds 已提交
268
/*
269
 * decode an AFSVolSync block
L
Linus Torvalds 已提交
270
 */
271 272
static void xdr_decode_AFSVolSync(const __be32 **_bp,
				  struct afs_volsync *volsync)
L
Linus Torvalds 已提交
273
{
274
	const __be32 *bp = *_bp;
L
Linus Torvalds 已提交
275

276 277 278 279 280 281 282 283
	volsync->creation = ntohl(*bp++);
	bp++; /* spare2 */
	bp++; /* spare3 */
	bp++; /* spare4 */
	bp++; /* spare5 */
	bp++; /* spare6 */
	*_bp = bp;
}
L
Linus Torvalds 已提交
284

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
/*
 * encode the requested attributes into an AFSStoreStatus block
 */
static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
{
	__be32 *bp = *_bp;
	u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;

	mask = 0;
	if (attr->ia_valid & ATTR_MTIME) {
		mask |= AFS_SET_MTIME;
		mtime = attr->ia_mtime.tv_sec;
	}

	if (attr->ia_valid & ATTR_UID) {
		mask |= AFS_SET_OWNER;
301
		owner = from_kuid(&init_user_ns, attr->ia_uid);
302 303 304 305
	}

	if (attr->ia_valid & ATTR_GID) {
		mask |= AFS_SET_GROUP;
306
		group = from_kgid(&init_user_ns, attr->ia_gid);
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
	}

	if (attr->ia_valid & ATTR_MODE) {
		mask |= AFS_SET_MODE;
		mode = attr->ia_mode & S_IALLUGO;
	}

	*bp++ = htonl(mask);
	*bp++ = htonl(mtime);
	*bp++ = htonl(owner);
	*bp++ = htonl(group);
	*bp++ = htonl(mode);
	*bp++ = 0;		/* segment size */
	*_bp = bp;
}

D
David Howells 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
/*
 * decode an AFSFetchVolumeStatus block
 */
static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
					    struct afs_volume_status *vs)
{
	const __be32 *bp = *_bp;

	vs->vid			= ntohl(*bp++);
	vs->parent_id		= ntohl(*bp++);
	vs->online		= ntohl(*bp++);
	vs->in_service		= ntohl(*bp++);
	vs->blessed		= ntohl(*bp++);
	vs->needs_salvage	= ntohl(*bp++);
	vs->type		= ntohl(*bp++);
	vs->min_quota		= ntohl(*bp++);
	vs->max_quota		= ntohl(*bp++);
	vs->blocks_in_use	= ntohl(*bp++);
	vs->part_blocks_avail	= ntohl(*bp++);
	vs->part_max_blocks	= ntohl(*bp++);
	*_bp = bp;
}

346 347 348
/*
 * deliver reply data to an FS.FetchStatus
 */
349
static int afs_deliver_fs_fetch_status_vnode(struct afs_call *call)
350
{
351
	struct afs_vnode *vnode = call->reply[0];
352
	const __be32 *bp;
353
	int ret;
L
Linus Torvalds 已提交
354

355
	ret = afs_transfer_reply(call);
356 357
	if (ret < 0)
		return ret;
L
Linus Torvalds 已提交
358

359 360
	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);

361 362
	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
363 364 365
	if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
366
	xdr_decode_AFSCallBack(call, vnode, &bp);
367 368
	if (call->reply[1])
		xdr_decode_AFSVolSync(&bp, call->reply[1]);
L
Linus Torvalds 已提交
369

370 371
	_leave(" = 0 [done]");
	return 0;
D
David Howells 已提交
372
}
373 374 375 376

/*
 * FS.FetchStatus operation type
 */
377 378
static const struct afs_call_type afs_RXFSFetchStatus_vnode = {
	.name		= "FS.FetchStatus(vnode)",
379
	.op		= afs_FS_FetchStatus,
380
	.deliver	= afs_deliver_fs_fetch_status_vnode,
381 382
	.destructor	= afs_flat_call_destructor,
};
L
Linus Torvalds 已提交
383 384 385 386

/*
 * fetch the status information for a file
 */
387 388
int afs_fs_fetch_file_status(struct afs_fs_cursor *fc, struct afs_volsync *volsync,
			     bool new_inode)
L
Linus Torvalds 已提交
389
{
390
	struct afs_vnode *vnode = fc->vnode;
391
	struct afs_call *call;
392
	struct afs_net *net = afs_v2net(vnode);
L
Linus Torvalds 已提交
393 394
	__be32 *bp;

D
David Howells 已提交
395
	_enter(",%x,{%x:%u},,",
396
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
L
Linus Torvalds 已提交
397

398 399
	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus_vnode,
				   16, (21 + 3 + 6) * 4);
400 401
	if (!call) {
		fc->ac.error = -ENOMEM;
402
		return -ENOMEM;
403
	}
L
Linus Torvalds 已提交
404

405
	call->key = fc->key;
406 407
	call->reply[0] = vnode;
	call->reply[1] = volsync;
408
	call->expected_version = new_inode ? 1 : vnode->status.data_version;
L
Linus Torvalds 已提交
409 410

	/* marshall the parameters */
411
	bp = call->request;
L
Linus Torvalds 已提交
412 413 414 415 416
	bp[0] = htonl(FSFETCHSTATUS);
	bp[1] = htonl(vnode->fid.vid);
	bp[2] = htonl(vnode->fid.vnode);
	bp[3] = htonl(vnode->fid.unique);

417 418
	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
419
	trace_afs_make_fs_call(call, &vnode->fid);
420
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
421
}
L
Linus Torvalds 已提交
422 423

/*
424
 * deliver reply data to an FS.FetchData
L
Linus Torvalds 已提交
425
 */
426
static int afs_deliver_fs_fetch_data(struct afs_call *call)
L
Linus Torvalds 已提交
427
{
428 429
	struct afs_vnode *vnode = call->reply[0];
	struct afs_read *req = call->reply[2];
430
	const __be32 *bp;
431
	unsigned int size;
432
	void *buffer;
L
Linus Torvalds 已提交
433 434
	int ret;

435
	_enter("{%u,%zu/%u;%llu/%llu}",
436 437
	       call->unmarshall, call->offset, call->count,
	       req->remain, req->actual_len);
438 439 440

	switch (call->unmarshall) {
	case 0:
441
		req->actual_len = 0;
442 443
		call->offset = 0;
		call->unmarshall++;
D
David Howells 已提交
444 445 446 447
		if (call->operation_ID != FSFETCHDATA64) {
			call->unmarshall++;
			goto no_msw;
		}
448

D
David Howells 已提交
449 450 451
		/* extract the upper part of the returned data length of an
		 * FSFETCHDATA64 op (which should always be 0 using this
		 * client) */
452
	case 1:
D
David Howells 已提交
453
		_debug("extract data length (MSW)");
454
		ret = afs_extract_data(call, &call->tmp, 4, true);
455 456
		if (ret < 0)
			return ret;
D
David Howells 已提交
457

458 459
		req->actual_len = ntohl(call->tmp);
		req->actual_len <<= 32;
D
David Howells 已提交
460 461 462 463 464 465
		call->offset = 0;
		call->unmarshall++;

	no_msw:
		/* extract the returned data length */
	case 2:
466
		_debug("extract data length");
467
		ret = afs_extract_data(call, &call->tmp, 4, true);
468 469
		if (ret < 0)
			return ret;
L
Linus Torvalds 已提交
470

471 472 473 474 475 476 477 478
		req->actual_len |= ntohl(call->tmp);
		_debug("DATA length: %llu", req->actual_len);

		req->remain = req->actual_len;
		call->offset = req->pos & (PAGE_SIZE - 1);
		req->index = 0;
		if (req->actual_len == 0)
			goto no_more_data;
479 480
		call->unmarshall++;

481
	begin_page:
482
		ASSERTCMP(req->index, <, req->nr_pages);
483 484 485 486 487 488 489 490
		if (req->remain > PAGE_SIZE - call->offset)
			size = PAGE_SIZE - call->offset;
		else
			size = req->remain;
		call->count = call->offset + size;
		ASSERTCMP(call->count, <=, PAGE_SIZE);
		req->remain -= size;

491
		/* extract the returned data */
D
David Howells 已提交
492
	case 3:
493
		_debug("extract data %llu/%llu %zu/%u",
494 495 496 497 498 499 500 501 502 503
		       req->remain, req->actual_len, call->offset, call->count);

		buffer = kmap(req->pages[req->index]);
		ret = afs_extract_data(call, buffer, call->count, true);
		kunmap(req->pages[req->index]);
		if (ret < 0)
			return ret;
		if (call->offset == PAGE_SIZE) {
			if (req->page_done)
				req->page_done(call, req);
D
David Howells 已提交
504
			req->index++;
505 506
			if (req->remain > 0) {
				call->offset = 0;
507 508
				if (req->index >= req->nr_pages) {
					call->unmarshall = 4;
509
					goto begin_discard;
510
				}
511 512
				goto begin_page;
			}
513
		}
514 515 516 517 518
		goto no_more_data;

		/* Discard any excess data the server gave us */
	begin_discard:
	case 4:
519
		size = min_t(loff_t, sizeof(afs_discard_buffer), req->remain);
520
		call->count = size;
521
		_debug("extract discard %llu/%llu %zu/%u",
522 523 524 525 526 527 528 529 530
		       req->remain, req->actual_len, call->offset, call->count);

		call->offset = 0;
		ret = afs_extract_data(call, afs_discard_buffer, call->count, true);
		req->remain -= call->offset;
		if (ret < 0)
			return ret;
		if (req->remain > 0)
			goto begin_discard;
L
Linus Torvalds 已提交
531

532
	no_more_data:
533
		call->offset = 0;
534
		call->unmarshall = 5;
L
Linus Torvalds 已提交
535

536
		/* extract the metadata */
537
	case 5:
538 539
		ret = afs_extract_data(call, call->buffer,
				       (21 + 3 + 6) * 4, false);
540 541
		if (ret < 0)
			return ret;
542 543

		bp = call->buffer;
D
David Howells 已提交
544 545 546 547
		if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
					      &vnode->status.data_version,
					      &req->new_version) < 0)
			return -EBADMSG;
548
		xdr_decode_AFSCallBack(call, vnode, &bp);
549 550
		if (call->reply[1])
			xdr_decode_AFSVolSync(&bp, call->reply[1]);
551 552 553

		call->offset = 0;
		call->unmarshall++;
L
Linus Torvalds 已提交
554

555
	case 6:
556
		break;
L
Linus Torvalds 已提交
557 558
	}

559 560 561 562
	for (; req->index < req->nr_pages; req->index++) {
		if (call->count < PAGE_SIZE)
			zero_user_segment(req->pages[req->index],
					  call->count, PAGE_SIZE);
563 564
		if (req->page_done)
			req->page_done(call, req);
565
		call->count = 0;
D
David Howells 已提交
566 567
	}

568 569
	_leave(" = 0 [done]");
	return 0;
D
David Howells 已提交
570
}
L
Linus Torvalds 已提交
571

572 573
static void afs_fetch_data_destructor(struct afs_call *call)
{
574
	struct afs_read *req = call->reply[2];
575 576 577 578 579

	afs_put_read(req);
	afs_flat_call_destructor(call);
}

L
Linus Torvalds 已提交
580
/*
581
 * FS.FetchData operation type
L
Linus Torvalds 已提交
582
 */
583
static const struct afs_call_type afs_RXFSFetchData = {
D
David Howells 已提交
584
	.name		= "FS.FetchData",
585
	.op		= afs_FS_FetchData,
586
	.deliver	= afs_deliver_fs_fetch_data,
587
	.destructor	= afs_fetch_data_destructor,
588 589
};

D
David Howells 已提交
590 591
static const struct afs_call_type afs_RXFSFetchData64 = {
	.name		= "FS.FetchData64",
592
	.op		= afs_FS_FetchData64,
D
David Howells 已提交
593
	.deliver	= afs_deliver_fs_fetch_data,
594
	.destructor	= afs_fetch_data_destructor,
D
David Howells 已提交
595 596 597 598 599
};

/*
 * fetch data from a very large file
 */
600
static int afs_fs_fetch_data64(struct afs_fs_cursor *fc, struct afs_read *req)
D
David Howells 已提交
601
{
602
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
603
	struct afs_call *call;
604
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
605 606 607 608
	__be32 *bp;

	_enter("");

609
	call = afs_alloc_flat_call(net, &afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
D
David Howells 已提交
610 611 612
	if (!call)
		return -ENOMEM;

613
	call->key = fc->key;
614 615 616
	call->reply[0] = vnode;
	call->reply[1] = NULL; /* volsync */
	call->reply[2] = req;
617
	call->expected_version = vnode->status.data_version;
D
David Howells 已提交
618 619 620 621 622 623 624

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSFETCHDATA64);
	bp[1] = htonl(vnode->fid.vid);
	bp[2] = htonl(vnode->fid.vnode);
	bp[3] = htonl(vnode->fid.unique);
625 626
	bp[4] = htonl(upper_32_bits(req->pos));
	bp[5] = htonl(lower_32_bits(req->pos));
D
David Howells 已提交
627
	bp[6] = 0;
628
	bp[7] = htonl(lower_32_bits(req->len));
D
David Howells 已提交
629

630
	atomic_inc(&req->usage);
631 632
	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
633
	trace_afs_make_fs_call(call, &vnode->fid);
634
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
635 636
}

637 638 639
/*
 * fetch data from a file
 */
640
int afs_fs_fetch_data(struct afs_fs_cursor *fc, struct afs_read *req)
L
Linus Torvalds 已提交
641
{
642
	struct afs_vnode *vnode = fc->vnode;
643
	struct afs_call *call;
644
	struct afs_net *net = afs_v2net(vnode);
L
Linus Torvalds 已提交
645 646
	__be32 *bp;

647 648 649
	if (upper_32_bits(req->pos) ||
	    upper_32_bits(req->len) ||
	    upper_32_bits(req->pos + req->len))
650
		return afs_fs_fetch_data64(fc, req);
D
David Howells 已提交
651

652
	_enter("");
L
Linus Torvalds 已提交
653

654
	call = afs_alloc_flat_call(net, &afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
655 656
	if (!call)
		return -ENOMEM;
L
Linus Torvalds 已提交
657

658
	call->key = fc->key;
659 660 661
	call->reply[0] = vnode;
	call->reply[1] = NULL; /* volsync */
	call->reply[2] = req;
662
	call->expected_version = vnode->status.data_version;
L
Linus Torvalds 已提交
663 664

	/* marshall the parameters */
665 666 667 668 669
	bp = call->request;
	bp[0] = htonl(FSFETCHDATA);
	bp[1] = htonl(vnode->fid.vid);
	bp[2] = htonl(vnode->fid.vnode);
	bp[3] = htonl(vnode->fid.unique);
670 671
	bp[4] = htonl(lower_32_bits(req->pos));
	bp[5] = htonl(lower_32_bits(req->len));
L
Linus Torvalds 已提交
672

673
	atomic_inc(&req->usage);
674 675
	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
676
	trace_afs_make_fs_call(call, &vnode->fid);
677
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
678
}
679 680 681 682

/*
 * deliver reply data to an FS.CreateFile or an FS.MakeDir
 */
683
static int afs_deliver_fs_create_vnode(struct afs_call *call)
684
{
685
	struct afs_vnode *vnode = call->reply[0];
686
	const __be32 *bp;
687
	int ret;
688

689
	_enter("{%u}", call->unmarshall);
690

691
	ret = afs_transfer_reply(call);
692 693
	if (ret < 0)
		return ret;
694 695 696

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
697
	xdr_decode_AFSFid(&bp, call->reply[1]);
D
David Howells 已提交
698 699 700 701
	if (xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL, NULL) < 0 ||
	    xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
702 703
	xdr_decode_AFSCallBack_raw(&bp, call->reply[3]);
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
704 705 706 707 708 709 710 711

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.CreateFile and FS.MakeDir operation type
 */
712 713 714 715 716 717 718 719 720 721
static const struct afs_call_type afs_RXFSCreateFile = {
	.name		= "FS.CreateFile",
	.op		= afs_FS_CreateFile,
	.deliver	= afs_deliver_fs_create_vnode,
	.destructor	= afs_flat_call_destructor,
};

static const struct afs_call_type afs_RXFSMakeDir = {
	.name		= "FS.MakeDir",
	.op		= afs_FS_MakeDir,
722 723 724 725 726 727 728
	.deliver	= afs_deliver_fs_create_vnode,
	.destructor	= afs_flat_call_destructor,
};

/*
 * create a file or make a directory
 */
D
David Howells 已提交
729
int afs_fs_create(struct afs_fs_cursor *fc,
730 731 732 733
		  const char *name,
		  umode_t mode,
		  struct afs_fid *newfid,
		  struct afs_file_status *newstatus,
734
		  struct afs_callback *newcb)
735
{
736
	struct afs_vnode *vnode = fc->vnode;
737
	struct afs_call *call;
738
	struct afs_net *net = afs_v2net(vnode);
739 740 741 742 743 744 745 746 747
	size_t namesz, reqsz, padsz;
	__be32 *bp;

	_enter("");

	namesz = strlen(name);
	padsz = (4 - (namesz & 3)) & 3;
	reqsz = (5 * 4) + namesz + padsz + (6 * 4);

748 749 750
	call = afs_alloc_flat_call(
		net, S_ISDIR(mode) ? &afs_RXFSMakeDir : &afs_RXFSCreateFile,
		reqsz, (3 + 21 + 21 + 3 + 6) * 4);
751 752 753
	if (!call)
		return -ENOMEM;

754
	call->key = fc->key;
755 756 757 758
	call->reply[0] = vnode;
	call->reply[1] = newfid;
	call->reply[2] = newstatus;
	call->reply[3] = newcb;
759
	call->expected_version = vnode->status.data_version;
760 761 762 763 764 765 766 767 768 769 770 771 772 773

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(S_ISDIR(mode) ? FSMAKEDIR : FSCREATEFILE);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);
	*bp++ = htonl(namesz);
	memcpy(bp, name, namesz);
	bp = (void *) bp + namesz;
	if (padsz > 0) {
		memset(bp, 0, padsz);
		bp = (void *) bp + padsz;
	}
774 775
	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
776 777 778 779 780
	*bp++ = 0; /* owner */
	*bp++ = 0; /* group */
	*bp++ = htonl(mode & S_IALLUGO); /* unix mode */
	*bp++ = 0; /* segment size */

781
	afs_use_fs_server(call, fc->cbi);
782
	trace_afs_make_fs_call(call, &vnode->fid);
783
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
784 785 786 787 788
}

/*
 * deliver reply data to an FS.RemoveFile or FS.RemoveDir
 */
789
static int afs_deliver_fs_remove(struct afs_call *call)
790
{
791
	struct afs_vnode *vnode = call->reply[0];
792
	const __be32 *bp;
793
	int ret;
794

795
	_enter("{%u}", call->unmarshall);
796

797
	ret = afs_transfer_reply(call);
798 799
	if (ret < 0)
		return ret;
800 801 802

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
803 804 805
	if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
806
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
807 808 809 810 811 812 813 814

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.RemoveDir/FS.RemoveFile operation type
 */
815 816 817 818 819 820 821 822 823 824
static const struct afs_call_type afs_RXFSRemoveFile = {
	.name		= "FS.RemoveFile",
	.op		= afs_FS_RemoveFile,
	.deliver	= afs_deliver_fs_remove,
	.destructor	= afs_flat_call_destructor,
};

static const struct afs_call_type afs_RXFSRemoveDir = {
	.name		= "FS.RemoveDir",
	.op		= afs_FS_RemoveDir,
825 826 827 828 829 830 831
	.deliver	= afs_deliver_fs_remove,
	.destructor	= afs_flat_call_destructor,
};

/*
 * remove a file or directory
 */
832
int afs_fs_remove(struct afs_fs_cursor *fc, const char *name, bool isdir)
833
{
834
	struct afs_vnode *vnode = fc->vnode;
835
	struct afs_call *call;
836
	struct afs_net *net = afs_v2net(vnode);
837 838 839 840 841 842 843 844 845
	size_t namesz, reqsz, padsz;
	__be32 *bp;

	_enter("");

	namesz = strlen(name);
	padsz = (4 - (namesz & 3)) & 3;
	reqsz = (5 * 4) + namesz + padsz;

846 847 848
	call = afs_alloc_flat_call(
		net, isdir ? &afs_RXFSRemoveDir : &afs_RXFSRemoveFile,
		reqsz, (21 + 6) * 4);
849 850 851
	if (!call)
		return -ENOMEM;

852
	call->key = fc->key;
853
	call->reply[0] = vnode;
854
	call->expected_version = vnode->status.data_version;
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(isdir ? FSREMOVEDIR : FSREMOVEFILE);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);
	*bp++ = htonl(namesz);
	memcpy(bp, name, namesz);
	bp = (void *) bp + namesz;
	if (padsz > 0) {
		memset(bp, 0, padsz);
		bp = (void *) bp + padsz;
	}

870
	afs_use_fs_server(call, fc->cbi);
871
	trace_afs_make_fs_call(call, &vnode->fid);
872
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
873 874 875 876 877
}

/*
 * deliver reply data to an FS.Link
 */
878
static int afs_deliver_fs_link(struct afs_call *call)
879
{
880
	struct afs_vnode *dvnode = call->reply[0], *vnode = call->reply[1];
881
	const __be32 *bp;
882
	int ret;
883

884
	_enter("{%u}", call->unmarshall);
885

886
	ret = afs_transfer_reply(call);
887 888
	if (ret < 0)
		return ret;
889 890 891

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
892 893 894 895
	if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL, NULL) < 0 ||
	    xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
896
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
897 898 899 900 901 902 903 904 905 906

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.Link operation type
 */
static const struct afs_call_type afs_RXFSLink = {
	.name		= "FS.Link",
907
	.op		= afs_FS_Link,
908 909 910 911 912 913 914
	.deliver	= afs_deliver_fs_link,
	.destructor	= afs_flat_call_destructor,
};

/*
 * make a hard link
 */
915 916
int afs_fs_link(struct afs_fs_cursor *fc, struct afs_vnode *vnode,
		const char *name)
917
{
918
	struct afs_vnode *dvnode = fc->vnode;
919
	struct afs_call *call;
920
	struct afs_net *net = afs_v2net(vnode);
921 922 923 924 925 926 927 928 929
	size_t namesz, reqsz, padsz;
	__be32 *bp;

	_enter("");

	namesz = strlen(name);
	padsz = (4 - (namesz & 3)) & 3;
	reqsz = (5 * 4) + namesz + padsz + (3 * 4);

930
	call = afs_alloc_flat_call(net, &afs_RXFSLink, reqsz, (21 + 21 + 6) * 4);
931 932 933
	if (!call)
		return -ENOMEM;

934
	call->key = fc->key;
935 936
	call->reply[0] = dvnode;
	call->reply[1] = vnode;
937
	call->expected_version = vnode->status.data_version;
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSLINK);
	*bp++ = htonl(dvnode->fid.vid);
	*bp++ = htonl(dvnode->fid.vnode);
	*bp++ = htonl(dvnode->fid.unique);
	*bp++ = htonl(namesz);
	memcpy(bp, name, namesz);
	bp = (void *) bp + namesz;
	if (padsz > 0) {
		memset(bp, 0, padsz);
		bp = (void *) bp + padsz;
	}
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

956
	afs_use_fs_server(call, fc->cbi);
957
	trace_afs_make_fs_call(call, &vnode->fid);
958
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
959 960 961 962 963
}

/*
 * deliver reply data to an FS.Symlink
 */
964
static int afs_deliver_fs_symlink(struct afs_call *call)
965
{
966
	struct afs_vnode *vnode = call->reply[0];
967
	const __be32 *bp;
968
	int ret;
969

970
	_enter("{%u}", call->unmarshall);
971

972
	ret = afs_transfer_reply(call);
973 974
	if (ret < 0)
		return ret;
975 976 977

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
978
	xdr_decode_AFSFid(&bp, call->reply[1]);
D
David Howells 已提交
979 980 981 982
	if (xdr_decode_AFSFetchStatus(&bp, call->reply[2], NULL, NULL, NULL) ||
	    xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
983
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
984 985 986 987 988 989 990 991 992 993

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.Symlink operation type
 */
static const struct afs_call_type afs_RXFSSymlink = {
	.name		= "FS.Symlink",
994
	.op		= afs_FS_Symlink,
995 996 997 998 999 1000 1001
	.deliver	= afs_deliver_fs_symlink,
	.destructor	= afs_flat_call_destructor,
};

/*
 * create a symbolic link
 */
D
David Howells 已提交
1002
int afs_fs_symlink(struct afs_fs_cursor *fc,
1003 1004 1005
		   const char *name,
		   const char *contents,
		   struct afs_fid *newfid,
1006
		   struct afs_file_status *newstatus)
1007
{
1008
	struct afs_vnode *vnode = fc->vnode;
1009
	struct afs_call *call;
1010
	struct afs_net *net = afs_v2net(vnode);
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
	size_t namesz, reqsz, padsz, c_namesz, c_padsz;
	__be32 *bp;

	_enter("");

	namesz = strlen(name);
	padsz = (4 - (namesz & 3)) & 3;

	c_namesz = strlen(contents);
	c_padsz = (4 - (c_namesz & 3)) & 3;

	reqsz = (6 * 4) + namesz + padsz + c_namesz + c_padsz + (6 * 4);

1024
	call = afs_alloc_flat_call(net, &afs_RXFSSymlink, reqsz,
1025 1026 1027 1028
				   (3 + 21 + 21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1029
	call->key = fc->key;
1030 1031 1032
	call->reply[0] = vnode;
	call->reply[1] = newfid;
	call->reply[2] = newstatus;
1033
	call->expected_version = vnode->status.data_version;
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSYMLINK);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);
	*bp++ = htonl(namesz);
	memcpy(bp, name, namesz);
	bp = (void *) bp + namesz;
	if (padsz > 0) {
		memset(bp, 0, padsz);
		bp = (void *) bp + padsz;
	}
	*bp++ = htonl(c_namesz);
	memcpy(bp, contents, c_namesz);
	bp = (void *) bp + c_namesz;
	if (c_padsz > 0) {
		memset(bp, 0, c_padsz);
		bp = (void *) bp + c_padsz;
	}
1055 1056
	*bp++ = htonl(AFS_SET_MODE | AFS_SET_MTIME);
	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1057 1058 1059 1060 1061
	*bp++ = 0; /* owner */
	*bp++ = 0; /* group */
	*bp++ = htonl(S_IRWXUGO); /* unix mode */
	*bp++ = 0; /* segment size */

1062
	afs_use_fs_server(call, fc->cbi);
1063
	trace_afs_make_fs_call(call, &vnode->fid);
1064
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1065 1066 1067 1068 1069
}

/*
 * deliver reply data to an FS.Rename
 */
1070
static int afs_deliver_fs_rename(struct afs_call *call)
1071
{
1072
	struct afs_vnode *orig_dvnode = call->reply[0], *new_dvnode = call->reply[1];
1073
	const __be32 *bp;
1074
	int ret;
1075

1076
	_enter("{%u}", call->unmarshall);
1077

1078
	ret = afs_transfer_reply(call);
1079 1080
	if (ret < 0)
		return ret;
1081 1082 1083

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
1084 1085 1086 1087 1088 1089 1090
	if (xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
	if (new_dvnode != orig_dvnode &&
	    xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
				      &call->expected_version_2, NULL) < 0)
		return -EBADMSG;
1091
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.Rename operation type
 */
static const struct afs_call_type afs_RXFSRename = {
	.name		= "FS.Rename",
1102
	.op		= afs_FS_Rename,
1103 1104 1105 1106 1107 1108 1109
	.deliver	= afs_deliver_fs_rename,
	.destructor	= afs_flat_call_destructor,
};

/*
 * create a symbolic link
 */
D
David Howells 已提交
1110
int afs_fs_rename(struct afs_fs_cursor *fc,
1111 1112
		  const char *orig_name,
		  struct afs_vnode *new_dvnode,
1113
		  const char *new_name)
1114
{
1115
	struct afs_vnode *orig_dvnode = fc->vnode;
1116
	struct afs_call *call;
1117
	struct afs_net *net = afs_v2net(orig_dvnode);
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
	size_t reqsz, o_namesz, o_padsz, n_namesz, n_padsz;
	__be32 *bp;

	_enter("");

	o_namesz = strlen(orig_name);
	o_padsz = (4 - (o_namesz & 3)) & 3;

	n_namesz = strlen(new_name);
	n_padsz = (4 - (n_namesz & 3)) & 3;

	reqsz = (4 * 4) +
		4 + o_namesz + o_padsz +
		(3 * 4) +
		4 + n_namesz + n_padsz;

1134
	call = afs_alloc_flat_call(net, &afs_RXFSRename, reqsz, (21 + 21 + 6) * 4);
1135 1136 1137
	if (!call)
		return -ENOMEM;

1138
	call->key = fc->key;
1139 1140
	call->reply[0] = orig_dvnode;
	call->reply[1] = new_dvnode;
1141 1142
	call->expected_version = orig_dvnode->status.data_version;
	call->expected_version_2 = new_dvnode->status.data_version;
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSRENAME);
	*bp++ = htonl(orig_dvnode->fid.vid);
	*bp++ = htonl(orig_dvnode->fid.vnode);
	*bp++ = htonl(orig_dvnode->fid.unique);
	*bp++ = htonl(o_namesz);
	memcpy(bp, orig_name, o_namesz);
	bp = (void *) bp + o_namesz;
	if (o_padsz > 0) {
		memset(bp, 0, o_padsz);
		bp = (void *) bp + o_padsz;
	}

	*bp++ = htonl(new_dvnode->fid.vid);
	*bp++ = htonl(new_dvnode->fid.vnode);
	*bp++ = htonl(new_dvnode->fid.unique);
	*bp++ = htonl(n_namesz);
	memcpy(bp, new_name, n_namesz);
	bp = (void *) bp + n_namesz;
	if (n_padsz > 0) {
		memset(bp, 0, n_padsz);
		bp = (void *) bp + n_padsz;
	}

1169
	afs_use_fs_server(call, fc->cbi);
1170
	trace_afs_make_fs_call(call, &orig_dvnode->fid);
1171
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1172
}
1173 1174 1175 1176

/*
 * deliver reply data to an FS.StoreData
 */
1177
static int afs_deliver_fs_store_data(struct afs_call *call)
1178
{
1179
	struct afs_vnode *vnode = call->reply[0];
1180
	const __be32 *bp;
1181
	int ret;
1182

1183
	_enter("");
1184

1185
	ret = afs_transfer_reply(call);
1186 1187
	if (ret < 0)
		return ret;
1188 1189 1190

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
1191 1192 1193
	if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
1194
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206

	afs_pages_written_back(vnode, call);

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.StoreData operation type
 */
static const struct afs_call_type afs_RXFSStoreData = {
	.name		= "FS.StoreData",
1207
	.op		= afs_FS_StoreData,
1208 1209 1210 1211
	.deliver	= afs_deliver_fs_store_data,
	.destructor	= afs_flat_call_destructor,
};

D
David Howells 已提交
1212 1213
static const struct afs_call_type afs_RXFSStoreData64 = {
	.name		= "FS.StoreData64",
1214
	.op		= afs_FS_StoreData64,
D
David Howells 已提交
1215 1216 1217 1218 1219 1220 1221
	.deliver	= afs_deliver_fs_store_data,
	.destructor	= afs_flat_call_destructor,
};

/*
 * store a set of pages to a very large file
 */
D
David Howells 已提交
1222
static int afs_fs_store_data64(struct afs_fs_cursor *fc,
1223
			       struct address_space *mapping,
D
David Howells 已提交
1224 1225
			       pgoff_t first, pgoff_t last,
			       unsigned offset, unsigned to,
1226
			       loff_t size, loff_t pos, loff_t i_size)
D
David Howells 已提交
1227
{
1228
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1229
	struct afs_call *call;
1230
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1231 1232 1233
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
1234
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
D
David Howells 已提交
1235

1236
	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
D
David Howells 已提交
1237 1238 1239 1240 1241
				   (4 + 6 + 3 * 2) * 4,
				   (21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1242 1243
	call->key = fc->key;
	call->mapping = mapping;
1244
	call->reply[0] = vnode;
D
David Howells 已提交
1245 1246 1247 1248 1249
	call->first = first;
	call->last = last;
	call->first_offset = offset;
	call->last_to = to;
	call->send_pages = true;
1250
	call->expected_version = vnode->status.data_version + 1;
D
David Howells 已提交
1251 1252 1253 1254 1255 1256 1257 1258

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSTOREDATA64);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

1259 1260
	*bp++ = htonl(AFS_SET_MTIME); /* mask */
	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
D
David Howells 已提交
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
	*bp++ = 0; /* owner */
	*bp++ = 0; /* group */
	*bp++ = 0; /* unix mode */
	*bp++ = 0; /* segment size */

	*bp++ = htonl(pos >> 32);
	*bp++ = htonl((u32) pos);
	*bp++ = htonl(size >> 32);
	*bp++ = htonl((u32) size);
	*bp++ = htonl(i_size >> 32);
	*bp++ = htonl((u32) i_size);

1273
	trace_afs_make_fs_call(call, &vnode->fid);
1274
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
1275 1276
}

1277 1278 1279
/*
 * store a set of pages
 */
1280
int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
1281
		      pgoff_t first, pgoff_t last,
1282
		      unsigned offset, unsigned to)
1283
{
1284
	struct afs_vnode *vnode = fc->vnode;
1285
	struct afs_call *call;
1286
	struct afs_net *net = afs_v2net(vnode);
1287 1288 1289 1290
	loff_t size, pos, i_size;
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
1291
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1292

1293
	size = (loff_t)to - (loff_t)offset;
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
	if (first != last)
		size += (loff_t)(last - first) << PAGE_SHIFT;
	pos = (loff_t)first << PAGE_SHIFT;
	pos += offset;

	i_size = i_size_read(&vnode->vfs_inode);
	if (pos + size > i_size)
		i_size = size + pos;

	_debug("size %llx, at %llx, i_size %llx",
	       (unsigned long long) size, (unsigned long long) pos,
	       (unsigned long long) i_size);

D
David Howells 已提交
1307
	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
1308
		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
1309
					   size, pos, i_size);
1310

1311
	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
1312 1313 1314 1315 1316
				   (4 + 6 + 3) * 4,
				   (21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1317 1318
	call->key = fc->key;
	call->mapping = mapping;
1319
	call->reply[0] = vnode;
1320 1321 1322 1323 1324
	call->first = first;
	call->last = last;
	call->first_offset = offset;
	call->last_to = to;
	call->send_pages = true;
1325
	call->expected_version = vnode->status.data_version + 1;
1326 1327 1328 1329 1330 1331 1332 1333

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSTOREDATA);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

1334 1335
	*bp++ = htonl(AFS_SET_MTIME); /* mask */
	*bp++ = htonl(vnode->vfs_inode.i_mtime.tv_sec); /* mtime */
1336 1337 1338 1339 1340 1341 1342 1343 1344
	*bp++ = 0; /* owner */
	*bp++ = 0; /* group */
	*bp++ = 0; /* unix mode */
	*bp++ = 0; /* segment size */

	*bp++ = htonl(pos);
	*bp++ = htonl(size);
	*bp++ = htonl(i_size);

1345
	afs_use_fs_server(call, fc->cbi);
1346
	trace_afs_make_fs_call(call, &vnode->fid);
1347
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1348 1349 1350 1351 1352
}

/*
 * deliver reply data to an FS.StoreStatus
 */
1353
static int afs_deliver_fs_store_status(struct afs_call *call)
1354
{
1355
	struct afs_vnode *vnode = call->reply[0];
1356
	const __be32 *bp;
1357
	int ret;
1358

1359
	_enter("");
1360

1361
	ret = afs_transfer_reply(call);
1362 1363
	if (ret < 0)
		return ret;
1364 1365 1366

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
D
David Howells 已提交
1367 1368 1369
	if (xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
				      &call->expected_version, NULL) < 0)
		return -EBADMSG;
1370
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.StoreStatus operation type
 */
static const struct afs_call_type afs_RXFSStoreStatus = {
	.name		= "FS.StoreStatus",
1381
	.op		= afs_FS_StoreStatus,
1382 1383 1384 1385 1386 1387
	.deliver	= afs_deliver_fs_store_status,
	.destructor	= afs_flat_call_destructor,
};

static const struct afs_call_type afs_RXFSStoreData_as_Status = {
	.name		= "FS.StoreData",
1388
	.op		= afs_FS_StoreData,
1389 1390 1391 1392
	.deliver	= afs_deliver_fs_store_status,
	.destructor	= afs_flat_call_destructor,
};

D
David Howells 已提交
1393 1394
static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
	.name		= "FS.StoreData64",
1395
	.op		= afs_FS_StoreData64,
D
David Howells 已提交
1396 1397 1398 1399 1400 1401 1402 1403
	.deliver	= afs_deliver_fs_store_status,
	.destructor	= afs_flat_call_destructor,
};

/*
 * set the attributes on a very large file, using FS.StoreData rather than
 * FS.StoreStatus so as to alter the file size also
 */
1404
static int afs_fs_setattr_size64(struct afs_fs_cursor *fc, struct iattr *attr)
D
David Howells 已提交
1405
{
1406
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1407
	struct afs_call *call;
1408
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1409 1410 1411
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
1412
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
D
David Howells 已提交
1413 1414 1415

	ASSERT(attr->ia_valid & ATTR_SIZE);

1416
	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64_as_Status,
D
David Howells 已提交
1417 1418 1419 1420 1421
				   (4 + 6 + 3 * 2) * 4,
				   (21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1422
	call->key = fc->key;
1423
	call->reply[0] = vnode;
1424
	call->expected_version = vnode->status.data_version + 1;
D
David Howells 已提交
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSTOREDATA64);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

	xdr_encode_AFS_StoreStatus(&bp, attr);

	*bp++ = 0;				/* position of start of write */
	*bp++ = 0;
	*bp++ = 0;				/* size of write */
	*bp++ = 0;
	*bp++ = htonl(attr->ia_size >> 32);	/* new file length */
	*bp++ = htonl((u32) attr->ia_size);

1442
	afs_use_fs_server(call, fc->cbi);
1443
	trace_afs_make_fs_call(call, &vnode->fid);
1444
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
1445 1446
}

1447 1448 1449 1450
/*
 * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
 * so as to alter the file size also
 */
1451
static int afs_fs_setattr_size(struct afs_fs_cursor *fc, struct iattr *attr)
1452
{
1453
	struct afs_vnode *vnode = fc->vnode;
1454
	struct afs_call *call;
1455
	struct afs_net *net = afs_v2net(vnode);
1456 1457 1458
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
1459
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1460 1461

	ASSERT(attr->ia_valid & ATTR_SIZE);
D
David Howells 已提交
1462
	if (attr->ia_size >> 32)
1463
		return afs_fs_setattr_size64(fc, attr);
1464

1465
	call = afs_alloc_flat_call(net, &afs_RXFSStoreData_as_Status,
1466 1467 1468 1469 1470
				   (4 + 6 + 3) * 4,
				   (21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1471
	call->key = fc->key;
1472
	call->reply[0] = vnode;
1473
	call->expected_version = vnode->status.data_version + 1;
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSTOREDATA);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

	xdr_encode_AFS_StoreStatus(&bp, attr);

	*bp++ = 0;				/* position of start of write */
	*bp++ = 0;				/* size of write */
	*bp++ = htonl(attr->ia_size);		/* new file length */

1488
	afs_use_fs_server(call, fc->cbi);
1489
	trace_afs_make_fs_call(call, &vnode->fid);
1490
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1491 1492 1493 1494 1495 1496
}

/*
 * set the attributes on a file, using FS.StoreData if there's a change in file
 * size, and FS.StoreStatus otherwise
 */
1497
int afs_fs_setattr(struct afs_fs_cursor *fc, struct iattr *attr)
1498
{
1499
	struct afs_vnode *vnode = fc->vnode;
1500
	struct afs_call *call;
1501
	struct afs_net *net = afs_v2net(vnode);
1502 1503 1504
	__be32 *bp;

	if (attr->ia_valid & ATTR_SIZE)
1505
		return afs_fs_setattr_size(fc, attr);
1506 1507

	_enter(",%x,{%x:%u},,",
1508
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);
1509

1510
	call = afs_alloc_flat_call(net, &afs_RXFSStoreStatus,
1511 1512 1513 1514 1515
				   (4 + 6) * 4,
				   (21 + 6) * 4);
	if (!call)
		return -ENOMEM;

1516
	call->key = fc->key;
1517
	call->reply[0] = vnode;
1518
	call->expected_version = vnode->status.data_version;
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSTORESTATUS);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

	xdr_encode_AFS_StoreStatus(&bp, attr);

1529
	afs_use_fs_server(call, fc->cbi);
1530
	trace_afs_make_fs_call(call, &vnode->fid);
1531
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1532
}
D
David Howells 已提交
1533 1534 1535 1536

/*
 * deliver reply data to an FS.GetVolumeStatus
 */
1537
static int afs_deliver_fs_get_volume_status(struct afs_call *call)
D
David Howells 已提交
1538 1539 1540 1541 1542
{
	const __be32 *bp;
	char *p;
	int ret;

1543
	_enter("{%u}", call->unmarshall);
D
David Howells 已提交
1544 1545 1546 1547 1548 1549 1550 1551 1552

	switch (call->unmarshall) {
	case 0:
		call->offset = 0;
		call->unmarshall++;

		/* extract the returned status record */
	case 1:
		_debug("extract status");
1553 1554
		ret = afs_extract_data(call, call->buffer,
				       12 * 4, true);
1555 1556
		if (ret < 0)
			return ret;
D
David Howells 已提交
1557 1558

		bp = call->buffer;
1559
		xdr_decode_AFSFetchVolumeStatus(&bp, call->reply[1]);
D
David Howells 已提交
1560 1561 1562 1563 1564
		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name length */
	case 2:
1565
		ret = afs_extract_data(call, &call->tmp, 4, true);
1566 1567
		if (ret < 0)
			return ret;
D
David Howells 已提交
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579

		call->count = ntohl(call->tmp);
		_debug("volname length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name */
	case 3:
		_debug("extract volname");
		if (call->count > 0) {
1580
			ret = afs_extract_data(call, call->reply[2],
1581
					       call->count, true);
1582 1583
			if (ret < 0)
				return ret;
D
David Howells 已提交
1584 1585
		}

1586
		p = call->reply[2];
D
David Howells 已提交
1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
		p[call->count] = 0;
		_debug("volname '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the volume name padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_volname_padding;
		}
		call->count = 4 - (call->count & 3);

	case 4:
1601 1602
		ret = afs_extract_data(call, call->buffer,
				       call->count, true);
1603 1604
		if (ret < 0)
			return ret;
D
David Howells 已提交
1605 1606 1607 1608 1609 1610 1611

		call->offset = 0;
		call->unmarshall++;
	no_volname_padding:

		/* extract the offline message length */
	case 5:
1612
		ret = afs_extract_data(call, &call->tmp, 4, true);
1613 1614
		if (ret < 0)
			return ret;
D
David Howells 已提交
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626

		call->count = ntohl(call->tmp);
		_debug("offline msg length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the offline message */
	case 6:
		_debug("extract offline");
		if (call->count > 0) {
1627
			ret = afs_extract_data(call, call->reply[2],
1628
					       call->count, true);
1629 1630
			if (ret < 0)
				return ret;
D
David Howells 已提交
1631 1632
		}

1633
		p = call->reply[2];
D
David Howells 已提交
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647
		p[call->count] = 0;
		_debug("offline '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the offline message padding */
		if ((call->count & 3) == 0) {
			call->unmarshall++;
			goto no_offline_padding;
		}
		call->count = 4 - (call->count & 3);

	case 7:
1648 1649
		ret = afs_extract_data(call, call->buffer,
				       call->count, true);
1650 1651
		if (ret < 0)
			return ret;
D
David Howells 已提交
1652 1653 1654 1655 1656 1657 1658

		call->offset = 0;
		call->unmarshall++;
	no_offline_padding:

		/* extract the message of the day length */
	case 8:
1659
		ret = afs_extract_data(call, &call->tmp, 4, true);
1660 1661
		if (ret < 0)
			return ret;
D
David Howells 已提交
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673

		call->count = ntohl(call->tmp);
		_debug("motd length: %u", call->count);
		if (call->count >= AFSNAMEMAX)
			return -EBADMSG;
		call->offset = 0;
		call->unmarshall++;

		/* extract the message of the day */
	case 9:
		_debug("extract motd");
		if (call->count > 0) {
1674
			ret = afs_extract_data(call, call->reply[2],
1675
					       call->count, true);
1676 1677
			if (ret < 0)
				return ret;
D
David Howells 已提交
1678 1679
		}

1680
		p = call->reply[2];
D
David Howells 已提交
1681 1682 1683 1684 1685 1686 1687
		p[call->count] = 0;
		_debug("motd '%s'", p);

		call->offset = 0;
		call->unmarshall++;

		/* extract the message of the day padding */
1688
		call->count = (4 - (call->count & 3)) & 3;
D
David Howells 已提交
1689 1690

	case 10:
1691 1692
		ret = afs_extract_data(call, call->buffer,
				       call->count, false);
1693 1694
		if (ret < 0)
			return ret;
D
David Howells 已提交
1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710

		call->offset = 0;
		call->unmarshall++;
	case 11:
		break;
	}

	_leave(" = 0 [done]");
	return 0;
}

/*
 * destroy an FS.GetVolumeStatus call
 */
static void afs_get_volume_status_call_destructor(struct afs_call *call)
{
1711 1712
	kfree(call->reply[2]);
	call->reply[2] = NULL;
D
David Howells 已提交
1713 1714 1715 1716 1717 1718 1719 1720
	afs_flat_call_destructor(call);
}

/*
 * FS.GetVolumeStatus operation type
 */
static const struct afs_call_type afs_RXFSGetVolumeStatus = {
	.name		= "FS.GetVolumeStatus",
1721
	.op		= afs_FS_GetVolumeStatus,
D
David Howells 已提交
1722 1723 1724 1725 1726 1727 1728
	.deliver	= afs_deliver_fs_get_volume_status,
	.destructor	= afs_get_volume_status_call_destructor,
};

/*
 * fetch the status of a volume
 */
D
David Howells 已提交
1729
int afs_fs_get_volume_status(struct afs_fs_cursor *fc,
1730
			     struct afs_volume_status *vs)
D
David Howells 已提交
1731
{
1732
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1733
	struct afs_call *call;
1734
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1735 1736 1737 1738 1739 1740 1741 1742 1743
	__be32 *bp;
	void *tmpbuf;

	_enter("");

	tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
	if (!tmpbuf)
		return -ENOMEM;

1744
	call = afs_alloc_flat_call(net, &afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
D
David Howells 已提交
1745 1746 1747 1748 1749
	if (!call) {
		kfree(tmpbuf);
		return -ENOMEM;
	}

1750
	call->key = fc->key;
1751 1752 1753
	call->reply[0] = vnode;
	call->reply[1] = vs;
	call->reply[2] = tmpbuf;
D
David Howells 已提交
1754 1755 1756 1757 1758 1759

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSGETVOLUMESTATUS);
	bp[1] = htonl(vnode->fid.vid);

1760
	afs_use_fs_server(call, fc->cbi);
1761
	trace_afs_make_fs_call(call, &vnode->fid);
1762
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
1763
}
D
David Howells 已提交
1764 1765 1766 1767

/*
 * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
 */
1768
static int afs_deliver_fs_xxxx_lock(struct afs_call *call)
D
David Howells 已提交
1769 1770
{
	const __be32 *bp;
1771
	int ret;
D
David Howells 已提交
1772

1773
	_enter("{%u}", call->unmarshall);
D
David Howells 已提交
1774

1775
	ret = afs_transfer_reply(call);
1776 1777
	if (ret < 0)
		return ret;
D
David Howells 已提交
1778 1779 1780

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
1781
	/* xdr_decode_AFSVolSync(&bp, call->reply[X]); */
D
David Howells 已提交
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.SetLock operation type
 */
static const struct afs_call_type afs_RXFSSetLock = {
	.name		= "FS.SetLock",
1792
	.op		= afs_FS_SetLock,
D
David Howells 已提交
1793 1794 1795 1796 1797 1798 1799 1800 1801
	.deliver	= afs_deliver_fs_xxxx_lock,
	.destructor	= afs_flat_call_destructor,
};

/*
 * FS.ExtendLock operation type
 */
static const struct afs_call_type afs_RXFSExtendLock = {
	.name		= "FS.ExtendLock",
1802
	.op		= afs_FS_ExtendLock,
D
David Howells 已提交
1803 1804 1805 1806 1807 1808 1809 1810 1811
	.deliver	= afs_deliver_fs_xxxx_lock,
	.destructor	= afs_flat_call_destructor,
};

/*
 * FS.ReleaseLock operation type
 */
static const struct afs_call_type afs_RXFSReleaseLock = {
	.name		= "FS.ReleaseLock",
1812
	.op		= afs_FS_ReleaseLock,
D
David Howells 已提交
1813 1814 1815 1816 1817
	.deliver	= afs_deliver_fs_xxxx_lock,
	.destructor	= afs_flat_call_destructor,
};

/*
1818
 * Set a lock on a file
D
David Howells 已提交
1819
 */
1820
int afs_fs_set_lock(struct afs_fs_cursor *fc, afs_lock_type_t type)
D
David Howells 已提交
1821
{
1822
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1823
	struct afs_call *call;
1824
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1825 1826 1827 1828
	__be32 *bp;

	_enter("");

1829
	call = afs_alloc_flat_call(net, &afs_RXFSSetLock, 5 * 4, 6 * 4);
D
David Howells 已提交
1830 1831 1832
	if (!call)
		return -ENOMEM;

1833
	call->key = fc->key;
1834
	call->reply[0] = vnode;
D
David Howells 已提交
1835 1836 1837 1838 1839 1840 1841 1842 1843

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSSETLOCK);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);
	*bp++ = htonl(type);

1844
	afs_use_fs_server(call, fc->cbi);
1845
	trace_afs_make_fs_call(call, &vnode->fid);
1846
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
1847 1848 1849 1850 1851
}

/*
 * extend a lock on a file
 */
1852
int afs_fs_extend_lock(struct afs_fs_cursor *fc)
D
David Howells 已提交
1853
{
1854
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1855
	struct afs_call *call;
1856
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1857 1858 1859 1860
	__be32 *bp;

	_enter("");

1861
	call = afs_alloc_flat_call(net, &afs_RXFSExtendLock, 4 * 4, 6 * 4);
D
David Howells 已提交
1862 1863 1864
	if (!call)
		return -ENOMEM;

1865
	call->key = fc->key;
1866
	call->reply[0] = vnode;
D
David Howells 已提交
1867 1868 1869 1870 1871 1872 1873 1874

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSEXTENDLOCK);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

1875
	afs_use_fs_server(call, fc->cbi);
1876
	trace_afs_make_fs_call(call, &vnode->fid);
1877
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
D
David Howells 已提交
1878 1879 1880 1881 1882
}

/*
 * release a lock on a file
 */
1883
int afs_fs_release_lock(struct afs_fs_cursor *fc)
D
David Howells 已提交
1884
{
1885
	struct afs_vnode *vnode = fc->vnode;
D
David Howells 已提交
1886
	struct afs_call *call;
1887
	struct afs_net *net = afs_v2net(vnode);
D
David Howells 已提交
1888 1889 1890 1891
	__be32 *bp;

	_enter("");

1892
	call = afs_alloc_flat_call(net, &afs_RXFSReleaseLock, 4 * 4, 6 * 4);
D
David Howells 已提交
1893 1894 1895
	if (!call)
		return -ENOMEM;

1896
	call->key = fc->key;
1897
	call->reply[0] = vnode;
D
David Howells 已提交
1898 1899 1900 1901 1902 1903 1904 1905

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSRELEASELOCK);
	*bp++ = htonl(vnode->fid.vid);
	*bp++ = htonl(vnode->fid.vnode);
	*bp++ = htonl(vnode->fid.unique);

1906
	afs_use_fs_server(call, fc->cbi);
1907
	trace_afs_make_fs_call(call, &vnode->fid);
1908
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923
}

/*
 * Deliver reply data to an FS.GiveUpAllCallBacks operation.
 */
static int afs_deliver_fs_give_up_all_callbacks(struct afs_call *call)
{
	return afs_transfer_reply(call);
}

/*
 * FS.GiveUpAllCallBacks operation type
 */
static const struct afs_call_type afs_RXFSGiveUpAllCallBacks = {
	.name		= "FS.GiveUpAllCallBacks",
1924
	.op		= afs_FS_GiveUpAllCallBacks,
1925 1926 1927 1928 1929 1930 1931
	.deliver	= afs_deliver_fs_give_up_all_callbacks,
	.destructor	= afs_flat_call_destructor,
};

/*
 * Flush all the callbacks we have on a server.
 */
1932 1933
int afs_fs_give_up_all_callbacks(struct afs_net *net,
				 struct afs_server *server,
D
David Howells 已提交
1934
				 struct afs_addr_cursor *ac,
1935
				 struct key *key)
1936 1937 1938 1939 1940 1941
{
	struct afs_call *call;
	__be32 *bp;

	_enter("");

1942
	call = afs_alloc_flat_call(net, &afs_RXFSGiveUpAllCallBacks, 1 * 4, 0);
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
	if (!call)
		return -ENOMEM;

	call->key = key;

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSGIVEUPALLCALLBACKS);

	/* Can't take a ref on server */
1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014
	return afs_make_call(ac, call, GFP_NOFS, false);
}

/*
 * Deliver reply data to an FS.GetCapabilities operation.
 */
static int afs_deliver_fs_get_capabilities(struct afs_call *call)
{
	u32 count;
	int ret;

	_enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);

again:
	switch (call->unmarshall) {
	case 0:
		call->offset = 0;
		call->unmarshall++;

		/* Extract the capabilities word count */
	case 1:
		ret = afs_extract_data(call, &call->tmp,
				       1 * sizeof(__be32),
				       true);
		if (ret < 0)
			return ret;

		count = ntohl(call->tmp);

		call->count = count;
		call->count2 = count;
		call->offset = 0;
		call->unmarshall++;

		/* Extract capabilities words */
	case 2:
		count = min(call->count, 16U);
		ret = afs_extract_data(call, call->buffer,
				       count * sizeof(__be32),
				       call->count > 16);
		if (ret < 0)
			return ret;

		/* TODO: Examine capabilities */

		call->count -= count;
		if (call->count > 0)
			goto again;
		call->offset = 0;
		call->unmarshall++;
		break;
	}

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.GetCapabilities operation type
 */
static const struct afs_call_type afs_RXFSGetCapabilities = {
	.name		= "FS.GetCapabilities",
2015
	.op		= afs_FS_GetCapabilities,
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
	.deliver	= afs_deliver_fs_get_capabilities,
	.destructor	= afs_flat_call_destructor,
};

/*
 * Probe a fileserver for the capabilities that it supports.  This can
 * return up to 196 words.
 */
int afs_fs_get_capabilities(struct afs_net *net,
			    struct afs_server *server,
			    struct afs_addr_cursor *ac,
			    struct key *key)
{
	struct afs_call *call;
	__be32 *bp;

	_enter("");

	call = afs_alloc_flat_call(net, &afs_RXFSGetCapabilities, 1 * 4, 16 * 4);
	if (!call)
		return -ENOMEM;

	call->key = key;

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSGETCAPABILITIES);

	/* Can't take a ref on server */
2045
	trace_afs_make_fs_call(call, NULL);
2046
	return afs_make_call(ac, call, GFP_NOFS, false);
D
David Howells 已提交
2047
}
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068

/*
 * Deliver reply data to an FS.FetchStatus with no vnode.
 */
static int afs_deliver_fs_fetch_status(struct afs_call *call)
{
	struct afs_file_status *status = call->reply[1];
	struct afs_callback *callback = call->reply[2];
	struct afs_volsync *volsync = call->reply[3];
	struct afs_vnode *vnode = call->reply[0];
	const __be32 *bp;
	int ret;

	ret = afs_transfer_reply(call);
	if (ret < 0)
		return ret;

	_enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);

	/* unmarshall the reply once we've received all of it */
	bp = call->buffer;
2069 2070
	xdr_decode_AFSFetchStatus(&bp, status, vnode,
				  &call->expected_version, NULL);
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121
	callback[call->count].version	= ntohl(bp[0]);
	callback[call->count].expiry	= ntohl(bp[1]);
	callback[call->count].type	= ntohl(bp[2]);
	if (vnode)
		xdr_decode_AFSCallBack(call, vnode, &bp);
	else
		bp += 3;
	if (volsync)
		xdr_decode_AFSVolSync(&bp, volsync);

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.FetchStatus operation type
 */
static const struct afs_call_type afs_RXFSFetchStatus = {
	.name		= "FS.FetchStatus",
	.op		= afs_FS_FetchStatus,
	.deliver	= afs_deliver_fs_fetch_status,
	.destructor	= afs_flat_call_destructor,
};

/*
 * Fetch the status information for a fid without needing a vnode handle.
 */
int afs_fs_fetch_status(struct afs_fs_cursor *fc,
			struct afs_net *net,
			struct afs_fid *fid,
			struct afs_file_status *status,
			struct afs_callback *callback,
			struct afs_volsync *volsync)
{
	struct afs_call *call;
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
	       key_serial(fc->key), fid->vid, fid->vnode);

	call = afs_alloc_flat_call(net, &afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
	if (!call) {
		fc->ac.error = -ENOMEM;
		return -ENOMEM;
	}

	call->key = fc->key;
	call->reply[0] = NULL; /* vnode for fid[0] */
	call->reply[1] = status;
	call->reply[2] = callback;
	call->reply[3] = volsync;
2122
	call->expected_version = 1; /* vnode->status.data_version */
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSFETCHSTATUS);
	bp[1] = htonl(fid->vid);
	bp[2] = htonl(fid->vnode);
	bp[3] = htonl(fid->unique);

	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
	trace_afs_make_fs_call(call, fid);
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
}

/*
 * Deliver reply data to an FS.InlineBulkStatus call
 */
static int afs_deliver_fs_inline_bulk_status(struct afs_call *call)
{
	struct afs_file_status *statuses;
	struct afs_callback *callbacks;
	struct afs_vnode *vnode = call->reply[0];
	const __be32 *bp;
	u32 tmp;
	int ret;

	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
		call->offset = 0;
		call->unmarshall++;

		/* Extract the file status count and array in two steps */
	case 1:
		_debug("extract status count");
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

		tmp = ntohl(call->tmp);
		_debug("status count: %u/%u", tmp, call->count2);
		if (tmp != call->count2)
			return -EBADMSG;

		call->count = 0;
		call->unmarshall++;
	more_counts:
		call->offset = 0;

	case 2:
		_debug("extract status array %u", call->count);
		ret = afs_extract_data(call, call->buffer, 21 * 4, true);
		if (ret < 0)
			return ret;

		bp = call->buffer;
		statuses = call->reply[1];
D
David Howells 已提交
2181 2182 2183 2184
		if (xdr_decode_AFSFetchStatus(&bp, &statuses[call->count],
					      call->count == 0 ? vnode : NULL,
					      NULL, NULL) < 0)
			return -EBADMSG;
2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309

		call->count++;
		if (call->count < call->count2)
			goto more_counts;

		call->count = 0;
		call->unmarshall++;
		call->offset = 0;

		/* Extract the callback count and array in two steps */
	case 3:
		_debug("extract CB count");
		ret = afs_extract_data(call, &call->tmp, 4, true);
		if (ret < 0)
			return ret;

		tmp = ntohl(call->tmp);
		_debug("CB count: %u", tmp);
		if (tmp != call->count2)
			return -EBADMSG;
		call->count = 0;
		call->unmarshall++;
	more_cbs:
		call->offset = 0;

	case 4:
		_debug("extract CB array");
		ret = afs_extract_data(call, call->buffer, 3 * 4, true);
		if (ret < 0)
			return ret;

		_debug("unmarshall CB array");
		bp = call->buffer;
		callbacks = call->reply[2];
		callbacks[call->count].version	= ntohl(bp[0]);
		callbacks[call->count].expiry	= ntohl(bp[1]);
		callbacks[call->count].type	= ntohl(bp[2]);
		statuses = call->reply[1];
		if (call->count == 0 && vnode && statuses[0].abort_code == 0)
			xdr_decode_AFSCallBack(call, vnode, &bp);
		call->count++;
		if (call->count < call->count2)
			goto more_cbs;

		call->offset = 0;
		call->unmarshall++;

	case 5:
		ret = afs_extract_data(call, call->buffer, 6 * 4, false);
		if (ret < 0)
			return ret;

		bp = call->buffer;
		if (call->reply[3])
			xdr_decode_AFSVolSync(&bp, call->reply[3]);

		call->offset = 0;
		call->unmarshall++;

	case 6:
		break;
	}

	_leave(" = 0 [done]");
	return 0;
}

/*
 * FS.InlineBulkStatus operation type
 */
static const struct afs_call_type afs_RXFSInlineBulkStatus = {
	.name		= "FS.InlineBulkStatus",
	.op		= afs_FS_InlineBulkStatus,
	.deliver	= afs_deliver_fs_inline_bulk_status,
	.destructor	= afs_flat_call_destructor,
};

/*
 * Fetch the status information for up to 50 files
 */
int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
			      struct afs_net *net,
			      struct afs_fid *fids,
			      struct afs_file_status *statuses,
			      struct afs_callback *callbacks,
			      unsigned int nr_fids,
			      struct afs_volsync *volsync)
{
	struct afs_call *call;
	__be32 *bp;
	int i;

	_enter(",%x,{%x:%u},%u",
	       key_serial(fc->key), fids[0].vid, fids[1].vnode, nr_fids);

	call = afs_alloc_flat_call(net, &afs_RXFSInlineBulkStatus,
				   (2 + nr_fids * 3) * 4,
				   21 * 4);
	if (!call) {
		fc->ac.error = -ENOMEM;
		return -ENOMEM;
	}

	call->key = fc->key;
	call->reply[0] = NULL; /* vnode for fid[0] */
	call->reply[1] = statuses;
	call->reply[2] = callbacks;
	call->reply[3] = volsync;
	call->count2 = nr_fids;

	/* marshall the parameters */
	bp = call->request;
	*bp++ = htonl(FSINLINEBULKSTATUS);
	*bp++ = htonl(nr_fids);
	for (i = 0; i < nr_fids; i++) {
		*bp++ = htonl(fids[i].vid);
		*bp++ = htonl(fids[i].vnode);
		*bp++ = htonl(fids[i].unique);
	}

	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
	trace_afs_make_fs_call(call, &fids[0]);
	return afs_make_call(&fc->ac, call, GFP_NOFS, false);
}