diff options
| author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-07-11 17:53:48 -0400 |
|---|---|---|
| committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2017-07-13 16:57:18 -0400 |
| commit | 301bfa483016d48b7fb9cbad87c0a04a15c25b90 (patch) | |
| tree | 1e86b94a773529cae5a3144e03ff7b35f7673188 | |
| parent | 00422483ad415d6267d36711f0e51f4bbbd653ed (diff) | |
NFS: Don't run wake_up_bit() when nobody is waiting...
"perf lock" shows fairly heavy contention for the bit waitqueue locks
when doing an I/O heavy workload.
Use a bit to tell whether or not there has been contention for a lock
so that we can optimise away the bit waitqueue options in those cases.
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
| -rw-r--r-- | fs/nfs/pagelist.c | 17 | ||||
| -rw-r--r-- | include/linux/nfs_page.h | 2 |
2 files changed, 18 insertions, 1 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 8a23e2b40b04..de9066a92c0d 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -155,9 +155,12 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock) | |||
| 155 | if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) | 155 | if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) |
| 156 | return 0; | 156 | return 0; |
| 157 | 157 | ||
| 158 | if (!nonblock) | 158 | if (!nonblock) { |
| 159 | set_bit(PG_CONTENDED1, &head->wb_flags); | ||
| 160 | smp_mb__after_atomic(); | ||
| 159 | return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, | 161 | return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, |
| 160 | TASK_UNINTERRUPTIBLE); | 162 | TASK_UNINTERRUPTIBLE); |
| 163 | } | ||
| 161 | 164 | ||
| 162 | return -EAGAIN; | 165 | return -EAGAIN; |
| 163 | } | 166 | } |
| @@ -175,6 +178,10 @@ nfs_page_group_lock_wait(struct nfs_page *req) | |||
| 175 | 178 | ||
| 176 | WARN_ON_ONCE(head != head->wb_head); | 179 | WARN_ON_ONCE(head != head->wb_head); |
| 177 | 180 | ||
| 181 | if (!test_bit(PG_HEADLOCK, &head->wb_flags)) | ||
| 182 | return; | ||
| 183 | set_bit(PG_CONTENDED1, &head->wb_flags); | ||
| 184 | smp_mb__after_atomic(); | ||
| 178 | wait_on_bit(&head->wb_flags, PG_HEADLOCK, | 185 | wait_on_bit(&head->wb_flags, PG_HEADLOCK, |
| 179 | TASK_UNINTERRUPTIBLE); | 186 | TASK_UNINTERRUPTIBLE); |
| 180 | } | 187 | } |
| @@ -193,6 +200,8 @@ nfs_page_group_unlock(struct nfs_page *req) | |||
| 193 | smp_mb__before_atomic(); | 200 | smp_mb__before_atomic(); |
| 194 | clear_bit(PG_HEADLOCK, &head->wb_flags); | 201 | clear_bit(PG_HEADLOCK, &head->wb_flags); |
| 195 | smp_mb__after_atomic(); | 202 | smp_mb__after_atomic(); |
| 203 | if (!test_bit(PG_CONTENDED1, &head->wb_flags)) | ||
| 204 | return; | ||
| 196 | wake_up_bit(&head->wb_flags, PG_HEADLOCK); | 205 | wake_up_bit(&head->wb_flags, PG_HEADLOCK); |
| 197 | } | 206 | } |
| 198 | 207 | ||
| @@ -383,6 +392,8 @@ void nfs_unlock_request(struct nfs_page *req) | |||
| 383 | smp_mb__before_atomic(); | 392 | smp_mb__before_atomic(); |
| 384 | clear_bit(PG_BUSY, &req->wb_flags); | 393 | clear_bit(PG_BUSY, &req->wb_flags); |
| 385 | smp_mb__after_atomic(); | 394 | smp_mb__after_atomic(); |
| 395 | if (!test_bit(PG_CONTENDED2, &req->wb_flags)) | ||
| 396 | return; | ||
| 386 | wake_up_bit(&req->wb_flags, PG_BUSY); | 397 | wake_up_bit(&req->wb_flags, PG_BUSY); |
| 387 | } | 398 | } |
| 388 | 399 | ||
| @@ -465,6 +476,10 @@ void nfs_release_request(struct nfs_page *req) | |||
| 465 | int | 476 | int |
| 466 | nfs_wait_on_request(struct nfs_page *req) | 477 | nfs_wait_on_request(struct nfs_page *req) |
| 467 | { | 478 | { |
| 479 | if (!test_bit(PG_BUSY, &req->wb_flags)) | ||
| 480 | return 0; | ||
| 481 | set_bit(PG_CONTENDED2, &req->wb_flags); | ||
| 482 | smp_mb__after_atomic(); | ||
| 468 | return wait_on_bit_io(&req->wb_flags, PG_BUSY, | 483 | return wait_on_bit_io(&req->wb_flags, PG_BUSY, |
| 469 | TASK_UNINTERRUPTIBLE); | 484 | TASK_UNINTERRUPTIBLE); |
| 470 | } | 485 | } |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index abbee2d15dce..d67b67ae6c8b 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -33,6 +33,8 @@ enum { | |||
| 33 | PG_UPTODATE, /* page group sync bit in read path */ | 33 | PG_UPTODATE, /* page group sync bit in read path */ |
| 34 | PG_WB_END, /* page group sync bit in write path */ | 34 | PG_WB_END, /* page group sync bit in write path */ |
| 35 | PG_REMOVE, /* page group sync bit in write path */ | 35 | PG_REMOVE, /* page group sync bit in write path */ |
| 36 | PG_CONTENDED1, /* Is someone waiting for a lock? */ | ||
| 37 | PG_CONTENDED2, /* Is someone waiting for a lock? */ | ||
| 36 | }; | 38 | }; |
| 37 | 39 | ||
| 38 | struct nfs_inode; | 40 | struct nfs_inode; |
