Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] NFS: Make searching and waiting on busy writeback requests more efficient.

Basically copies the VFS's method for tracking writebacks and applies
it to the struct nfs_page.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

+45 -18
+28 -1
fs/nfs/pagelist.c
··· 112 112 } 113 113 114 114 /** 115 + * nfs_set_page_writeback_locked - Lock a request for writeback 116 + * @req: 117 + */ 118 + int nfs_set_page_writeback_locked(struct nfs_page *req) 119 + { 120 + struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); 121 + 122 + if (!nfs_lock_request(req)) 123 + return 0; 124 + radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); 125 + return 1; 126 + } 127 + 128 + /** 129 + * nfs_clear_page_writeback - Unlock request and wake up sleepers 130 + */ 131 + void nfs_clear_page_writeback(struct nfs_page *req) 132 + { 133 + struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode); 134 + 135 + spin_lock(&nfsi->req_lock); 136 + radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK); 137 + spin_unlock(&nfsi->req_lock); 138 + nfs_unlock_request(req); 139 + } 140 + 141 + /** 115 142 * nfs_clear_request - Free up all resources allocated to the request 116 143 * @req: 117 144 * ··· 328 301 if (req->wb_index > idx_end) 329 302 break; 330 303 331 - if (!nfs_lock_request(req)) 304 + if (!nfs_set_page_writeback_locked(req)) 332 305 continue; 333 306 nfs_list_remove_request(req); 334 307 nfs_list_add_request(req, dst);
-3
fs/nfs/read.c
··· 173 173 if (len < PAGE_CACHE_SIZE) 174 174 memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); 175 175 176 - nfs_lock_request(new); 177 176 nfs_list_add_request(new, &one_request); 178 177 nfs_pagein_one(&one_request, inode); 179 178 return 0; ··· 184 185 185 186 nfs_clear_request(req); 186 187 nfs_release_request(req); 187 - nfs_unlock_request(req); 188 188 189 189 dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", 190 190 req->wb_context->dentry->d_inode->i_sb->s_id, ··· 551 553 } 552 554 if (len < PAGE_CACHE_SIZE) 553 555 memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len); 554 - nfs_lock_request(new); 555 556 nfs_list_add_request(new, desc->head); 556 557 return 0; 557 558 }
+9 -10
fs/nfs/write.c
··· 503 503 504 504 spin_lock(&nfsi->req_lock); 505 505 next = idx_start; 506 - while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) { 506 + while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) { 507 507 if (req->wb_index > idx_end) 508 508 break; 509 509 510 510 next = req->wb_index + 1; 511 - if (!NFS_WBACK_BUSY(req)) 512 - continue; 511 + BUG_ON(!NFS_WBACK_BUSY(req)); 513 512 514 513 atomic_inc(&req->wb_count); 515 514 spin_unlock(&nfsi->req_lock); ··· 820 821 #else 821 822 nfs_inode_remove_request(req); 822 823 #endif 823 - nfs_unlock_request(req); 824 + nfs_clear_page_writeback(req); 824 825 } 825 826 826 827 static inline int flush_task_priority(int how) ··· 951 952 nfs_writedata_free(data); 952 953 } 953 954 nfs_mark_request_dirty(req); 954 - nfs_unlock_request(req); 955 + nfs_clear_page_writeback(req); 955 956 return -ENOMEM; 956 957 } 957 958 ··· 1001 1002 struct nfs_page *req = nfs_list_entry(head->next); 1002 1003 nfs_list_remove_request(req); 1003 1004 nfs_mark_request_dirty(req); 1004 - nfs_unlock_request(req); 1005 + nfs_clear_page_writeback(req); 1005 1006 } 1006 1007 return -ENOMEM; 1007 1008 } ··· 1028 1029 req = nfs_list_entry(head->next); 1029 1030 nfs_list_remove_request(req); 1030 1031 nfs_mark_request_dirty(req); 1031 - nfs_unlock_request(req); 1032 + nfs_clear_page_writeback(req); 1032 1033 } 1033 1034 return error; 1034 1035 } ··· 1120 1121 nfs_inode_remove_request(req); 1121 1122 #endif 1122 1123 next: 1123 - nfs_unlock_request(req); 1124 + nfs_clear_page_writeback(req); 1124 1125 } 1125 1126 } 1126 1127 ··· 1277 1278 req = nfs_list_entry(head->next); 1278 1279 nfs_list_remove_request(req); 1279 1280 nfs_mark_request_commit(req); 1280 - nfs_unlock_request(req); 1281 + nfs_clear_page_writeback(req); 1281 1282 } 1282 1283 return -ENOMEM; 1283 1284 } ··· 1323 1324 dprintk(" mismatch\n"); 1324 1325 nfs_mark_request_dirty(req); 1325 1326 next: 1326 - nfs_unlock_request(req); 1327 + nfs_clear_page_writeback(req); 1327 1328 res++; 1328 1329 } 1329 1330 sub_page_state(nr_unstable,res);
+8 -4
include/linux/nfs_page.h
··· 20 20 #include <asm/atomic.h> 21 21 22 22 /* 23 + * Valid flags for the radix tree 24 + */ 25 + #define NFS_PAGE_TAG_WRITEBACK 1 26 + 27 + /* 23 28 * Valid flags for a dirty buffer 24 29 */ 25 30 #define PG_BUSY 0 ··· 67 62 unsigned int); 68 63 extern int nfs_wait_on_request(struct nfs_page *); 69 64 extern void nfs_unlock_request(struct nfs_page *req); 65 + extern int nfs_set_page_writeback_locked(struct nfs_page *req); 66 + extern void nfs_clear_page_writeback(struct nfs_page *req); 67 + 70 68 71 69 /* 72 70 * Lock the page of an asynchronous request without incrementing the wb_count ··· 104 96 { 105 97 if (list_empty(&req->wb_list)) 106 98 return; 107 - if (!NFS_WBACK_BUSY(req)) { 108 - printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n"); 109 - BUG(); 110 - } 111 99 list_del_init(&req->wb_list); 112 100 req->wb_list_head = NULL; 113 101 }