@@ -154,6 +154,14 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
154
154
set_bit (NFS_CONTEXT_ERROR_WRITE , & ctx -> flags );
155
155
}
156
156
157
+ static struct nfs_page *
158
+ nfs_page_private_request (struct page * page )
159
+ {
160
+ if (!PagePrivate (page ))
161
+ return NULL ;
162
+ return (struct nfs_page * )page_private (page );
163
+ }
164
+
157
165
/*
158
166
* nfs_page_find_head_request_locked - find head request associated with @page
159
167
*
@@ -164,11 +172,10 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
164
172
static struct nfs_page *
165
173
nfs_page_find_head_request_locked (struct nfs_inode * nfsi , struct page * page )
166
174
{
167
- struct nfs_page * req = NULL ;
175
+ struct nfs_page * req ;
168
176
169
- if (PagePrivate (page ))
170
- req = (struct nfs_page * )page_private (page );
171
- else if (unlikely (PageSwapCache (page )))
177
+ req = nfs_page_private_request (page );
178
+ if (!req && unlikely (PageSwapCache (page )))
172
179
req = nfs_page_search_commits_for_head_request_locked (nfsi ,
173
180
page );
174
181
@@ -448,31 +455,29 @@ nfs_lock_and_join_requests(struct page *page)
448
455
int ret ;
449
456
450
457
try_again :
451
- if (!(PagePrivate (page ) || PageSwapCache (page )))
452
- return NULL ;
453
- spin_lock (& inode -> i_lock );
454
458
/*
455
459
* A reference is taken only on the head request which acts as a
456
460
* reference to the whole page group - the group will not be destroyed
457
461
* until the head reference is released.
458
462
*/
459
- head = nfs_page_find_head_request_locked (NFS_I (inode ), page );
460
-
461
- if (!head ) {
462
- spin_unlock (& inode -> i_lock );
463
+ head = nfs_page_find_head_request (page );
464
+ if (!head )
463
465
return NULL ;
464
- }
465
466
466
467
/* lock the page head first in order to avoid an ABBA inefficiency */
467
468
if (!nfs_lock_request (head )) {
468
- spin_unlock (& inode -> i_lock );
469
469
ret = nfs_wait_on_request (head );
470
470
nfs_release_request (head );
471
471
if (ret < 0 )
472
472
return ERR_PTR (ret );
473
473
goto try_again ;
474
474
}
475
- spin_unlock (& inode -> i_lock );
475
+
476
+ /* Ensure that nobody removed the request before we locked it */
477
+ if (head != nfs_page_private_request (page ) && !PageSwapCache (page )) {
478
+ nfs_unlock_and_release_request (head );
479
+ goto try_again ;
480
+ }
476
481
477
482
ret = nfs_page_group_lock (head );
478
483
if (ret < 0 ) {
@@ -559,7 +564,7 @@ nfs_lock_and_join_requests(struct page *page)
559
564
return NULL ;
560
565
}
561
566
562
- /* still holds ref on head from nfs_page_find_head_request_locked
567
+ /* still holds ref on head from nfs_page_find_head_request
563
568
* and still has lock on head from lock loop */
564
569
return head ;
565
570
}
0 commit comments