diff options
Diffstat (limited to 'fs/nfs/flexfilelayout/flexfilelayout.c')
-rw-r--r-- | fs/nfs/flexfilelayout/flexfilelayout.c | 192 |
1 files changed, 181 insertions, 11 deletions
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 0f1410c94827..8ac31fbf040a 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c | |||
@@ -412,6 +412,130 @@ ff_layout_get_lseg_count(struct nfs4_ff_layout_segment *fls) | |||
412 | return 1; | 412 | return 1; |
413 | } | 413 | } |
414 | 414 | ||
415 | static void | ||
416 | nfs4_ff_start_busy_timer(struct nfs4_ff_busy_timer *timer) | ||
417 | { | ||
418 | ktime_t old, new; | ||
419 | |||
420 | /* | ||
421 | * Note: careful here! | ||
422 | * If the counter is zero, then we must not increment it until after | ||
423 | * we've set the start_time. | ||
424 | * If we were instead to use atomic_inc_return(), then another | ||
425 | * request might come in, bump, and then call end_busy_timer() | ||
426 | * before we've set the timer->start_time. | ||
427 | */ | ||
428 | old = timer->start_time; | ||
429 | if (atomic_inc_not_zero(&timer->n_ops) == 0) { | ||
430 | new = ktime_get(); | ||
431 | cmpxchg(&timer->start_time.tv64, old.tv64, new.tv64); | ||
432 | atomic_inc(&timer->n_ops); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | static ktime_t | ||
437 | nfs4_ff_end_busy_timer(struct nfs4_ff_busy_timer *timer) | ||
438 | { | ||
439 | ktime_t start, now; | ||
440 | |||
441 | now = ktime_get(); | ||
442 | start.tv64 = xchg(&timer->start_time.tv64, now.tv64); | ||
443 | atomic_dec(&timer->n_ops); | ||
444 | return ktime_sub(now, start); | ||
445 | } | ||
446 | |||
447 | static ktime_t | ||
448 | nfs4_ff_layout_calc_completion_time(struct rpc_task *task) | ||
449 | { | ||
450 | return ktime_sub(ktime_get(), task->tk_start); | ||
451 | } | ||
452 | |||
453 | static void | ||
454 | nfs4_ff_layoutstat_start_io(struct nfs4_ff_layoutstat *layoutstat) | ||
455 | { | ||
456 | nfs4_ff_start_busy_timer(&layoutstat->busy_timer); | ||
457 | } | ||
458 | |||
459 | static void | ||
460 | nfs4_ff_layout_stat_io_update_requested(struct nfs4_ff_layoutstat *layoutstat, | ||
461 | __u64 requested) | ||
462 | { | ||
463 | struct nfs4_ff_io_stat *iostat = &layoutstat->io_stat; | ||
464 | |||
465 | iostat->ops_requested++; | ||
466 | iostat->bytes_requested += requested; | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | nfs4_ff_layout_stat_io_update_completed(struct nfs4_ff_layoutstat *layoutstat, | ||
471 | __u64 requested, | ||
472 | __u64 completed, | ||
473 | ktime_t time_completed) | ||
474 | { | ||
475 | struct nfs4_ff_io_stat *iostat = &layoutstat->io_stat; | ||
476 | ktime_t timer; | ||
477 | |||
478 | iostat->ops_completed++; | ||
479 | iostat->bytes_completed += completed; | ||
480 | iostat->bytes_not_delivered += requested - completed; | ||
481 | |||
482 | timer = nfs4_ff_end_busy_timer(&layoutstat->busy_timer); | ||
483 | iostat->total_busy_time = | ||
484 | ktime_add(iostat->total_busy_time, timer); | ||
485 | iostat->aggregate_completion_time = | ||
486 | ktime_add(iostat->aggregate_completion_time, time_completed); | ||
487 | } | ||
488 | |||
489 | static void | ||
490 | nfs4_ff_layout_stat_io_start_read(struct nfs4_ff_layout_mirror *mirror, | ||
491 | __u64 requested) | ||
492 | { | ||
493 | spin_lock(&mirror->lock); | ||
494 | nfs4_ff_layoutstat_start_io(&mirror->read_stat); | ||
495 | nfs4_ff_layout_stat_io_update_requested(&mirror->read_stat, requested); | ||
496 | spin_unlock(&mirror->lock); | ||
497 | } | ||
498 | |||
499 | static void | ||
500 | nfs4_ff_layout_stat_io_end_read(struct rpc_task *task, | ||
501 | struct nfs4_ff_layout_mirror *mirror, | ||
502 | __u64 requested, | ||
503 | __u64 completed) | ||
504 | { | ||
505 | spin_lock(&mirror->lock); | ||
506 | nfs4_ff_layout_stat_io_update_completed(&mirror->read_stat, | ||
507 | requested, completed, | ||
508 | nfs4_ff_layout_calc_completion_time(task)); | ||
509 | spin_unlock(&mirror->lock); | ||
510 | } | ||
511 | |||
512 | static void | ||
513 | nfs4_ff_layout_stat_io_start_write(struct nfs4_ff_layout_mirror *mirror, | ||
514 | __u64 requested) | ||
515 | { | ||
516 | spin_lock(&mirror->lock); | ||
517 | nfs4_ff_layoutstat_start_io(&mirror->write_stat); | ||
518 | nfs4_ff_layout_stat_io_update_requested(&mirror->write_stat, requested); | ||
519 | spin_unlock(&mirror->lock); | ||
520 | } | ||
521 | |||
522 | static void | ||
523 | nfs4_ff_layout_stat_io_end_write(struct rpc_task *task, | ||
524 | struct nfs4_ff_layout_mirror *mirror, | ||
525 | __u64 requested, | ||
526 | __u64 completed, | ||
527 | enum nfs3_stable_how committed) | ||
528 | { | ||
529 | if (committed == NFS_UNSTABLE) | ||
530 | requested = completed = 0; | ||
531 | |||
532 | spin_lock(&mirror->lock); | ||
533 | nfs4_ff_layout_stat_io_update_completed(&mirror->write_stat, | ||
534 | requested, completed, | ||
535 | nfs4_ff_layout_calc_completion_time(task)); | ||
536 | spin_unlock(&mirror->lock); | ||
537 | } | ||
538 | |||
415 | static int | 539 | static int |
416 | ff_layout_alloc_commit_info(struct pnfs_layout_segment *lseg, | 540 | ff_layout_alloc_commit_info(struct pnfs_layout_segment *lseg, |
417 | struct nfs_commit_info *cinfo, | 541 | struct nfs_commit_info *cinfo, |
@@ -906,6 +1030,10 @@ ff_layout_reset_to_mds(struct pnfs_layout_segment *lseg, int idx) | |||
906 | static int ff_layout_read_prepare_common(struct rpc_task *task, | 1030 | static int ff_layout_read_prepare_common(struct rpc_task *task, |
907 | struct nfs_pgio_header *hdr) | 1031 | struct nfs_pgio_header *hdr) |
908 | { | 1032 | { |
1033 | nfs4_ff_layout_stat_io_start_read( | ||
1034 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | ||
1035 | hdr->args.count); | ||
1036 | |||
909 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { | 1037 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
910 | rpc_exit(task, -EIO); | 1038 | rpc_exit(task, -EIO); |
911 | return -EIO; | 1039 | return -EIO; |
@@ -959,15 +1087,15 @@ static void ff_layout_read_prepare_v4(struct rpc_task *task, void *data) | |||
959 | { | 1087 | { |
960 | struct nfs_pgio_header *hdr = data; | 1088 | struct nfs_pgio_header *hdr = data; |
961 | 1089 | ||
962 | if (ff_layout_read_prepare_common(task, hdr)) | ||
963 | return; | ||
964 | |||
965 | if (ff_layout_setup_sequence(hdr->ds_clp, | 1090 | if (ff_layout_setup_sequence(hdr->ds_clp, |
966 | &hdr->args.seq_args, | 1091 | &hdr->args.seq_args, |
967 | &hdr->res.seq_res, | 1092 | &hdr->res.seq_res, |
968 | task)) | 1093 | task)) |
969 | return; | 1094 | return; |
970 | 1095 | ||
1096 | if (ff_layout_read_prepare_common(task, hdr)) | ||
1097 | return; | ||
1098 | |||
971 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, | 1099 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, |
972 | hdr->args.lock_context, FMODE_READ) == -EIO) | 1100 | hdr->args.lock_context, FMODE_READ) == -EIO) |
973 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | 1101 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ |
@@ -979,6 +1107,10 @@ static void ff_layout_read_call_done(struct rpc_task *task, void *data) | |||
979 | 1107 | ||
980 | dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); | 1108 | dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); |
981 | 1109 | ||
1110 | nfs4_ff_layout_stat_io_end_read(task, | ||
1111 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | ||
1112 | hdr->args.count, hdr->res.count); | ||
1113 | |||
982 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && | 1114 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && |
983 | task->tk_status == 0) { | 1115 | task->tk_status == 0) { |
984 | nfs4_sequence_done(task, &hdr->res.seq_res); | 1116 | nfs4_sequence_done(task, &hdr->res.seq_res); |
@@ -1080,6 +1212,10 @@ static int ff_layout_commit_done_cb(struct rpc_task *task, | |||
1080 | static int ff_layout_write_prepare_common(struct rpc_task *task, | 1212 | static int ff_layout_write_prepare_common(struct rpc_task *task, |
1081 | struct nfs_pgio_header *hdr) | 1213 | struct nfs_pgio_header *hdr) |
1082 | { | 1214 | { |
1215 | nfs4_ff_layout_stat_io_start_write( | ||
1216 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | ||
1217 | hdr->args.count); | ||
1218 | |||
1083 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { | 1219 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
1084 | rpc_exit(task, -EIO); | 1220 | rpc_exit(task, -EIO); |
1085 | return -EIO; | 1221 | return -EIO; |
@@ -1113,15 +1249,15 @@ static void ff_layout_write_prepare_v4(struct rpc_task *task, void *data) | |||
1113 | { | 1249 | { |
1114 | struct nfs_pgio_header *hdr = data; | 1250 | struct nfs_pgio_header *hdr = data; |
1115 | 1251 | ||
1116 | if (ff_layout_write_prepare_common(task, hdr)) | ||
1117 | return; | ||
1118 | |||
1119 | if (ff_layout_setup_sequence(hdr->ds_clp, | 1252 | if (ff_layout_setup_sequence(hdr->ds_clp, |
1120 | &hdr->args.seq_args, | 1253 | &hdr->args.seq_args, |
1121 | &hdr->res.seq_res, | 1254 | &hdr->res.seq_res, |
1122 | task)) | 1255 | task)) |
1123 | return; | 1256 | return; |
1124 | 1257 | ||
1258 | if (ff_layout_write_prepare_common(task, hdr)) | ||
1259 | return; | ||
1260 | |||
1125 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, | 1261 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, |
1126 | hdr->args.lock_context, FMODE_WRITE) == -EIO) | 1262 | hdr->args.lock_context, FMODE_WRITE) == -EIO) |
1127 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | 1263 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ |
@@ -1131,6 +1267,11 @@ static void ff_layout_write_call_done(struct rpc_task *task, void *data) | |||
1131 | { | 1267 | { |
1132 | struct nfs_pgio_header *hdr = data; | 1268 | struct nfs_pgio_header *hdr = data; |
1133 | 1269 | ||
1270 | nfs4_ff_layout_stat_io_end_write(task, | ||
1271 | FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), | ||
1272 | hdr->args.count, hdr->res.count, | ||
1273 | hdr->res.verf->committed); | ||
1274 | |||
1134 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && | 1275 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && |
1135 | task->tk_status == 0) { | 1276 | task->tk_status == 0) { |
1136 | nfs4_sequence_done(task, &hdr->res.seq_res); | 1277 | nfs4_sequence_done(task, &hdr->res.seq_res); |
@@ -1149,8 +1290,17 @@ static void ff_layout_write_count_stats(struct rpc_task *task, void *data) | |||
1149 | &NFS_CLIENT(hdr->inode)->cl_metrics[NFSPROC4_CLNT_WRITE]); | 1290 | &NFS_CLIENT(hdr->inode)->cl_metrics[NFSPROC4_CLNT_WRITE]); |
1150 | } | 1291 | } |
1151 | 1292 | ||
1293 | static void ff_layout_commit_prepare_common(struct rpc_task *task, | ||
1294 | struct nfs_commit_data *cdata) | ||
1295 | { | ||
1296 | nfs4_ff_layout_stat_io_start_write( | ||
1297 | FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index), | ||
1298 | 0); | ||
1299 | } | ||
1300 | |||
1152 | static void ff_layout_commit_prepare_v3(struct rpc_task *task, void *data) | 1301 | static void ff_layout_commit_prepare_v3(struct rpc_task *task, void *data) |
1153 | { | 1302 | { |
1303 | ff_layout_commit_prepare_common(task, data); | ||
1154 | rpc_call_start(task); | 1304 | rpc_call_start(task); |
1155 | } | 1305 | } |
1156 | 1306 | ||
@@ -1158,10 +1308,30 @@ static void ff_layout_commit_prepare_v4(struct rpc_task *task, void *data) | |||
1158 | { | 1308 | { |
1159 | struct nfs_commit_data *wdata = data; | 1309 | struct nfs_commit_data *wdata = data; |
1160 | 1310 | ||
1161 | ff_layout_setup_sequence(wdata->ds_clp, | 1311 | if (ff_layout_setup_sequence(wdata->ds_clp, |
1162 | &wdata->args.seq_args, | 1312 | &wdata->args.seq_args, |
1163 | &wdata->res.seq_res, | 1313 | &wdata->res.seq_res, |
1164 | task); | 1314 | task)) |
1315 | return; | ||
1316 | ff_layout_commit_prepare_common(task, data); | ||
1317 | } | ||
1318 | |||
1319 | static void ff_layout_commit_done(struct rpc_task *task, void *data) | ||
1320 | { | ||
1321 | struct nfs_commit_data *cdata = data; | ||
1322 | struct nfs_page *req; | ||
1323 | __u64 count = 0; | ||
1324 | |||
1325 | if (task->tk_status == 0) { | ||
1326 | list_for_each_entry(req, &cdata->pages, wb_list) | ||
1327 | count += req->wb_bytes; | ||
1328 | } | ||
1329 | |||
1330 | nfs4_ff_layout_stat_io_end_write(task, | ||
1331 | FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index), | ||
1332 | count, count, NFS_FILE_SYNC); | ||
1333 | |||
1334 | pnfs_generic_write_commit_done(task, data); | ||
1165 | } | 1335 | } |
1166 | 1336 | ||
1167 | static void ff_layout_commit_count_stats(struct rpc_task *task, void *data) | 1337 | static void ff_layout_commit_count_stats(struct rpc_task *task, void *data) |
@@ -1202,14 +1372,14 @@ static const struct rpc_call_ops ff_layout_write_call_ops_v4 = { | |||
1202 | 1372 | ||
1203 | static const struct rpc_call_ops ff_layout_commit_call_ops_v3 = { | 1373 | static const struct rpc_call_ops ff_layout_commit_call_ops_v3 = { |
1204 | .rpc_call_prepare = ff_layout_commit_prepare_v3, | 1374 | .rpc_call_prepare = ff_layout_commit_prepare_v3, |
1205 | .rpc_call_done = pnfs_generic_write_commit_done, | 1375 | .rpc_call_done = ff_layout_commit_done, |
1206 | .rpc_count_stats = ff_layout_commit_count_stats, | 1376 | .rpc_count_stats = ff_layout_commit_count_stats, |
1207 | .rpc_release = pnfs_generic_commit_release, | 1377 | .rpc_release = pnfs_generic_commit_release, |
1208 | }; | 1378 | }; |
1209 | 1379 | ||
1210 | static const struct rpc_call_ops ff_layout_commit_call_ops_v4 = { | 1380 | static const struct rpc_call_ops ff_layout_commit_call_ops_v4 = { |
1211 | .rpc_call_prepare = ff_layout_commit_prepare_v4, | 1381 | .rpc_call_prepare = ff_layout_commit_prepare_v4, |
1212 | .rpc_call_done = pnfs_generic_write_commit_done, | 1382 | .rpc_call_done = ff_layout_commit_done, |
1213 | .rpc_count_stats = ff_layout_commit_count_stats, | 1383 | .rpc_count_stats = ff_layout_commit_count_stats, |
1214 | .rpc_release = pnfs_generic_commit_release, | 1384 | .rpc_release = pnfs_generic_commit_release, |
1215 | }; | 1385 | }; |
@@ -1253,7 +1423,6 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr) | |||
1253 | fh = nfs4_ff_layout_select_ds_fh(lseg, idx); | 1423 | fh = nfs4_ff_layout_select_ds_fh(lseg, idx); |
1254 | if (fh) | 1424 | if (fh) |
1255 | hdr->args.fh = fh; | 1425 | hdr->args.fh = fh; |
1256 | |||
1257 | /* | 1426 | /* |
1258 | * Note that if we ever decide to split across DSes, | 1427 | * Note that if we ever decide to split across DSes, |
1259 | * then we may need to handle dense-like offsets. | 1428 | * then we may need to handle dense-like offsets. |
@@ -1382,6 +1551,7 @@ static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how) | |||
1382 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); | 1551 | fh = select_ds_fh_from_commit(lseg, data->ds_commit_index); |
1383 | if (fh) | 1552 | if (fh) |
1384 | data->args.fh = fh; | 1553 | data->args.fh = fh; |
1554 | |||
1385 | return nfs_initiate_commit(ds_clnt, data, ds->ds_clp->rpc_ops, | 1555 | return nfs_initiate_commit(ds_clnt, data, ds->ds_clp->rpc_ops, |
1386 | vers == 3 ? &ff_layout_commit_call_ops_v3 : | 1556 | vers == 3 ? &ff_layout_commit_call_ops_v3 : |
1387 | &ff_layout_commit_call_ops_v4, | 1557 | &ff_layout_commit_call_ops_v4, |