filelayout.c 38.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 39 40 41 42
#include "../nfs4session.h"
#include "../internal.h"
#include "../delegation.h"
#include "filelayout.h"
#include "../nfs4trace.h"
43 44 45 46 47 48 49

#define NFSDBG_FACILITY         NFSDBG_PNFS_LD

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

50 51
#define FILELAYOUT_POLL_RETRY_MAX     (15*HZ)

F
Fred Isaman 已提交
52 53 54 55 56
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;
57 58
	u64 stripe_no;
	u32 rem;
F
Fred Isaman 已提交
59 60

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

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

/* 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();
}

87
static void filelayout_reset_write(struct nfs_pgio_header *hdr)
88
{
89
	struct rpc_task *task = &hdr->task;
90 91 92

	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
		dprintk("%s Reset task %5u for i/o through MDS "
93
			"(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
94
			hdr->task.tk_pid,
B
Bryan Schumaker 已提交
95
			hdr->inode->i_sb->s_id,
96
			(unsigned long long)NFS_FILEID(hdr->inode),
97 98
			hdr->args.count,
			(unsigned long long)hdr->args.offset);
99

100
		task->tk_status = pnfs_write_done_resend_to_mds(hdr);
101 102 103
	}
}

104
static void filelayout_reset_read(struct nfs_pgio_header *hdr)
105
{
106
	struct rpc_task *task = &hdr->task;
107 108 109

	if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
		dprintk("%s Reset task %5u for i/o through MDS "
110
			"(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
111
			hdr->task.tk_pid,
B
Bryan Schumaker 已提交
112
			hdr->inode->i_sb->s_id,
113
			(unsigned long long)NFS_FILEID(hdr->inode),
114 115
			hdr->args.count,
			(unsigned long long)hdr->args.offset);
116

117
		task->tk_status = pnfs_read_done_resend_to_mds(hdr);
118 119 120
	}
}

121 122 123 124 125 126 127
static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo)
{
	if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
		return;
	pnfs_return_layout(inode);
}

128 129 130
static int filelayout_async_handle_error(struct rpc_task *task,
					 struct nfs4_state *state,
					 struct nfs_client *clp,
131
					 struct pnfs_layout_segment *lseg)
132
{
133 134
	struct pnfs_layout_hdr *lo = lseg->pls_layout;
	struct inode *inode = lo->plh_inode;
135 136
	struct nfs_server *mds_server = NFS_SERVER(inode);
	struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
A
Andy Adamson 已提交
137
	struct nfs_client *mds_client = mds_server->nfs_client;
138
	struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table;
A
Andy Adamson 已提交
139

140 141 142 143
	if (task->tk_status >= 0)
		return 0;

	switch (task->tk_status) {
A
Andy Adamson 已提交
144 145 146 147
	/* MDS state errors */
	case -NFS4ERR_DELEG_REVOKED:
	case -NFS4ERR_ADMIN_REVOKED:
	case -NFS4ERR_BAD_STATEID:
148 149
		if (state == NULL)
			break;
150
		nfs_remove_bad_delegation(state->inode);
A
Andy Adamson 已提交
151
	case -NFS4ERR_OPENMODE:
152 153
		if (state == NULL)
			break;
154 155
		if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
			goto out_bad_stateid;
A
Andy Adamson 已提交
156 157
		goto wait_on_recovery;
	case -NFS4ERR_EXPIRED:
158 159 160 161
		if (state != NULL) {
			if (nfs4_schedule_stateid_recovery(mds_server, state) < 0)
				goto out_bad_stateid;
		}
A
Andy Adamson 已提交
162 163 164
		nfs4_schedule_lease_recovery(mds_client);
		goto wait_on_recovery;
	/* DS session errors */
165 166 167 168 169 170 171 172 173 174
	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);
175
		nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
176 177 178 179 180
		break;
	case -NFS4ERR_DELAY:
	case -NFS4ERR_GRACE:
		rpc_delay(task, FILELAYOUT_POLL_RETRY_MAX);
		break;
181 182
	case -NFS4ERR_RETRY_UNCACHED_REP:
		break;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	/* Invalidate Layout errors */
	case -NFS4ERR_PNFS_NO_LAYOUT:
	case -ESTALE:           /* mapped NFS4ERR_STALE */
	case -EBADHANDLE:       /* mapped NFS4ERR_BADHANDLE */
	case -EISDIR:           /* mapped NFS4ERR_ISDIR */
	case -NFS4ERR_FHEXPIRED:
	case -NFS4ERR_WRONG_TYPE:
		dprintk("%s Invalid layout error %d\n", __func__,
			task->tk_status);
		/*
		 * Destroy layout so new i/o will get a new layout.
		 * Layout will not be destroyed until all current lseg
		 * references are put. Mark layout as invalid to resend failed
		 * i/o and all i/o waiting on the slot table to the MDS until
		 * layout is destroyed and a new valid layout is obtained.
		 */
199
		pnfs_destroy_layout(NFS_I(inode));
200 201
		rpc_wake_up(&tbl->slot_tbl_waitq);
		goto reset;
202 203 204 205 206 207 208 209 210 211
	/* RPC connection errors */
	case -ECONNREFUSED:
	case -EHOSTDOWN:
	case -EHOSTUNREACH:
	case -ENETUNREACH:
	case -EIO:
	case -ETIMEDOUT:
	case -EPIPE:
		dprintk("%s DS connection error %d\n", __func__,
			task->tk_status);
212
		nfs4_mark_deviceid_unavailable(devid);
213
		set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags);
214
		rpc_wake_up(&tbl->slot_tbl_waitq);
215
		/* fall through */
216
	default:
217
reset:
218
		dprintk("%s Retry through MDS. Error %d\n", __func__,
219
			task->tk_status);
220
		return -NFS4ERR_RESET_TO_MDS;
221
	}
A
Andy Adamson 已提交
222
out:
223 224
	task->tk_status = 0;
	return -EAGAIN;
225 226 227
out_bad_stateid:
	task->tk_status = -EIO;
	return 0;
A
Andy Adamson 已提交
228 229 230 231 232
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;
233 234 235 236 237
}

/* NFS_PROTO call done callback routines */

static int filelayout_read_done_cb(struct rpc_task *task,
238
				struct nfs_pgio_header *hdr)
239
{
240
	int err;
241

242 243 244
	trace_nfs4_pnfs_read(hdr, task->tk_status);
	err = filelayout_async_handle_error(task, hdr->args.context->state,
					    hdr->ds_clp, hdr->lseg);
245

246 247
	switch (err) {
	case -NFS4ERR_RESET_TO_MDS:
248
		filelayout_reset_read(hdr);
249 250
		return task->tk_status;
	case -EAGAIN:
251
		rpc_restart_call_prepare(task);
252 253 254 255 256 257
		return -EAGAIN;
	}

	return 0;
}

A
Andy Adamson 已提交
258 259 260 261 262 263
/*
 * 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
264
filelayout_set_layoutcommit(struct nfs_pgio_header *hdr)
A
Andy Adamson 已提交
265
{
266 267

	if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds ||
268
	    hdr->res.verf->committed == NFS_FILE_SYNC)
A
Andy Adamson 已提交
269 270
		return;

271
	pnfs_set_layoutcommit(hdr);
T
Tom Haynes 已提交
272
	dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino,
273
		(unsigned long) NFS_I(hdr->inode)->layout->plh_lwb);
A
Andy Adamson 已提交
274 275
}

276 277 278 279 280 281 282 283 284 285 286 287
bool
filelayout_test_devid_unavailable(struct nfs4_deviceid_node *node)
{
	return filelayout_test_devid_invalid(node) ||
		nfs4_test_deviceid_unavailable(node);
}

static bool
filelayout_reset_to_mds(struct pnfs_layout_segment *lseg)
{
	struct nfs4_deviceid_node *node = FILELAYOUT_DEVID_NODE(lseg);

288
	return filelayout_test_devid_unavailable(node);
289 290
}

A
Andy Adamson 已提交
291 292 293 294 295 296 297
/*
 * 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)
{
298
	struct nfs_pgio_header *hdr = data;
A
Andy Adamson 已提交
299

300
	if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
301 302 303
		rpc_exit(task, -EIO);
		return;
	}
304
	if (filelayout_reset_to_mds(hdr->lseg)) {
305
		dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
306
		filelayout_reset_read(hdr);
307 308 309
		rpc_exit(task, 0);
		return;
	}
310
	hdr->pgio_done_cb = filelayout_read_done_cb;
311

312 313 314
	if (nfs41_setup_sequence(hdr->ds_clp->cl_session,
			&hdr->args.seq_args,
			&hdr->res.seq_res,
315 316
			task))
		return;
317 318
	if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
			hdr->args.lock_context, FMODE_READ) == -EIO)
319
		rpc_exit(task, -EIO); /* lost lock, terminate I/O */
A
Andy Adamson 已提交
320 321 322 323
}

static void filelayout_read_call_done(struct rpc_task *task, void *data)
{
324
	struct nfs_pgio_header *hdr = data;
A
Andy Adamson 已提交
325 326 327

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

328
	if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
329
	    task->tk_status == 0) {
330
		nfs41_sequence_done(task, &hdr->res.seq_res);
331
		return;
332
	}
333

A
Andy Adamson 已提交
334
	/* Note this may cause RPC to be resent */
335
	hdr->mds_ops->rpc_call_done(task, data);
A
Andy Adamson 已提交
336 337
}

338 339
static void filelayout_read_count_stats(struct rpc_task *task, void *data)
{
340
	struct nfs_pgio_header *hdr = data;
341

342
	rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
343 344
}

A
Andy Adamson 已提交
345 346
static void filelayout_read_release(void *data)
{
347 348
	struct nfs_pgio_header *hdr = data;
	struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout;
A
Andy Adamson 已提交
349

350
	filelayout_fenceme(lo->plh_inode, lo);
351 352
	nfs_put_client(hdr->ds_clp);
	hdr->mds_ops->rpc_release(data);
A
Andy Adamson 已提交
353 354
}

355
static int filelayout_write_done_cb(struct rpc_task *task,
356
				struct nfs_pgio_header *hdr)
357
{
358 359
	int err;

360 361 362
	trace_nfs4_pnfs_write(hdr, task->tk_status);
	err = filelayout_async_handle_error(task, hdr->args.context->state,
					    hdr->ds_clp, hdr->lseg);
363 364 365

	switch (err) {
	case -NFS4ERR_RESET_TO_MDS:
366
		filelayout_reset_write(hdr);
367 368
		return task->tk_status;
	case -EAGAIN:
369
		rpc_restart_call_prepare(task);
370 371 372
		return -EAGAIN;
	}

373
	filelayout_set_layoutcommit(hdr);
374 375 376
	return 0;
}

377
/* Fake up some data that will cause nfs_commit_release to retry the writes. */
378
static void prepare_to_resend_writes(struct nfs_commit_data *data)
379 380 381 382
{
	struct nfs_page *first = nfs_list_entry(data->pages.next);

	data->task.tk_status = 0;
383 384 385
	memcpy(&data->verf.verifier, &first->wb_verf,
	       sizeof(data->verf.verifier));
	data->verf.verifier.data[0]++; /* ensure verifier mismatch */
386 387 388
}

static int filelayout_commit_done_cb(struct rpc_task *task,
389
				     struct nfs_commit_data *data)
390
{
391 392
	int err;

393
	trace_nfs4_pnfs_commit_ds(data, task->tk_status);
394 395 396 397 398 399 400 401 402
	err = filelayout_async_handle_error(task, NULL, data->ds_clp,
					    data->lseg);

	switch (err) {
	case -NFS4ERR_RESET_TO_MDS:
		prepare_to_resend_writes(data);
		return -EAGAIN;
	case -EAGAIN:
		rpc_restart_call_prepare(task);
403 404 405 406 407 408
		return -EAGAIN;
	}

	return 0;
}

409 410
static void filelayout_write_prepare(struct rpc_task *task, void *data)
{
411
	struct nfs_pgio_header *hdr = data;
412

413
	if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) {
414 415 416
		rpc_exit(task, -EIO);
		return;
	}
417
	if (filelayout_reset_to_mds(hdr->lseg)) {
418
		dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid);
419
		filelayout_reset_write(hdr);
420 421 422
		rpc_exit(task, 0);
		return;
	}
423 424 425
	if (nfs41_setup_sequence(hdr->ds_clp->cl_session,
			&hdr->args.seq_args,
			&hdr->res.seq_res,
426 427
			task))
		return;
428 429
	if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
			hdr->args.lock_context, FMODE_WRITE) == -EIO)
430
		rpc_exit(task, -EIO); /* lost lock, terminate I/O */
431 432 433 434
}

static void filelayout_write_call_done(struct rpc_task *task, void *data)
{
435
	struct nfs_pgio_header *hdr = data;
436

437
	if (test_bit(NFS_IOHDR_REDO, &hdr->flags) &&
438
	    task->tk_status == 0) {
439
		nfs41_sequence_done(task, &hdr->res.seq_res);
440
		return;
441
	}
442

443
	/* Note this may cause RPC to be resent */
444
	hdr->mds_ops->rpc_call_done(task, data);
445 446
}

447 448
static void filelayout_write_count_stats(struct rpc_task *task, void *data)
{
449
	struct nfs_pgio_header *hdr = data;
450

451
	rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics);
452 453
}

454 455
static void filelayout_write_release(void *data)
{
456 457
	struct nfs_pgio_header *hdr = data;
	struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout;
458

459
	filelayout_fenceme(lo->plh_inode, lo);
460 461
	nfs_put_client(hdr->ds_clp);
	hdr->mds_ops->rpc_release(data);
462 463
}

464
static void filelayout_commit_prepare(struct rpc_task *task, void *data)
465
{
466
	struct nfs_commit_data *wdata = data;
467

468 469 470 471
	nfs41_setup_sequence(wdata->ds_clp->cl_session,
			&wdata->args.seq_args,
			&wdata->res.seq_res,
			task);
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
}

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;

493
	data->completion_ops->completion(data);
494
	pnfs_put_lseg(data->lseg);
495
	nfs_put_client(data->ds_clp);
496
	nfs_commitdata_release(data);
497 498
}

499
static const struct rpc_call_ops filelayout_read_call_ops = {
A
Andy Adamson 已提交
500 501
	.rpc_call_prepare = filelayout_read_prepare,
	.rpc_call_done = filelayout_read_call_done,
502
	.rpc_count_stats = filelayout_read_count_stats,
A
Andy Adamson 已提交
503 504 505
	.rpc_release = filelayout_read_release,
};

506
static const struct rpc_call_ops filelayout_write_call_ops = {
507 508
	.rpc_call_prepare = filelayout_write_prepare,
	.rpc_call_done = filelayout_write_call_done,
509
	.rpc_count_stats = filelayout_write_count_stats,
510 511 512
	.rpc_release = filelayout_write_release,
};

513
static const struct rpc_call_ops filelayout_commit_call_ops = {
514 515 516
	.rpc_call_prepare = filelayout_commit_prepare,
	.rpc_call_done = filelayout_write_commit_done,
	.rpc_count_stats = filelayout_commit_count_stats,
517 518 519
	.rpc_release = filelayout_commit_release,
};

A
Andy Adamson 已提交
520
static enum pnfs_try_status
521
filelayout_read_pagelist(struct nfs_pgio_header *hdr)
A
Andy Adamson 已提交
522
{
523
	struct pnfs_layout_segment *lseg = hdr->lseg;
A
Andy Adamson 已提交
524
	struct nfs4_pnfs_ds *ds;
525
	struct rpc_clnt *ds_clnt;
526
	loff_t offset = hdr->args.offset;
A
Andy Adamson 已提交
527 528 529 530
	u32 j, idx;
	struct nfs_fh *fh;

	dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n",
531
		__func__, hdr->inode->i_ino,
532
		hdr->args.pgbase, (size_t)hdr->args.count, offset);
A
Andy Adamson 已提交
533 534 535 536 537

	/* 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);
538
	if (!ds)
A
Andy Adamson 已提交
539
		return PNFS_NOT_ATTEMPTED;
540 541 542 543 544

	ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
	if (IS_ERR(ds_clnt))
		return PNFS_NOT_ATTEMPTED;

545 546
	dprintk("%s USE DS: %s cl_count %d\n", __func__,
		ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
A
Andy Adamson 已提交
547 548

	/* No multipath support. Use first DS */
549
	atomic_inc(&ds->ds_clp->cl_count);
550 551
	hdr->ds_clp = ds->ds_clp;
	hdr->ds_idx = idx;
A
Andy Adamson 已提交
552 553
	fh = nfs4_fl_select_ds_fh(lseg, j);
	if (fh)
554
		hdr->args.fh = fh;
A
Andy Adamson 已提交
555

556 557
	hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
	hdr->mds_offset = offset;
A
Andy Adamson 已提交
558 559

	/* Perform an asynchronous read to ds */
560
	nfs_initiate_pgio(ds_clnt, hdr,
561
			    &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN);
A
Andy Adamson 已提交
562 563 564
	return PNFS_ATTEMPTED;
}

565
/* Perform async writes. */
566
static enum pnfs_try_status
567
filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync)
568
{
569
	struct pnfs_layout_segment *lseg = hdr->lseg;
570
	struct nfs4_pnfs_ds *ds;
571
	struct rpc_clnt *ds_clnt;
572
	loff_t offset = hdr->args.offset;
573 574 575 576 577 578 579
	u32 j, idx;
	struct nfs_fh *fh;

	/* 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);
580
	if (!ds)
581
		return PNFS_NOT_ATTEMPTED;
582 583 584 585 586

	ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
	if (IS_ERR(ds_clnt))
		return PNFS_NOT_ATTEMPTED;

587
	dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n",
588
		__func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count,
589
		offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
590

591
	hdr->pgio_done_cb = filelayout_write_done_cb;
592
	atomic_inc(&ds->ds_clp->cl_count);
593 594
	hdr->ds_clp = ds->ds_clp;
	hdr->ds_idx = idx;
595 596
	fh = nfs4_fl_select_ds_fh(lseg, j);
	if (fh)
597 598
		hdr->args.fh = fh;
	hdr->args.offset = filelayout_get_dserver_offset(lseg, offset);
599 600

	/* Perform an asynchronous write */
601
	nfs_initiate_pgio(ds_clnt, hdr,
602 603
				    &filelayout_write_call_ops, sync,
				    RPC_TASK_SOFTCONN);
604
	return PNFS_ATTEMPTED;
605 606
}

607 608 609 610 611 612 613 614 615 616 617 618
/*
 * 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,
619 620
			struct nfs4_deviceid *id,
			gfp_t gfp_flags)
621
{
622
	struct nfs4_deviceid_node *d;
623 624 625 626 627
	struct nfs4_file_layout_dsaddr *dsaddr;
	int status = -EINVAL;

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

628 629 630 631 632 633 634 635
	/* 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;
	}

636
	if (fl->pattern_offset > lgr->range.offset) {
637
		dprintk("%s pattern_offset %lld too large\n",
638 639 640 641
				__func__, fl->pattern_offset);
		goto out;
	}

642
	if (!fl->stripe_unit) {
643
		dprintk("%s Invalid stripe unit (%u)\n",
644 645 646 647 648
			__func__, fl->stripe_unit);
		goto out;
	}

	/* find and reference the deviceid */
649 650
	d = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode)->pnfs_curr_ld,
				   NFS_SERVER(lo->plh_inode)->nfs_client, id);
651
	if (d == NULL) {
652 653
		dsaddr = filelayout_get_device_info(lo->plh_inode, id,
				lo->plh_lc_cred, gfp_flags);
654 655
		if (dsaddr == NULL)
			goto out;
656 657
	} else
		dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
658 659
	/* Found deviceid is unavailable */
	if (filelayout_test_devid_unavailable(&dsaddr->id_node))
660 661
			goto out_put;

662 663
	fl->dsaddr = dsaddr;

664 665
	if (fl->first_stripe_index >= dsaddr->stripe_count) {
		dprintk("%s Bad first_stripe_index %u\n",
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683
				__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;
	}

	status = 0;
out:
	dprintk("--> %s returns %d\n", __func__, status);
	return status;
out_put:
684
	nfs4_fl_put_deviceid(dsaddr);
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
	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,
712 713
			 struct nfs4_deviceid *id,
			 gfp_t gfp_flags)
714
{
715
	struct xdr_stream stream;
716
	struct xdr_buf buf;
717 718
	struct page *scratch;
	__be32 *p;
719 720 721 722 723
	uint32_t nfl_util;
	int i;

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

724
	scratch = alloc_page(gfp_flags);
725 726 727
	if (!scratch)
		return -ENOMEM;

728
	xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len);
729 730 731 732 733 734 735 736
	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;

737 738
	memcpy(id, p, sizeof(*id));
	p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
739
	nfs4_print_deviceid(id);
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

	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);

758 759
	/* Note that a zero value for num_fh is legal for STRIPE_SPARSE.
	 * Futher checking is done in filelayout_check_layout */
760
	if (fl->num_fh >
761
	    max(NFS4_PNFS_MAX_STRIPE_CNT, NFS4_PNFS_MAX_MULTI_CNT))
762 763
		goto out_err;

764
	if (fl->num_fh > 0) {
765
		fl->fh_array = kcalloc(fl->num_fh, sizeof(fl->fh_array[0]),
766 767 768 769
				       gfp_flags);
		if (!fl->fh_array)
			goto out_err;
	}
770 771 772

	for (i = 0; i < fl->num_fh; i++) {
		/* Do we want to use a mempool here? */
773
		fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), gfp_flags);
774 775 776 777 778 779
		if (!fl->fh_array[i])
			goto out_err_free;

		p = xdr_inline_decode(&stream, 4);
		if (unlikely(!p))
			goto out_err_free;
780 781
		fl->fh_array[i]->size = be32_to_cpup(p++);
		if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
782
			printk(KERN_ERR "NFS: Too big fh %d received %d\n",
783
			       i, fl->fh_array[i]->size);
784
			goto out_err_free;
785
		}
786 787 788 789

		p = xdr_inline_decode(&stream, fl->fh_array[i]->size);
		if (unlikely(!p))
			goto out_err_free;
790 791 792 793 794
		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);
	}

795
	__free_page(scratch);
796
	return 0;
797 798 799 800 801 802

out_err_free:
	filelayout_free_fh_array(fl);
out_err:
	__free_page(scratch);
	return -EIO;
803 804
}

805 806 807 808 809 810 811
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);
812 813 814 815 816 817 818 819 820
	/* 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;
	}
821 822 823
	_filelayout_free_lseg(fl);
}

824 825
static int
filelayout_alloc_commit_info(struct pnfs_layout_segment *lseg,
F
Fred Isaman 已提交
826
			     struct nfs_commit_info *cinfo,
827 828 829
			     gfp_t gfp_flags)
{
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
F
Fred Isaman 已提交
830
	struct pnfs_commit_bucket *buckets;
831
	int size, i;
832 833 834

	if (fl->commit_through_mds)
		return 0;
835 836 837 838 839

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

	if (cinfo->ds->nbuckets >= size) {
840 841 842 843 844 845 846 847 848
		/* 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;
	}

F
Fred Isaman 已提交
849
	buckets = kcalloc(size, sizeof(struct pnfs_commit_bucket),
850 851 852
			  gfp_flags);
	if (!buckets)
		return -ENOMEM;
853 854 855
	for (i = 0; i < size; i++) {
		INIT_LIST_HEAD(&buckets[i].written);
		INIT_LIST_HEAD(&buckets[i].committing);
856 857
		/* mark direct verifier as unset */
		buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW;
858
	}
859 860 861 862 863 864 865 866 867

	spin_lock(cinfo->lock);
	if (cinfo->ds->nbuckets >= size)
		goto out;
	for (i = 0; i < cinfo->ds->nbuckets; i++) {
		list_splice(&cinfo->ds->buckets[i].written,
			    &buckets[i].written);
		list_splice(&cinfo->ds->buckets[i].committing,
			    &buckets[i].committing);
868 869
		buckets[i].direct_verf.committed =
			cinfo->ds->buckets[i].direct_verf.committed;
870 871 872 873 874 875 876 877 878
		buckets[i].wlseg = cinfo->ds->buckets[i].wlseg;
		buckets[i].clseg = cinfo->ds->buckets[i].clseg;
	}
	swap(cinfo->ds->buckets, buckets);
	cinfo->ds->nbuckets = size;
out:
	spin_unlock(cinfo->lock);
	kfree(buckets);
	return 0;
879 880
}

881 882
static struct pnfs_layout_segment *
filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
883 884
		      struct nfs4_layoutget_res *lgr,
		      gfp_t gfp_flags)
885 886 887 888 889 890
{
	struct nfs4_filelayout_segment *fl;
	int rc;
	struct nfs4_deviceid id;

	dprintk("--> %s\n", __func__);
891
	fl = kzalloc(sizeof(*fl), gfp_flags);
892 893 894
	if (!fl)
		return NULL;

895 896
	rc = filelayout_decode_layout(layoutid, fl, lgr, &id, gfp_flags);
	if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id, gfp_flags)) {
897 898 899 900 901 902
		_filelayout_free_lseg(fl);
		return NULL;
	}
	return &fl->generic_hdr;
}

903 904 905
/*
 * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
 *
906 907
 * Return 0 if @req cannot be coalesced into @pgio, otherwise return the number
 * of bytes (maximum @req->wb_bytes) that can be coalesced.
908
 */
909
static size_t
910 911 912
filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
		   struct nfs_page *req)
{
913
	unsigned int size;
914
	u64 p_stripe, r_stripe;
915 916 917
	u32 stripe_offset;
	u64 segment_offset = pgio->pg_lseg->pls_range.offset;
	u32 stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
918

919 920 921
	/* calls nfs_generic_pg_test */
	size = pnfs_generic_pg_test(pgio, prev, req);
	if (!size)
922
		return 0;
923

924
	/* see if req and prev are in the same stripe */
925
	if (prev) {
926 927
		p_stripe = (u64)req_offset(prev) - segment_offset;
		r_stripe = (u64)req_offset(req) - segment_offset;
928 929
		do_div(p_stripe, stripe_unit);
		do_div(r_stripe, stripe_unit);
930

931 932 933
		if (p_stripe != r_stripe)
			return 0;
	}
934 935 936 937 938 939 940 941 942

	/* calculate remaining bytes in the current stripe */
	div_u64_rem((u64)req_offset(req) - segment_offset,
			stripe_unit,
			&stripe_offset);
	WARN_ON_ONCE(stripe_offset > stripe_unit);
	if (stripe_offset >= stripe_unit)
		return 0;
	return min(stripe_unit - (unsigned int)stripe_offset, size);
943 944
}

945
static void
946 947 948
filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio,
			struct nfs_page *req)
{
949 950
	if (!pgio->pg_lseg)
		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
951 952 953 954 955 956 957
					   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)
958
		nfs_pageio_reset_read_mds(pgio);
959 960
}

961
static void
962 963 964
filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio,
			 struct nfs_page *req)
{
F
Fred Isaman 已提交
965
	struct nfs_commit_info cinfo;
966 967
	int status;

968 969
	if (!pgio->pg_lseg)
		pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode,
970 971 972 973 974 975 976
					   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)
977
		goto out_mds;
F
Fred Isaman 已提交
978 979
	nfs_init_cinfo(&cinfo, pgio->pg_inode, pgio->pg_dreq);
	status = filelayout_alloc_commit_info(pgio->pg_lseg, &cinfo, GFP_NOFS);
980
	if (status < 0) {
981
		pnfs_put_lseg(pgio->pg_lseg);
982 983 984 985 986 987
		pgio->pg_lseg = NULL;
		goto out_mds;
	}
	return;
out_mds:
	nfs_pageio_reset_write_mds(pgio);
988 989
}

990
static const struct nfs_pageio_ops filelayout_pg_read_ops = {
991
	.pg_init = filelayout_pg_init_read,
992
	.pg_test = filelayout_pg_test,
993
	.pg_doio = pnfs_generic_pg_readpages,
994 995 996
};

static const struct nfs_pageio_ops filelayout_pg_write_ops = {
997
	.pg_init = filelayout_pg_init_write,
998
	.pg_test = filelayout_pg_test,
999
	.pg_doio = pnfs_generic_pg_writepages,
1000 1001
};

1002 1003 1004 1005 1006 1007 1008 1009
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 已提交
1010 1011 1012
/* 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.
 */
1013
static void
F
Fred Isaman 已提交
1014 1015
filelayout_clear_request_commit(struct nfs_page *req,
				struct nfs_commit_info *cinfo)
F
Fred Isaman 已提交
1016
{
1017 1018
	struct pnfs_layout_segment *freeme = NULL;

F
Fred Isaman 已提交
1019
	spin_lock(cinfo->lock);
1020 1021
	if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
		goto out;
F
Fred Isaman 已提交
1022
	cinfo->ds->nwritten--;
F
Fred Isaman 已提交
1023
	if (list_is_singular(&req->wb_list)) {
F
Fred Isaman 已提交
1024
		struct pnfs_commit_bucket *bucket;
F
Fred Isaman 已提交
1025

1026
		bucket = list_first_entry(&req->wb_list,
F
Fred Isaman 已提交
1027
					  struct pnfs_commit_bucket,
1028 1029 1030
					  written);
		freeme = bucket->wlseg;
		bucket->wlseg = NULL;
F
Fred Isaman 已提交
1031
	}
1032
out:
F
Fred Isaman 已提交
1033 1034
	nfs_request_remove_commit_list(req, cinfo);
	spin_unlock(cinfo->lock);
1035
	pnfs_put_lseg(freeme);
F
Fred Isaman 已提交
1036 1037
}

1038 1039 1040 1041 1042
static void
filelayout_mark_request_commit(struct nfs_page *req,
			       struct pnfs_layout_segment *lseg,
			       struct nfs_commit_info *cinfo)

1043 1044 1045 1046
{
	struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
	u32 i, j;
	struct list_head *list;
F
Fred Isaman 已提交
1047
	struct pnfs_commit_bucket *buckets;
1048

1049 1050 1051 1052 1053
	if (fl->commit_through_mds) {
		list = &cinfo->mds->list;
		spin_lock(cinfo->lock);
		goto mds_commit;
	}
F
Fred Isaman 已提交
1054

1055 1056 1057 1058 1059 1060
	/* 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.
	 */
1061
	j = nfs4_fl_calc_j_index(lseg, req_offset(req));
1062
	i = select_bucket_index(fl, j);
1063
	spin_lock(cinfo->lock);
F
Fred Isaman 已提交
1064
	buckets = cinfo->ds->buckets;
1065
	list = &buckets[i].written;
1066
	if (list_empty(list)) {
F
Fred Isaman 已提交
1067 1068 1069 1070
		/* 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
1071
		 * filelayout_clear_request_commit
F
Fred Isaman 已提交
1072
		 */
1073
		buckets[i].wlseg = pnfs_get_lseg(lseg);
1074
	}
1075
	set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
F
Fred Isaman 已提交
1076
	cinfo->ds->nwritten++;
1077

1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
mds_commit:
	/* nfs_request_add_commit_list(). We need to add req to list without
	 * dropping cinfo lock.
	 */
	set_bit(PG_CLEAN, &(req)->wb_flags);
	nfs_list_add_request(req, list);
	cinfo->mds->ncommit++;
	spin_unlock(cinfo->lock);
	if (!cinfo->dreq) {
		inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
		inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
			     BDI_RECLAIMABLE);
		__mark_inode_dirty(req->wb_context->dentry->d_inode,
				   I_DIRTY_DATASYNC);
	}
1093 1094
}

1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
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];
}

1120
static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
1121 1122 1123
{
	struct pnfs_layout_segment *lseg = data->lseg;
	struct nfs4_pnfs_ds *ds;
1124
	struct rpc_clnt *ds_clnt;
1125 1126 1127 1128 1129
	u32 idx;
	struct nfs_fh *fh;

	idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
	ds = nfs4_fl_prepare_ds(lseg, idx);
1130 1131 1132 1133 1134 1135 1136
	if (!ds)
		goto out_err;

	ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, data->inode);
	if (IS_ERR(ds_clnt))
		goto out_err;

1137 1138
	dprintk("%s ino %lu, how %d cl_count %d\n", __func__,
		data->inode->i_ino, how, atomic_read(&ds->ds_clp->cl_count));
1139
	data->commit_done_cb = filelayout_commit_done_cb;
1140
	atomic_inc(&ds->ds_clp->cl_count);
1141 1142 1143 1144
	data->ds_clp = ds->ds_clp;
	fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
	if (fh)
		data->args.fh = fh;
1145
	return nfs_initiate_commit(ds_clnt, data,
1146 1147
				   &filelayout_commit_call_ops, how,
				   RPC_TASK_SOFTCONN);
1148 1149 1150 1151
out_err:
	prepare_to_resend_writes(data);
	filelayout_commit_release(data);
	return -EAGAIN;
1152 1153
}

1154
static int
1155 1156
transfer_commit_list(struct list_head *src, struct list_head *dst,
		     struct nfs_commit_info *cinfo, int max)
1157 1158 1159 1160 1161 1162 1163
{
	struct nfs_page *req, *tmp;
	int ret = 0;

	list_for_each_entry_safe(req, tmp, src, wb_list) {
		if (!nfs_lock_request(req))
			continue;
1164
		kref_get(&req->wb_kref);
F
Fred Isaman 已提交
1165
		if (cond_resched_lock(cinfo->lock))
1166
			list_safe_reset_next(req, tmp, wb_list);
F
Fred Isaman 已提交
1167
		nfs_request_remove_commit_list(req, cinfo);
1168 1169 1170
		clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
		nfs_list_add_request(req, dst);
		ret++;
1171
		if ((ret == max) && !cinfo->dreq)
1172 1173
			break;
	}
1174 1175 1176
	return ret;
}

1177
/* Note called with cinfo->lock held. */
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
static int
filelayout_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
			       struct nfs_commit_info *cinfo,
			       int max)
{
	struct list_head *src = &bucket->written;
	struct list_head *dst = &bucket->committing;
	int ret;

	ret = transfer_commit_list(src, dst, cinfo, max);
1188
	if (ret) {
F
Fred Isaman 已提交
1189 1190
		cinfo->ds->nwritten -= ret;
		cinfo->ds->ncommitting += ret;
1191 1192 1193 1194
		bucket->clseg = bucket->wlseg;
		if (list_empty(src))
			bucket->wlseg = NULL;
		else
1195
			pnfs_get_lseg(bucket->clseg);
1196
	}
1197 1198 1199
	return ret;
}

F
Fred Isaman 已提交
1200
/* Move reqs from written to committing lists, returning count of number moved.
F
Fred Isaman 已提交
1201
 * Note called with cinfo->lock held.
F
Fred Isaman 已提交
1202
 */
F
Fred Isaman 已提交
1203 1204
static int filelayout_scan_commit_lists(struct nfs_commit_info *cinfo,
					int max)
F
Fred Isaman 已提交
1205 1206 1207
{
	int i, rv = 0, cnt;

F
Fred Isaman 已提交
1208 1209 1210
	for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {
		cnt = filelayout_scan_ds_commit_list(&cinfo->ds->buckets[i],
						     cinfo, max);
F
Fred Isaman 已提交
1211 1212 1213 1214 1215 1216
		max -= cnt;
		rv += cnt;
	}
	return rv;
}

1217 1218 1219 1220 1221
/* Pull everything off the committing lists and dump into @dst */
static void filelayout_recover_commit_reqs(struct list_head *dst,
					   struct nfs_commit_info *cinfo)
{
	struct pnfs_commit_bucket *b;
1222
	struct pnfs_layout_segment *freeme;
1223 1224
	int i;

1225
restart:
1226
	spin_lock(cinfo->lock);
1227 1228
	for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
		if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
1229
			freeme = b->wlseg;
1230
			b->wlseg = NULL;
1231 1232 1233
			spin_unlock(cinfo->lock);
			pnfs_put_lseg(freeme);
			goto restart;
1234 1235 1236
		}
	}
	cinfo->ds->nwritten = 0;
1237
	spin_unlock(cinfo->lock);
1238 1239
}

1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
/* filelayout_search_commit_reqs - Search lists in @cinfo for the head reqest
 *				   for @page
 * @cinfo - commit info for current inode
 * @page - page to search for matching head request
 *
 * Returns a the head request if one is found, otherwise returns NULL.
 */
static struct nfs_page *
filelayout_search_commit_reqs(struct nfs_commit_info *cinfo, struct page *page)
{
	struct nfs_page *freq, *t;
	struct pnfs_commit_bucket *b;
	int i;

	/* Linearly search the commit lists for each bucket until a matching
	 * request is found */
	for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
		list_for_each_entry_safe(freq, t, &b->written, wb_list) {
			if (freq->wb_page == page)
				return freq->wb_head;
		}
		list_for_each_entry_safe(freq, t, &b->committing, wb_list) {
			if (freq->wb_page == page)
				return freq->wb_head;
		}
	}

	return NULL;
}

1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
static void filelayout_retry_commit(struct nfs_commit_info *cinfo, int idx)
{
	struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds;
	struct pnfs_commit_bucket *bucket = fl_cinfo->buckets;
	struct pnfs_layout_segment *freeme;
	int i;

	for (i = idx; i < fl_cinfo->nbuckets; i++, bucket++) {
		if (list_empty(&bucket->committing))
			continue;
		nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo);
		spin_lock(cinfo->lock);
		freeme = bucket->clseg;
		bucket->clseg = NULL;
		spin_unlock(cinfo->lock);
		pnfs_put_lseg(freeme);
	}
}

1289
static unsigned int
F
Fred Isaman 已提交
1290
alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list)
1291
{
F
Fred Isaman 已提交
1292 1293
	struct pnfs_ds_commit_info *fl_cinfo;
	struct pnfs_commit_bucket *bucket;
1294
	struct nfs_commit_data *data;
1295
	int i;
1296
	unsigned int nreq = 0;
1297

F
Fred Isaman 已提交
1298
	fl_cinfo = cinfo->ds;
1299 1300 1301
	bucket = fl_cinfo->buckets;
	for (i = 0; i < fl_cinfo->nbuckets; i++, bucket++) {
		if (list_empty(&bucket->committing))
1302 1303 1304
			continue;
		data = nfs_commitdata_alloc();
		if (!data)
1305
			break;
1306
		data->ds_commit_index = i;
1307
		spin_lock(cinfo->lock);
1308 1309
		data->lseg = bucket->clseg;
		bucket->clseg = NULL;
1310
		spin_unlock(cinfo->lock);
1311
		list_add(&data->pages, list);
1312
		nreq++;
1313 1314
	}

1315
	/* Clean up on error */
1316
	filelayout_retry_commit(cinfo, i);
1317
	/* Caller will clean up entries put on list */
1318
	return nreq;
1319 1320 1321 1322 1323
}

/* This follows nfs_commit_list pretty closely */
static int
filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages,
F
Fred Isaman 已提交
1324
			   int how, struct nfs_commit_info *cinfo)
1325
{
1326
	struct nfs_commit_data *data, *tmp;
1327
	LIST_HEAD(list);
1328
	unsigned int nreq = 0;
1329 1330 1331

	if (!list_empty(mds_pages)) {
		data = nfs_commitdata_alloc();
1332 1333 1334 1335
		if (data != NULL) {
			data->lseg = NULL;
			list_add(&data->pages, &list);
			nreq++;
1336
		} else {
F
Fred Isaman 已提交
1337
			nfs_retry_commit(mds_pages, NULL, cinfo);
1338 1339 1340 1341
			filelayout_retry_commit(cinfo, 0);
			cinfo->completion_ops->error_cleanup(NFS_I(inode));
			return -ENOMEM;
		}
1342 1343
	}

F
Fred Isaman 已提交
1344
	nreq += alloc_ds_commits(cinfo, &list);
1345 1346

	if (nreq == 0) {
1347
		cinfo->completion_ops->error_cleanup(NFS_I(inode));
1348 1349 1350
		goto out;
	}

F
Fred Isaman 已提交
1351
	atomic_add(nreq, &cinfo->mds->rpcs_out);
1352 1353 1354 1355

	list_for_each_entry_safe(data, tmp, &list, pages) {
		list_del_init(&data->pages);
		if (!data->lseg) {
1356
			nfs_init_commit(data, mds_pages, NULL, cinfo);
1357
			nfs_initiate_commit(NFS_CLIENT(inode), data,
1358
					    data->mds_ops, how, 0);
1359
		} else {
F
Fred Isaman 已提交
1360
			struct pnfs_commit_bucket *buckets;
1361

F
Fred Isaman 已提交
1362
			buckets = cinfo->ds->buckets;
1363
			nfs_init_commit(data, &buckets[data->ds_commit_index].committing, data->lseg, cinfo);
1364 1365 1366
			filelayout_initiate_commit(data, how);
		}
	}
1367
out:
F
Fred Isaman 已提交
1368
	cinfo->ds->ncommitting = 0;
1369
	return PNFS_ATTEMPTED;
1370 1371
}

1372 1373 1374 1375 1376 1377
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));
}

1378 1379 1380 1381 1382 1383
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);
1384
	return flo != NULL ? &flo->generic_hdr : NULL;
1385 1386 1387 1388 1389 1390 1391 1392
}

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

F
Fred Isaman 已提交
1393 1394 1395
static struct pnfs_ds_commit_info *
filelayout_get_ds_info(struct inode *inode)
{
1396 1397 1398 1399 1400 1401
	struct pnfs_layout_hdr *layout = NFS_I(inode)->layout;

	if (layout == NULL)
		return NULL;
	else
		return &FILELAYOUT_FROM_HDR(layout)->commit_info;
F
Fred Isaman 已提交
1402 1403
}

1404
static struct pnfs_layoutdriver_type filelayout_type = {
1405 1406 1407
	.id			= LAYOUT_NFSV4_1_FILES,
	.name			= "LAYOUT_NFSV4_1_FILES",
	.owner			= THIS_MODULE,
1408 1409
	.alloc_layout_hdr	= filelayout_alloc_layout_hdr,
	.free_layout_hdr	= filelayout_free_layout_hdr,
1410 1411
	.alloc_lseg		= filelayout_alloc_lseg,
	.free_lseg		= filelayout_free_lseg,
1412 1413
	.pg_read_ops		= &filelayout_pg_read_ops,
	.pg_write_ops		= &filelayout_pg_write_ops,
F
Fred Isaman 已提交
1414
	.get_ds_info		= &filelayout_get_ds_info,
1415 1416
	.mark_request_commit	= filelayout_mark_request_commit,
	.clear_request_commit	= filelayout_clear_request_commit,
F
Fred Isaman 已提交
1417
	.scan_commit_lists	= filelayout_scan_commit_lists,
1418
	.recover_commit_reqs	= filelayout_recover_commit_reqs,
1419
	.search_commit_reqs	= filelayout_search_commit_reqs,
1420
	.commit_pagelist	= filelayout_commit_pagelist,
A
Andy Adamson 已提交
1421
	.read_pagelist		= filelayout_read_pagelist,
1422
	.write_pagelist		= filelayout_write_pagelist,
1423
	.free_deviceid_node	= filelayout_free_deveiceid_node,
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
};

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);
}

1440 1441
MODULE_ALIAS("nfs-layouttype4-1");

1442 1443
module_init(nfs4filelayout_init);
module_exit(nfs4filelayout_exit);