diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-17 11:59:30 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-20 13:08:26 -0400 |
commit | 3b3be88d67cc17d0f0ab6edaf131516793fc947e (patch) | |
tree | 293bc2bcc7cf7a175786ec33a4e2aff8c5c7ebca | |
parent | 5ae67c4fee869c9b3c87b727a9ea511b6326b834 (diff) |
NFS: Use cond_resched_lock() to reduce latencies in the commit scans
Ensure that we conditionally drop the inode->i_lock when it is safe
to do so in the commit loops.
We do so after locking the nfs_page, but before removing it from the
commit list. We can then use list_safe_reset_next to recover the loop
after the lock is retaken.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 11 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 8 | ||||
-rw-r--r-- | fs/nfs/write.c | 11 |
3 files changed, 20 insertions, 10 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index e0bdbf4fe454..634c0bcb4fd6 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -936,7 +936,8 @@ static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode) | |||
936 | } | 936 | } |
937 | 937 | ||
938 | static int | 938 | static int |
939 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max) | 939 | filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max, |
940 | spinlock_t *lock) | ||
940 | { | 941 | { |
941 | struct list_head *src = &bucket->written; | 942 | struct list_head *src = &bucket->written; |
942 | struct list_head *dst = &bucket->committing; | 943 | struct list_head *dst = &bucket->committing; |
@@ -946,6 +947,8 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max) | |||
946 | list_for_each_entry_safe(req, tmp, src, wb_list) { | 947 | list_for_each_entry_safe(req, tmp, src, wb_list) { |
947 | if (!nfs_lock_request(req)) | 948 | if (!nfs_lock_request(req)) |
948 | continue; | 949 | continue; |
950 | if (cond_resched_lock(lock)) | ||
951 | list_safe_reset_next(req, tmp, wb_list); | ||
949 | nfs_request_remove_commit_list(req); | 952 | nfs_request_remove_commit_list(req); |
950 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 953 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); |
951 | nfs_list_add_request(req, dst); | 954 | nfs_list_add_request(req, dst); |
@@ -959,7 +962,8 @@ filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max) | |||
959 | /* Move reqs from written to committing lists, returning count of number moved. | 962 | /* Move reqs from written to committing lists, returning count of number moved. |
960 | * Note called with i_lock held. | 963 | * Note called with i_lock held. |
961 | */ | 964 | */ |
962 | static int filelayout_scan_commit_lists(struct inode *inode, int max) | 965 | static int filelayout_scan_commit_lists(struct inode *inode, int max, |
966 | spinlock_t *lock) | ||
963 | { | 967 | { |
964 | struct pnfs_layout_segment *lseg; | 968 | struct pnfs_layout_segment *lseg; |
965 | struct nfs4_filelayout_segment *fl; | 969 | struct nfs4_filelayout_segment *fl; |
@@ -972,7 +976,8 @@ static int filelayout_scan_commit_lists(struct inode *inode, int max) | |||
972 | if (fl->commit_through_mds) | 976 | if (fl->commit_through_mds) |
973 | goto out_done; | 977 | goto out_done; |
974 | for (i = 0; i < fl->number_of_buckets && max != 0; i++) { | 978 | for (i = 0; i < fl->number_of_buckets && max != 0; i++) { |
975 | cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], max); | 979 | cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], |
980 | max, lock); | ||
976 | max -= cnt; | 981 | max -= cnt; |
977 | rv += cnt; | 982 | rv += cnt; |
978 | } | 983 | } |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index e98ff3027d3a..07802652f5a3 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -97,7 +97,7 @@ struct pnfs_layoutdriver_type { | |||
97 | void (*mark_request_commit) (struct nfs_page *req, | 97 | void (*mark_request_commit) (struct nfs_page *req, |
98 | struct pnfs_layout_segment *lseg); | 98 | struct pnfs_layout_segment *lseg); |
99 | void (*clear_request_commit) (struct nfs_page *req); | 99 | void (*clear_request_commit) (struct nfs_page *req); |
100 | int (*scan_commit_lists) (struct inode *inode, int max); | 100 | int (*scan_commit_lists) (struct inode *inode, int max, spinlock_t *lock); |
101 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); | 101 | int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); |
102 | 102 | ||
103 | /* | 103 | /* |
@@ -294,14 +294,14 @@ pnfs_clear_request_commit(struct nfs_page *req) | |||
294 | } | 294 | } |
295 | 295 | ||
296 | static inline int | 296 | static inline int |
297 | pnfs_scan_commit_lists(struct inode *inode, int max) | 297 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) |
298 | { | 298 | { |
299 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | 299 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; |
300 | int ret; | 300 | int ret; |
301 | 301 | ||
302 | if (ld == NULL || ld->scan_commit_lists == NULL) | 302 | if (ld == NULL || ld->scan_commit_lists == NULL) |
303 | return 0; | 303 | return 0; |
304 | ret = ld->scan_commit_lists(inode, max); | 304 | ret = ld->scan_commit_lists(inode, max, lock); |
305 | if (ret != 0) | 305 | if (ret != 0) |
306 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); | 306 | set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags); |
307 | return ret; | 307 | return ret; |
@@ -419,7 +419,7 @@ pnfs_clear_request_commit(struct nfs_page *req) | |||
419 | } | 419 | } |
420 | 420 | ||
421 | static inline int | 421 | static inline int |
422 | pnfs_scan_commit_lists(struct inode *inode, int max) | 422 | pnfs_scan_commit_lists(struct inode *inode, int max, spinlock_t *lock) |
423 | { | 423 | { |
424 | return 0; | 424 | return 0; |
425 | } | 425 | } |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 628d9a69d0a2..bd93d40099f9 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -561,7 +561,8 @@ nfs_need_commit(struct nfs_inode *nfsi) | |||
561 | 561 | ||
562 | /* i_lock held by caller */ | 562 | /* i_lock held by caller */ |
563 | static int | 563 | static int |
564 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max) | 564 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max, |
565 | spinlock_t *lock) | ||
565 | { | 566 | { |
566 | struct nfs_page *req, *tmp; | 567 | struct nfs_page *req, *tmp; |
567 | int ret = 0; | 568 | int ret = 0; |
@@ -569,6 +570,8 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max) | |||
569 | list_for_each_entry_safe(req, tmp, src, wb_list) { | 570 | list_for_each_entry_safe(req, tmp, src, wb_list) { |
570 | if (!nfs_lock_request(req)) | 571 | if (!nfs_lock_request(req)) |
571 | continue; | 572 | continue; |
573 | if (cond_resched_lock(lock)) | ||
574 | list_safe_reset_next(req, tmp, wb_list); | ||
572 | nfs_request_remove_commit_list(req); | 575 | nfs_request_remove_commit_list(req); |
573 | nfs_list_add_request(req, dst); | 576 | nfs_list_add_request(req, dst); |
574 | ret++; | 577 | ret++; |
@@ -596,8 +599,10 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst) | |||
596 | if (nfsi->ncommit > 0) { | 599 | if (nfsi->ncommit > 0) { |
597 | const int max = INT_MAX; | 600 | const int max = INT_MAX; |
598 | 601 | ||
599 | ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max); | 602 | ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max, |
600 | ret += pnfs_scan_commit_lists(inode, max - ret); | 603 | &inode->i_lock); |
604 | ret += pnfs_scan_commit_lists(inode, max - ret, | ||
605 | &inode->i_lock); | ||
601 | } | 606 | } |
602 | spin_unlock(&inode->i_lock); | 607 | spin_unlock(&inode->i_lock); |
603 | return ret; | 608 | return ret; |