nfs4filelayout.c 31.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 *  Module for the pnfs nfs4 file layout driver.
 *  Defines all I/O and Policy interface operations, plus code
 *  to register itself with the pNFS client.
 *
 *  Copyright (c) 2002
 *  The Regents of the University of Michigan
 *  All Rights Reserved
 *
 *  Dean Hildebrand <dhildebz@umich.edu>
 *
 *  Permission is granted to use, copy, create derivative works, and
 *  redistribute this software and such derivative works for any purpose,
 *  so long as the name of the University of Michigan is not used in
 *  any advertising or publicity pertaining to the use or distribution
 *  of this software without specific, written prior authorization. If
 *  the above copyright notice or any other identification of the
 *  University of Michigan is included in any copy of any portion of
 *  this software, then the disclaimer below must also be included.
 *
 *  This software is provided as is, without representation or warranty
 *  of any kind either express or implied, including without limitation
 *  the implied warranties of merchantability, fitness for a particular
 *  purpose, or noninfringement.  The Regents of the University of
 *  Michigan shall not be liable for any damages, including special,
 *  indirect, incidental, or consequential damages, with respect to any
 *  claim arising out of or in connection with the use of the software,
 *  even if it has been or is hereafter advised of the possibility of
 *  such damages.
 */

#include <linux/nfs_fs.h>
33
#include <linux/nfs_page.h>
34
#include <linux/module.h>
35

36 37
#include <linux/sunrpc/metrics.h>

38
#include "internal.h"
A
Andy Adamson 已提交
39
#include "delegation.h"
40
#include "nfs4filelayout.h"
41 42 43 44 45 46 47

#define NFSDBG_FACILITY         NFSDBG_PNFS_LD

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
MODULE_DESCRIPTION("The NFSv4 file layout driver");

48 49
#define FILELAYOUT_POLL_RETRY_MAX     (15*HZ)

F
Fred Isaman 已提交
50 51 52 53 54
static loff_t
filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
			    loff_t offset)
{
	u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
55 56
	u64 stripe_no;
	u32 rem;
F
Fred Isaman 已提交
57 58

	offset -= flseg->pattern_offset;
59 60
	stripe_no = div_u64(offset, stripe_width);
	div_u64_rem(offset, flseg->stripe_unit, &rem);
F
Fred Isaman 已提交
61

62
	return stripe_no * flseg->stripe_unit + rem;
F
Fred Isaman 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
}

/* This function is used by the layout driver to calculate the
 * offset of the file on the dserver based on whether the
 * layout type is STRIPE_DENSE or STRIPE_SPARSE
 */
static loff_t
filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
{
	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);

	switch (flseg->stripe_type) {
	case STRIPE_SPARSE:
		return offset;

	case STRIPE_DENSE:
		return filelayout_get_dense_offset(flseg, offset);
	}

	BUG();
}

85 86 87 88 89
static int filelayout_async_handle_error(struct rpc_task *task,
					 struct nfs4_state *state,
					 struct nfs_client *clp,
					 int *reset)
{
A
Andy Adamson 已提交
90 91 92
	struct nfs_server *mds_server = NFS_SERVER(state->inode);
	struct nfs_client *mds_client = mds_server->nfs_client;

93 94 95 96 97
	if (task->tk_status >= 0)
		return 0;
	*reset = 0;

	switch (task->tk_status) {
A
Andy Adamson 已提交
98 99 100 101
	/* MDS state errors */
	case -NFS4ERR_DELEG_REVOKED:
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_BAD_STATEID:
102
		nfs_remove_bad_delegation(state->inode);
A
Andy Adamson 已提交
103 104 105 106
	case -NFS4ERR_OPENMODE:
		nfs4_schedule_stateid_recovery(mds_server, state);
		goto wait_on_recovery;
	case -NFS4ERR_EXPIRED:
107
		nfs4_schedule_stateid_recovery(mds_server, state);
A
Andy Adamson 已提交
108 109 110
		nfs4_schedule_lease_recovery(mds_client);
		goto wait_on_recovery;
	/* DS session errors */
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
	case -NFS4ERR_BADSESSION:
	case -NFS4ERR_BADSLOT:
	case -NFS4ERR_BAD_HIGH_SLOT:
	case -NFS4ERR_DEADSESSION:
	case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
	case -NFS4ERR_SEQ_FALSE_RETRY:
	case -NFS4ERR_SEQ_MISORDERED:
		dprintk("%s ERROR %d, Reset session. Exchangeid "
			"flags 0x%x\n", __func__, task->tk_status,
			clp->cl_exchange_flags);
		nfs4_schedule_session_recovery(clp->cl_session);
		break;
	case -NFS4ERR_DELAY:
	case -NFS4ERR_GRACE:
	case -EKEYEXPIRED:
		rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
		break;
128 129
	case -NFS4ERR_RETRY_UNCACHED_REP:
		break;
130 131 132 133 134 135
	default:
		dprintk("%s DS error. Retry through MDS %d\n", __func__,
			task->tk_status);
		*reset = 1;
		break;
	}
A
Andy Adamson 已提交
136
out:
137 138
	task->tk_status = 0;
	return -EAGAIN;
A
Andy Adamson 已提交
139 140 141 142 143
wait_on_recovery:
	rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL);
	if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0)
		rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task);
	goto out;
144 145 146 147 148 149 150
}

/* NFS_PROTO call done callback routines */

static int filelayout_read_done_cb(struct rpc_task *task,
				struct nfs_read_data *data)
{
151
	struct nfs_pgio_header *hdr = data->header;
152 153 154 155 156 157 158 159 160
	int reset = 0;

	dprintk("%s DS read\n", __func__);

	if (filelayout_async_handle_error(task, data->args.context->state,
					  data->ds_clp, &reset) == -EAGAIN) {
		dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
			__func__, data->ds_clp, data->ds_clp->cl_session);
		if (reset) {
161
			pnfs_set_lo_fail(hdr->lseg);
162 163
			nfs4_reset_read(task, data);
		}
164
		rpc_restart_call_prepare(task);
165 166 167 168 169 170
		return -EAGAIN;
	}

	return 0;
}

A
Andy Adamson 已提交
171 172 173 174 175 176 177 178
/*
 * We reference the rpc_cred of the first WRITE that triggers the need for
 * a LAYOUTCOMMIT, and use it to send the layoutcommit compound.
 * rfc5661 is not clear about which credential should be used.
 */
static void
filelayout_set_layoutcommit(struct nfs_write_data *wdata)
{
179 180 181
	struct nfs_pgio_header *hdr = wdata->header;

	if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
A
Andy Adamson 已提交
182 183 184 185
	    wdata->res.verf->committed == NFS_FILE_SYNC)
		return;

	pnfs_set_layoutcommit(wdata);
186 187
	dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
		(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
A
Andy Adamson 已提交
188 189
}

A
Andy Adamson 已提交
190 191 192 193 194 195 196
/*
 * Call ops for the async read/write cases
 * In the case of dense layouts, the offset needs to be reset to its
 * original value.
 */
static void filelayout_read_prepare(struct rpc_task *task, void *data)
{
197
	struct nfs_read_data *rdata = data;
A
Andy Adamson 已提交
198

199 200
	rdata->read_done_cb = filelayout_read_done_cb;

A
Andy Adamson 已提交
201 202
	if (nfs41_setup_sequence(rdata->ds_clp->cl_session,
				&rdata->args.seq_args, &rdata->res.seq_res,
203
				task))
A
Andy Adamson 已提交
204 205 206 207 208 209 210
		return;

	rpc_call_start(task);
}

static void filelayout_read_call_done(struct rpc_task *task, void *data)
{
211
	struct nfs_read_data *rdata = data;
A
Andy Adamson 已提交
212 213 214 215

	dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);

	/* Note this may cause RPC to be resent */
216
	rdata->header->mds_ops->rpc_call_done(task, data);
A
Andy Adamson 已提交
217 218
}

219 220
static void filelayout_read_count_stats(struct rpc_task *task, void *data)
{
221
	struct nfs_read_data *rdata = data;
222

223
	rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics);
224 225
}

A
Andy Adamson 已提交
226 227
static void filelayout_read_release(void *data)
{
228
	struct nfs_read_data *rdata = data;
A
Andy Adamson 已提交
229

230
	rdata->header->mds_ops->rpc_release(data);
A
Andy Adamson 已提交
231 232
}

233 234 235
static int filelayout_write_done_cb(struct rpc_task *task,
				struct nfs_write_data *data)
{
236
	struct nfs_pgio_header *hdr = data->header;
237 238 239 240 241 242 243
	int reset = 0;

	if (filelayout_async_handle_error(task, data->args.context->state,
					  data->ds_clp, &reset) == -EAGAIN) {
		dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
			__func__, data->ds_clp, data->ds_clp->cl_session);
		if (reset) {
244
			pnfs_set_lo_fail(hdr->lseg);
245
			nfs4_reset_write(task, data);
246 247
		}
		rpc_restart_call_prepare(task);
248 249 250
		return -EAGAIN;
	}

A
Andy Adamson 已提交
251
	filelayout_set_layoutcommit(data);
252 253 254
	return 0;
}

255
/* Fake up some data that will cause nfs_commit_release to retry the writes. */
256
static void prepare_to_resend_writes(struct nfs_commit_data *data)
257 258 259 260 261 262 263 264 265 266
{
	struct nfs_page *first = nfs_list_entry(data->pages.next);

	data->task.tk_status = 0;
	memcpy(data->verf.verifier, first->wb_verf.verifier,
	       sizeof(first->wb_verf.verifier));
	data->verf.verifier[0]++; /* ensure verifier mismatch */
}

static int filelayout_commit_done_cb(struct rpc_task *task,
267
				     struct nfs_commit_data *data)
268 269 270
{
	int reset = 0;

271
	if (filelayout_async_handle_error(task, data->context->state,
272 273 274 275 276
					  data->ds_clp, &reset) == -EAGAIN) {
		dprintk("%s calling restart ds_clp %p ds_clp->cl_session %p\n",
			__func__, data->ds_clp, data->ds_clp->cl_session);
		if (reset) {
			prepare_to_resend_writes(data);
P
Peng Tao 已提交
277
			pnfs_set_lo_fail(data->lseg);
278
		} else
279
			rpc_restart_call_prepare(task);
280 281 282 283 284 285
		return -EAGAIN;
	}

	return 0;
}

286 287
static void filelayout_write_prepare(struct rpc_task *task, void *data)
{
288
	struct nfs_write_data *wdata = data;
289 290 291

	if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
				&wdata->args.seq_args, &wdata->res.seq_res,
292
				task))
293 294 295 296 297 298 299
		return;

	rpc_call_start(task);
}

static void filelayout_write_call_done(struct rpc_task *task, void *data)
{
300
	struct nfs_write_data *wdata = data;
301 302

	/* Note this may cause RPC to be resent */
303
	wdata->header->mds_ops->rpc_call_done(task, data);
304 305
}

306 307
static void filelayout_write_count_stats(struct rpc_task *task, void *data)
{
308
	struct nfs_write_data *wdata = data;
309

310
	rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics);
311 312
}

313 314
static void filelayout_write_release(void *data)
{
315
	struct nfs_write_data *wdata = data;
316

317 318
	put_lseg(wdata->header->lseg);
	wdata->header->mds_ops->rpc_release(data);
319 320
}

321
static void filelayout_commit_prepare(struct rpc_task *task, void *data)
322
{
323
	struct nfs_commit_data *wdata = data;
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
	if (nfs41_setup_sequence(wdata->ds_clp->cl_session,
				&wdata->args.seq_args, &wdata->res.seq_res,
				task))
		return;

	rpc_call_start(task);
}

static void filelayout_write_commit_done(struct rpc_task *task, void *data)
{
	struct nfs_commit_data *wdata = data;

	/* Note this may cause RPC to be resent */
	wdata->mds_ops->rpc_call_done(task, data);
}

static void filelayout_commit_count_stats(struct rpc_task *task, void *data)
{
	struct nfs_commit_data *cdata = data;

	rpc_count_iostats(task, NFS_SERVER(cdata->inode)->client->cl_metrics);
}

static void filelayout_commit_release(void *calldata)
{
	struct nfs_commit_data *data = calldata;

	nfs_commit_release_pages(data);
	if (atomic_dec_and_test(&NFS_I(data->inode)->commits_outstanding))
		nfs_commit_clear_lock(NFS_I(data->inode));
	put_lseg(data->lseg);
	nfs_commitdata_release(data);
357 358
}

359
static const struct rpc_call_ops filelayout_read_call_ops = {
A
Andy Adamson 已提交
360 361
	.rpc_call_prepare = filelayout_read_prepare,
	.rpc_call_done = filelayout_read_call_done,
362
	.rpc_count_stats = filelayout_read_count_stats,
A
Andy Adamson 已提交
363 364 365
	.rpc_release = filelayout_read_release,
};

366
static const struct rpc_call_ops filelayout_write_call_ops = {
367 368
	.rpc_call_prepare = filelayout_write_prepare,
	.rpc_call_done = filelayout_write_call_done,
369
	.rpc_count_stats = filelayout_write_count_stats,
370 371 372
	.rpc_release = filelayout_write_release,
};

373
static const struct rpc_call_ops filelayout_commit_call_ops = {
374 375 376
	.rpc_call_prepare = filelayout_commit_prepare,
	.rpc_call_done = filelayout_write_commit_done,
	.rpc_count_stats = filelayout_commit_count_stats,
377 378 379
	.rpc_release = filelayout_commit_release,
};

A
Andy Adamson 已提交
380 381 382
static enum pnfs_try_status
filelayout_read_pagelist(struct nfs_read_data *data)
{
383 384
	struct nfs_pgio_header *hdr = data->header;
	struct pnfs_layout_segment *lseg = hdr->lseg;
A
Andy Adamson 已提交
385 386 387 388 389 390 391
	struct nfs4_pnfs_ds *ds;
	loff_t offset = data->args.offset;
	u32 j, idx;
	struct nfs_fh *fh;
	int status;

	dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
392
		__func__, hdr->inode->i_ino,
A
Andy Adamson 已提交
393 394
		data->args.pgbase, (size_t)data->args.count, offset);

395 396 397
	if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags))
		return PNFS_NOT_ATTEMPTED;

A
Andy Adamson 已提交
398 399 400 401 402
	/* Retrieve the correct rpc_client for the byte range */
	j = nfs4_fl_calc_j_index(lseg, offset);
	idx = nfs4_fl_calc_ds_index(lseg, j);
	ds = nfs4_fl_prepare_ds(lseg, idx);
	if (!ds) {
403 404 405
		/* Either layout fh index faulty, or ds connect failed */
		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
A
Andy Adamson 已提交
406 407
		return PNFS_NOT_ATTEMPTED;
	}
W
Weston Andros Adamson 已提交
408
	dprintk("%s USE DS: %s\n", __func__, ds->ds_remotestr);
A
Andy Adamson 已提交
409 410 411 412 413 414 415 416 417 418 419

	/* No multipath support. Use first DS */
	data->ds_clp = ds->ds_clp;
	fh = nfs4_fl_select_ds_fh(lseg, j);
	if (fh)
		data->args.fh = fh;

	data->args.offset = filelayout_get_dserver_offset(lseg, offset);
	data->mds_offset = offset;

	/* Perform an asynchronous read to ds */
420
	status = nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
A
Andy Adamson 已提交
421 422 423 424 425
				   &filelayout_read_call_ops);
	BUG_ON(status != 0);
	return PNFS_ATTEMPTED;
}

426
/* Perform async writes. */
427 428 429
static enum pnfs_try_status
filelayout_write_pagelist(struct nfs_write_data *data, int sync)
{
430 431
	struct nfs_pgio_header *hdr = data->header;
	struct pnfs_layout_segment *lseg = hdr->lseg;
432 433 434 435 436 437
	struct nfs4_pnfs_ds *ds;
	loff_t offset = data->args.offset;
	u32 j, idx;
	struct nfs_fh *fh;
	int status;

438 439 440
	if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags))
		return PNFS_NOT_ATTEMPTED;

441 442 443 444 445
	/* Retrieve the correct rpc_client for the byte range */
	j = nfs4_fl_calc_j_index(lseg, offset);
	idx = nfs4_fl_calc_ds_index(lseg, j);
	ds = nfs4_fl_prepare_ds(lseg, idx);
	if (!ds) {
446 447
		printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
			__func__);
448 449 450 451
		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
		return PNFS_NOT_ATTEMPTED;
	}
W
Weston Andros Adamson 已提交
452
	dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s\n", __func__,
453
		hdr->inode->i_ino, sync, (size_t) data->args.count, offset,
W
Weston Andros Adamson 已提交
454
		ds->ds_remotestr);
455 456 457 458 459 460 461 462 463 464 465 466 467

	data->write_done_cb = filelayout_write_done_cb;
	data->ds_clp = ds->ds_clp;
	fh = nfs4_fl_select_ds_fh(lseg, j);
	if (fh)
		data->args.fh = fh;
	/*
	 * Get the file offset on the dserver. Set the write offset to
	 * this offset and save the original offset.
	 */
	data->args.offset = filelayout_get_dserver_offset(lseg, offset);

	/* Perform an asynchronous write */
468
	status = nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
469 470 471
				    &filelayout_write_call_ops, sync);
	BUG_ON(status != 0);
	return PNFS_ATTEMPTED;
472 473
}

474 475 476 477 478 479 480 481 482 483 484 485
/*
 * filelayout_check_layout()
 *
 * Make sure layout segment parameters are sane WRT the device.
 * At this point no generic layer initialization of the lseg has occurred,
 * and nothing has been added to the layout_hdr cache.
 *
 */
static int
filelayout_check_layout(struct pnfs_layout_hdr *lo,
			struct nfs4_filelayout_segment *fl,
			struct nfs4_layoutget_res *lgr,
486 487
			struct nfs4_deviceid *id,
			gfp_t gfp_flags)
488
{
489
	struct nfs4_deviceid_node *d;
490 491
	struct nfs4_file_layout_dsaddr *dsaddr;
	int status = -EINVAL;
492
	struct nfs_server *nfss = NFS_SERVER(lo->plh_inode);
493 494 495

	dprintk("--> %s\n", __func__);

496 497 498 499 500 501 502 503
	/* FIXME: remove this check when layout segment support is added */
	if (lgr->range.offset != 0 ||
	    lgr->range.length != NFS4_MAX_UINT64) {
		dprintk("%s Only whole file layouts supported. Use MDS i/o\n",
			__func__);
		goto out;
	}

504
	if (fl->pattern_offset > lgr->range.offset) {
505
		dprintk("%s pattern_offset %lld too large\n",
506 507 508 509
				__func__, fl->pattern_offset);
		goto out;
	}

510 511
	if (!fl->stripe_unit || fl->stripe_unit % PAGE_SIZE) {
		dprintk("%s Invalid stripe unit (%u)\n",
512 513 514 515 516
			__func__, fl->stripe_unit);
		goto out;
	}

	/* find and reference the deviceid */
517 518
	d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld,
				   NFS_SERVER(lo->plh_inode)->nfs_client, id);
519
	if (d == NULL) {
520
		dsaddr = get_device_info(lo->plh_inode, id, gfp_flags);
521 522
		if (dsaddr == NULL)
			goto out;
523 524
	} else
		dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
525 526 527 528
	/* Found deviceid is being reaped */
	if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags))
			goto out_put;

529 530
	fl->dsaddr = dsaddr;

531 532
	if (fl->first_stripe_index >= dsaddr->stripe_count) {
		dprintk("%s Bad first_stripe_index %u\n",
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
				__func__, fl->first_stripe_index);
		goto out_put;
	}

	if ((fl->stripe_type == STRIPE_SPARSE &&
	    fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
	    (fl->stripe_type == STRIPE_DENSE &&
	    fl->num_fh != dsaddr->stripe_count)) {
		dprintk("%s num_fh %u not valid for given packing\n",
			__func__, fl->num_fh);
		goto out_put;
	}

	if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
		dprintk("%s Stripe unit (%u) not aligned with rsize %u "
			"wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
			nfss->wsize);
	}

	status = 0;
out:
	dprintk("--> %s returns %d\n", __func__, status);
	return status;
out_put:
557
	nfs4_fl_put_deviceid(dsaddr);
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
	goto out;
}

static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
{
	int i;

	for (i = 0; i < fl->num_fh; i++) {
		if (!fl->fh_array[i])
			break;
		kfree(fl->fh_array[i]);
	}
	kfree(fl->fh_array);
	fl->fh_array = NULL;
}

static void
_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
{
	filelayout_free_fh_array(fl);
	kfree(fl);
}

static int
filelayout_decode_layout(struct pnfs_layout_hdr *flo,
			 struct nfs4_filelayout_segment *fl,
			 struct nfs4_layoutget_res *lgr,
585 586
			 struct nfs4_deviceid *id,
			 gfp_t gfp_flags)
587
{
588
	struct xdr_stream stream;
589
	struct xdr_buf buf;
590 591
	struct page *scratch;
	__be32 *p;
592 593 594 595 596
	uint32_t nfl_util;
	int i;

	dprintk("%s: set_layout_map Begin\n", __func__);

597
	scratch = alloc_page(gfp_flags);
598 599 600
	if (!scratch)
		return -ENOMEM;

601
	xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
602 603 604 605 606 607 608 609
	xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);

	/* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8),
	 * num_fh (4) */
	p = xdr_inline_decode(&stream, NFS4_DEVICEID4_SIZE + 20);
	if (unlikely(!p))
		goto out_err;

610 611
	memcpy(id, p, sizeof(*id));
	p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
612
	nfs4_print_deviceid(id);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630

	nfl_util = be32_to_cpup(p++);
	if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
		fl->commit_through_mds = 1;
	if (nfl_util & NFL4_UFLG_DENSE)
		fl->stripe_type = STRIPE_DENSE;
	else
		fl->stripe_type = STRIPE_SPARSE;
	fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;

	fl->first_stripe_index = be32_to_cpup(p++);
	p = xdr_decode_hyper(p, &fl->pattern_offset);
	fl->num_fh = be32_to_cpup(p++);

	dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
		__func__, nfl_util, fl->num_fh, fl->first_stripe_index,
		fl->pattern_offset);

631 632
	/* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
	 * Futher checking is done in filelayout_check_layout */
633
	if (fl->num_fh >
634
	    max(NFS4_PNFS_MAX_STRIPE_CNT, NFS4_PNFS_MAX_MULTI_CNT))
635 636
		goto out_err;

637 638 639 640 641 642
	if (fl->num_fh > 0) {
		fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
				       gfp_flags);
		if (!fl->fh_array)
			goto out_err;
	}
643 644 645

	for (i = 0; i < fl->num_fh; i++) {
		/* Do we want to use a mempool here? */
646
		fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
647 648 649 650 651 652
		if (!fl->fh_array[i])
			goto out_err_free;

		p = xdr_inline_decode(&stream, 4);
		if (unlikely(!p))
			goto out_err_free;
653 654
		fl->fh_array[i]->size = be32_to_cpup(p++);
		if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
655
			printk(KERN_ERR "NFS: Too big fh %d received %d\n",
656
			       i, fl->fh_array[i]->size);
657
			goto out_err_free;
658
		}
659 660 661 662

		p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
		if (unlikely(!p))
			goto out_err_free;
663 664 665 666 667
		memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
		dprintk("DEBUG: %s: fh len %d\n", __func__,
			fl->fh_array[i]->size);
	}

668
	__free_page(scratch);
669
	return 0;
670 671 672 673 674 675

out_err_free:
	filelayout_free_fh_array(fl);
out_err:
	__free_page(scratch);
	return -EIO;
676 677
}

678 679 680 681 682 683 684
static void
filelayout_free_lseg(struct pnfs_layout_segment *lseg)
{
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);

	dprintk("--> %s\n", __func__);
	nfs4_fl_put_deviceid(fl->dsaddr);
685 686 687 688 689 690 691 692 693
	/* This assumes a single RW lseg */
	if (lseg->pls_range.iomode == IOMODE_RW) {
		struct nfs4_filelayout *flo;

		flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);
		flo->commit_info.nbuckets = 0;
		kfree(flo->commit_info.buckets);
		flo->commit_info.buckets = NULL;
	}
694 695 696
	_filelayout_free_lseg(fl);
}

697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
static int
filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
			     gfp_t gfp_flags)
{
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
	struct nfs4_filelayout *flo = FILELAYOUT_FROM_HDR(lseg->pls_layout);

	struct nfs4_fl_commit_bucket *buckets;
	int size;

	if (fl->commit_through_mds)
		return 0;
	if (flo->commit_info.nbuckets != 0) {
		/* This assumes there is only one IOMODE_RW lseg.  What
		 * we really want to do is have a layout_hdr level
		 * dictionary of <multipath_list4, fh> keys, each
		 * associated with a struct list_head, populated by calls
		 * to filelayout_write_pagelist().
		 * */
		return 0;
	}

	size = (fl->stripe_type == STRIPE_SPARSE) ?
		fl->dsaddr->ds_num : fl->dsaddr->stripe_count;

	buckets = kcalloc(size, sizeof(struct nfs4_fl_commit_bucket),
			  gfp_flags);
	if (!buckets)
		return -ENOMEM;
	else {
		int i;

		spin_lock(&lseg->pls_layout->plh_inode->i_lock);
		if (flo->commit_info.nbuckets != 0)
			kfree(buckets);
		else {
			flo->commit_info.buckets = buckets;
			flo->commit_info.nbuckets = size;
			for (i = 0; i < size; i++) {
				INIT_LIST_HEAD(&buckets[i].written);
				INIT_LIST_HEAD(&buckets[i].committing);
			}
		}
		spin_unlock(&lseg->pls_layout->plh_inode->i_lock);
		return 0;
	}
}

745 746
static struct pnfs_layout_segment *
filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
747 748
		      struct nfs4_layoutget_res *lgr,
		      gfp_t gfp_flags)
749 750 751 752 753 754
{
	struct nfs4_filelayout_segment *fl;
	int rc;
	struct nfs4_deviceid id;

	dprintk("--> %s\n", __func__);
755
	fl = kzalloc(sizeof(*fl), gfp_flags);
756 757 758
	if (!fl)
		return NULL;

759 760
	rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
	if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
761 762 763 764 765 766
		_filelayout_free_lseg(fl);
		return NULL;
	}
	return &fl->generic_hdr;
}

767 768 769
/*
 * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
 *
770 771
 * return true  : coalesce page
 * return false : don't coalesce page
772
 */
773
static bool
774 775 776 777 778 779
filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
		   struct nfs_page *req)
{
	u64 p_stripe, r_stripe;
	u32 stripe_unit;

780 781 782
	if (!pnfs_generic_pg_test(pgio, prev, req) ||
	    !nfs_generic_pg_test(pgio, prev, req))
		return false;
783

784 785
	p_stripe = (u64)req_offset(prev);
	r_stripe = (u64)req_offset(req);
786 787 788 789 790 791 792 793
	stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;

	do_div(p_stripe, stripe_unit);
	do_div(r_stripe, stripe_unit);

	return (p_stripe == r_stripe);
}

794
static void
795 796 797 798 799 800 801 802 803 804 805 806 807
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
			struct nfs_page *req)
{
	BUG_ON(pgio->pg_lseg != NULL);

	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
					   req->wb_context,
					   0,
					   NFS4_MAX_UINT64,
					   IOMODE_READ,
					   GFP_KERNEL);
	/* If no lseg, fall back to read through mds */
	if (pgio->pg_lseg == NULL)
808
		nfs_pageio_reset_read_mds(pgio);
809 810
}

811
static void
812 813 814
filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
			 struct nfs_page *req)
{
815 816
	int status;

817 818 819 820 821 822 823 824 825 826
	BUG_ON(pgio->pg_lseg != NULL);

	pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
					   req->wb_context,
					   0,
					   NFS4_MAX_UINT64,
					   IOMODE_RW,
					   GFP_NOFS);
	/* If no lseg, fall back to write through mds */
	if (pgio->pg_lseg == NULL)
827 828 829 830 831 832 833 834 835 836
		goto out_mds;
	status = filelayout_alloc_commit_info(pgio->pg_lseg, GFP_NOFS);
	if (status < 0) {
		put_lseg(pgio->pg_lseg);
		pgio->pg_lseg = NULL;
		goto out_mds;
	}
	return;
out_mds:
	nfs_pageio_reset_write_mds(pgio);
837 838
}

839
static const struct nfs_pageio_ops filelayout_pg_read_ops = {
840
	.pg_init = filelayout_pg_init_read,
841
	.pg_test = filelayout_pg_test,
842
	.pg_doio = pnfs_generic_pg_readpages,
843 844 845
};

static const struct nfs_pageio_ops filelayout_pg_write_ops = {
846
	.pg_init = filelayout_pg_init_write,
847
	.pg_test = filelayout_pg_test,
848
	.pg_doio = pnfs_generic_pg_writepages,
849 850
};

851 852 853 854 855 856 857 858
static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
{
	if (fl->stripe_type == STRIPE_SPARSE)
		return nfs4_fl_calc_ds_index(&fl->generic_hdr, j);
	else
		return j;
}

F
Fred Isaman 已提交
859 860 861
/* The generic layer is about to remove the req from the commit list.
 * If this will make the bucket empty, it will need to put the lseg reference.
 */
862 863
static void
filelayout_clear_request_commit(struct nfs_page *req)
F
Fred Isaman 已提交
864
{
865 866 867 868 869 870
	struct pnfs_layout_segment *freeme = NULL;
	struct inode *inode = req->wb_context->dentry->d_inode;

	spin_lock(&inode->i_lock);
	if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
		goto out;
F
Fred Isaman 已提交
871
	if (list_is_singular(&req->wb_list)) {
872
		struct nfs4_fl_commit_bucket *bucket;
F
Fred Isaman 已提交
873

874 875 876 877 878
		bucket = list_first_entry(&req->wb_list,
					  struct nfs4_fl_commit_bucket,
					  written);
		freeme = bucket->wlseg;
		bucket->wlseg = NULL;
F
Fred Isaman 已提交
879
	}
880 881 882 883
out:
	nfs_request_remove_commit_list(req);
	spin_unlock(&inode->i_lock);
	put_lseg(freeme);
F
Fred Isaman 已提交
884 885 886 887 888
}

static struct list_head *
filelayout_choose_commit_list(struct nfs_page *req,
			      struct pnfs_layout_segment *lseg)
889 890 891 892
{
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
	u32 i, j;
	struct list_head *list;
893
	struct nfs4_fl_commit_bucket *buckets;
894

F
Fred Isaman 已提交
895 896 897
	if (fl->commit_through_mds)
		return &NFS_I(req->wb_context->dentry->d_inode)->commit_list;

898 899 900 901 902 903
	/* Note that we are calling nfs4_fl_calc_j_index on each page
	 * that ends up being committed to a data server.  An attractive
	 * alternative is to add a field to nfs_write_data and nfs_page
	 * to store the value calculated in filelayout_write_pagelist
	 * and just use that here.
	 */
904
	j = nfs4_fl_calc_j_index(lseg, req_offset(req));
905
	i = select_bucket_index(fl, j);
906 907
	buckets = FILELAYOUT_FROM_HDR(lseg->pls_layout)->commit_info.buckets;
	list = &buckets[i].written;
908
	if (list_empty(list)) {
F
Fred Isaman 已提交
909 910 911 912
		/* Non-empty buckets hold a reference on the lseg.  That ref
		 * is normally transferred to the COMMIT call and released
		 * there.  It could also be released if the last req is pulled
		 * off due to a rewrite, in which case it will be done in
913
		 * filelayout_clear_request_commit
F
Fred Isaman 已提交
914
		 */
915
		buckets[i].wlseg = get_lseg(lseg);
916
	}
917
	set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
918 919 920
	return list;
}

921 922 923 924 925 926 927 928 929 930
static void
filelayout_mark_request_commit(struct nfs_page *req,
		struct pnfs_layout_segment *lseg)
{
	struct list_head *list;

	list = filelayout_choose_commit_list(req, lseg);
	nfs_request_add_commit_list(req, list);
}

931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
{
	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);

	if (flseg->stripe_type == STRIPE_SPARSE)
		return i;
	else
		return nfs4_fl_calc_ds_index(lseg, i);
}

static struct nfs_fh *
select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
{
	struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);

	if (flseg->stripe_type == STRIPE_SPARSE) {
		if (flseg->num_fh == 1)
			i = 0;
		else if (flseg->num_fh == 0)
			/* Use the MDS OPEN fh set in nfs_read_rpcsetup */
			return NULL;
	}
	return flseg->fh_array[i];
}

956
static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
957 958 959 960 961 962 963 964 965
{
	struct pnfs_layout_segment *lseg = data->lseg;
	struct nfs4_pnfs_ds *ds;
	u32 idx;
	struct nfs_fh *fh;

	idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
	ds = nfs4_fl_prepare_ds(lseg, idx);
	if (!ds) {
966 967
		printk(KERN_ERR "NFS: %s: prepare_ds failed, use MDS\n",
			__func__);
968 969 970
		set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
		set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
		prepare_to_resend_writes(data);
971
		filelayout_commit_release(data);
972 973 974
		return -EAGAIN;
	}
	dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
975
	data->commit_done_cb = filelayout_commit_done_cb;
976 977 978 979
	data->ds_clp = ds->ds_clp;
	fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
	if (fh)
		data->args.fh = fh;
980
	return nfs_initiate_commit(ds->ds_clp->cl_rpcclient, data,
981 982 983
				   &filelayout_commit_call_ops, how);
}

984
static int
985 986
filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max,
		spinlock_t *lock)
987 988 989 990 991 992 993 994 995
{
	struct list_head *src = &bucket->written;
	struct list_head *dst = &bucket->committing;
	struct nfs_page *req, *tmp;
	int ret = 0;

	list_for_each_entry_safe(req, tmp, src, wb_list) {
		if (!nfs_lock_request(req))
			continue;
996 997
		if (cond_resched_lock(lock))
			list_safe_reset_next(req, tmp, wb_list);
998 999 1000 1001 1002 1003 1004
		nfs_request_remove_commit_list(req);
		clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
		nfs_list_add_request(req, dst);
		ret++;
		if (ret == max)
			break;
	}
1005 1006 1007 1008 1009 1010 1011
	if (ret) {
		bucket->clseg = bucket->wlseg;
		if (list_empty(src))
			bucket->wlseg = NULL;
		else
			get_lseg(bucket->clseg);
	}
1012 1013 1014
	return ret;
}

F
Fred Isaman 已提交
1015 1016 1017
/* Move reqs from written to committing lists, returning count of number moved.
 * Note called with i_lock held.
 */
1018 1019
static int filelayout_scan_commit_lists(struct inode *inode, int max,
		spinlock_t *lock)
F
Fred Isaman 已提交
1020
{
1021
	struct nfs4_fl_commit_info *fl_cinfo;
F
Fred Isaman 已提交
1022 1023
	int i, rv = 0, cnt;

1024 1025
	fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info;
	if (fl_cinfo->nbuckets == 0)
1026
		goto out_done;
1027 1028
	for (i = 0; i < fl_cinfo->nbuckets && max != 0; i++) {
		cnt = filelayout_scan_ds_commit_list(&fl_cinfo->buckets[i],
1029
				max, lock);
F
Fred Isaman 已提交
1030 1031 1032
		max -= cnt;
		rv += cnt;
	}
1033
out_done:
F
Fred Isaman 已提交
1034 1035 1036
	return rv;
}

1037 1038
static unsigned int
alloc_ds_commits(struct inode *inode, struct list_head *list)
1039
{
1040 1041
	struct nfs4_fl_commit_info *fl_cinfo;
	struct nfs4_fl_commit_bucket *bucket;
1042
	struct nfs_commit_data *data;
1043
	int i, j;
1044
	unsigned int nreq = 0;
1045

1046 1047 1048 1049
	fl_cinfo = &FILELAYOUT_FROM_HDR(NFS_I(inode)->layout)->commit_info;
	bucket = fl_cinfo->buckets;
	for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
		if (list_empty(&bucket->committing))
1050 1051 1052
			continue;
		data = nfs_commitdata_alloc();
		if (!data)
1053
			break;
1054
		data->ds_commit_index = i;
1055 1056
		data->lseg = bucket->clseg;
		bucket->clseg = NULL;
1057
		list_add(&data->pages, list);
1058
		nreq++;
1059 1060
	}

1061
	/* Clean up on error */
1062 1063
	for (j = i; j < fl_cinfo->nbuckets; j++, bucket++) {
		if (list_empty(&bucket->committing))
1064
			continue;
1065 1066 1067
		nfs_retry_commit(&bucket->committing, bucket->clseg);
		put_lseg(bucket->clseg);
		bucket->clseg = NULL;
1068 1069
	}
	/* Caller will clean up entries put on list */
1070
	return nreq;
1071 1072 1073 1074 1075 1076 1077
}

/* This follows nfs_commit_list pretty closely */
static int
filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
			   int how)
{
1078
	struct nfs_commit_data *data, *tmp;
1079
	LIST_HEAD(list);
1080
	unsigned int nreq = 0;
1081 1082 1083

	if (!list_empty(mds_pages)) {
		data = nfs_commitdata_alloc();
1084 1085 1086 1087 1088 1089
		if (data != NULL) {
			data->lseg = NULL;
			list_add(&data->pages, &list);
			nreq++;
		} else
			nfs_retry_commit(mds_pages, NULL);
1090 1091
	}

1092 1093 1094 1095 1096 1097 1098 1099
	nreq += alloc_ds_commits(inode, &list);

	if (nreq == 0) {
		nfs_commit_clear_lock(NFS_I(inode));
		goto out;
	}

	atomic_add(nreq, &NFS_I(inode)->commits_outstanding);
1100 1101 1102 1103 1104

	list_for_each_entry_safe(data, tmp, &list, pages) {
		list_del_init(&data->pages);
		if (!data->lseg) {
			nfs_init_commit(data, mds_pages, NULL);
1105
			nfs_initiate_commit(NFS_CLIENT(inode), data,
1106 1107
					    data->mds_ops, how);
		} else {
1108 1109 1110 1111
			struct nfs4_fl_commit_info *fl_cinfo;

			fl_cinfo = &FILELAYOUT_FROM_HDR(data->lseg->pls_layout)->commit_info;
			nfs_init_commit(data, &fl_cinfo->buckets[data->ds_commit_index].committing, data->lseg);
1112 1113 1114
			filelayout_initiate_commit(data, how);
		}
	}
1115 1116
out:
	return PNFS_ATTEMPTED;
1117 1118
}

1119 1120 1121 1122 1123 1124
static void
filelayout_free_deveiceid_node(struct nfs4_deviceid_node *d)
{
	nfs4_fl_free_deviceid(container_of(d, struct nfs4_file_layout_dsaddr, id_node));
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
static struct pnfs_layout_hdr *
filelayout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags)
{
	struct nfs4_filelayout *flo;

	flo = kzalloc(sizeof(*flo), gfp_flags);
	return &flo->generic_hdr;
}

static void
filelayout_free_layout_hdr(struct pnfs_layout_hdr *lo)
{
	kfree(FILELAYOUT_FROM_HDR(lo));
}

1140
static struct pnfs_layoutdriver_type filelayout_type = {
1141 1142 1143
	.id			= LAYOUT_NFSV4_1_FILES,
	.name			= "LAYOUT_NFSV4_1_FILES",
	.owner			= THIS_MODULE,
1144 1145
	.alloc_layout_hdr	= filelayout_alloc_layout_hdr,
	.free_layout_hdr	= filelayout_free_layout_hdr,
1146 1147
	.alloc_lseg		= filelayout_alloc_lseg,
	.free_lseg		= filelayout_free_lseg,
1148 1149
	.pg_read_ops		= &filelayout_pg_read_ops,
	.pg_write_ops		= &filelayout_pg_write_ops,
1150 1151
	.mark_request_commit	= filelayout_mark_request_commit,
	.clear_request_commit	= filelayout_clear_request_commit,
F
Fred Isaman 已提交
1152
	.scan_commit_lists	= filelayout_scan_commit_lists,
1153
	.commit_pagelist	= filelayout_commit_pagelist,
A
Andy Adamson 已提交
1154
	.read_pagelist		= filelayout_read_pagelist,
1155
	.write_pagelist		= filelayout_write_pagelist,
1156
	.free_deviceid_node	= filelayout_free_deveiceid_node,
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
};

static int __init nfs4filelayout_init(void)
{
	printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
	       __func__);
	return pnfs_register_layoutdriver(&filelayout_type);
}

static void __exit nfs4filelayout_exit(void)
{
	printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
	       __func__);
	pnfs_unregister_layoutdriver(&filelayout_type);
}

1173 1174
MODULE_ALIAS("nfs-layouttype4-1");

1175 1176
module_init(nfs4filelayout_init);
module_exit(nfs4filelayout_exit);