@@ -149,6 +149,31 @@ static void nfs_io_completion_put(struct nfs_io_completion *ioc)
149
149
kref_put (& ioc -> refcount , nfs_io_completion_release );
150
150
}
151
151
152
+ static void
153
+ nfs_page_set_inode_ref (struct nfs_page * req , struct inode * inode )
154
+ {
155
+ if (!test_and_set_bit (PG_INODE_REF , & req -> wb_flags )) {
156
+ kref_get (& req -> wb_kref );
157
+ atomic_long_inc (& NFS_I (inode )-> nrequests );
158
+ }
159
+ }
160
+
161
+ static int
162
+ nfs_cancel_remove_inode (struct nfs_page * req , struct inode * inode )
163
+ {
164
+ int ret ;
165
+
166
+ if (!test_bit (PG_REMOVE , & req -> wb_flags ))
167
+ return 0 ;
168
+ ret = nfs_page_group_lock (req );
169
+ if (ret )
170
+ return ret ;
171
+ if (test_and_clear_bit (PG_REMOVE , & req -> wb_flags ))
172
+ nfs_page_set_inode_ref (req , inode );
173
+ nfs_page_group_unlock (req );
174
+ return 0 ;
175
+ }
176
+
152
177
static struct nfs_page *
153
178
nfs_page_private_request (struct page * page )
154
179
{
@@ -218,6 +243,36 @@ static struct nfs_page *nfs_page_find_head_request(struct page *page)
218
243
return req ;
219
244
}
220
245
246
+ static struct nfs_page * nfs_find_and_lock_page_request (struct page * page )
247
+ {
248
+ struct inode * inode = page_file_mapping (page )-> host ;
249
+ struct nfs_page * req , * head ;
250
+ int ret ;
251
+
252
+ for (;;) {
253
+ req = nfs_page_find_head_request (page );
254
+ if (!req )
255
+ return req ;
256
+ head = nfs_page_group_lock_head (req );
257
+ if (head != req )
258
+ nfs_release_request (req );
259
+ if (IS_ERR (head ))
260
+ return head ;
261
+ ret = nfs_cancel_remove_inode (head , inode );
262
+ if (ret < 0 ) {
263
+ nfs_unlock_and_release_request (head );
264
+ return ERR_PTR (ret );
265
+ }
266
+ /* Ensure that nobody removed the request before we locked it */
267
+ if (head == nfs_page_private_request (page ))
268
+ break ;
269
+ if (PageSwapCache (page ))
270
+ break ;
271
+ nfs_unlock_and_release_request (head );
272
+ }
273
+ return head ;
274
+ }
275
+
221
276
/* Adjust the file length if we're writing beyond the end */
222
277
static void nfs_grow_file (struct page * page , unsigned int offset , unsigned int count )
223
278
{
@@ -436,65 +491,22 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
436
491
}
437
492
438
493
/*
439
- * nfs_lock_and_join_requests - join all subreqs to the head req and return
440
- * a locked reference, cancelling any pending
441
- * operations for this page.
442
- *
443
- * @page - the page used to lookup the "page group" of nfs_page structures
494
+ * nfs_join_page_group - destroy subrequests of the head req
495
+ * @head: the page used to lookup the "page group" of nfs_page structures
496
+ * @inode: Inode to which the request belongs.
444
497
*
445
498
* This function joins all sub requests to the head request by first
446
499
* locking all requests in the group, cancelling any pending operations
447
500
* and finally updating the head request to cover the whole range covered by
448
501
* the (former) group. All subrequests are removed from any write or commit
449
502
* lists, unlinked from the group and destroyed.
450
- *
451
- * Returns a locked, referenced pointer to the head request - which after
452
- * this call is guaranteed to be the only request associated with the page.
453
- * Returns NULL if no requests are found for @page, or a ERR_PTR if an
454
- * error was encountered.
455
503
*/
456
- static struct nfs_page *
457
- nfs_lock_and_join_requests (struct page * page )
504
+ static void
505
+ nfs_join_page_group (struct nfs_page * head , struct inode * inode )
458
506
{
459
- struct inode * inode = page_file_mapping (page )-> host ;
460
- struct nfs_page * head , * subreq ;
507
+ struct nfs_page * subreq ;
461
508
struct nfs_page * destroy_list = NULL ;
462
509
unsigned int pgbase , off , bytes ;
463
- int ret ;
464
-
465
- try_again :
466
- /*
467
- * A reference is taken only on the head request which acts as a
468
- * reference to the whole page group - the group will not be destroyed
469
- * until the head reference is released.
470
- */
471
- head = nfs_page_find_head_request (page );
472
- if (!head )
473
- return NULL ;
474
-
475
- /* lock the page head first in order to avoid an ABBA inefficiency */
476
- if (!nfs_lock_request (head )) {
477
- ret = nfs_wait_on_request (head );
478
- nfs_release_request (head );
479
- if (ret < 0 )
480
- return ERR_PTR (ret );
481
- goto try_again ;
482
- }
483
-
484
- /* Ensure that nobody removed the request before we locked it */
485
- if (head != nfs_page_private_request (page ) && !PageSwapCache (page )) {
486
- nfs_unlock_and_release_request (head );
487
- goto try_again ;
488
- }
489
-
490
- ret = nfs_page_group_lock (head );
491
- if (ret < 0 )
492
- goto release_request ;
493
-
494
- /* lock each request in the page group */
495
- ret = nfs_page_group_lock_subrequests (head );
496
- if (ret < 0 )
497
- goto release_request ;
498
510
499
511
pgbase = head -> wb_pgbase ;
500
512
bytes = head -> wb_bytes ;
@@ -531,30 +543,50 @@ nfs_lock_and_join_requests(struct page *page)
531
543
head -> wb_this_page = head ;
532
544
}
533
545
534
- /* Postpone destruction of this request */
535
- if (test_and_clear_bit (PG_REMOVE , & head -> wb_flags )) {
536
- set_bit (PG_INODE_REF , & head -> wb_flags );
537
- kref_get (& head -> wb_kref );
538
- atomic_long_inc (& NFS_I (inode )-> nrequests );
539
- }
546
+ nfs_destroy_unlinked_subrequests (destroy_list , head , inode );
547
+ }
540
548
541
- nfs_page_group_unlock (head );
549
+ /*
550
+ * nfs_lock_and_join_requests - join all subreqs to the head req
551
+ * @page: the page used to lookup the "page group" of nfs_page structures
552
+ *
553
+ * This function joins all sub requests to the head request by first
554
+ * locking all requests in the group, cancelling any pending operations
555
+ * and finally updating the head request to cover the whole range covered by
556
+ * the (former) group. All subrequests are removed from any write or commit
557
+ * lists, unlinked from the group and destroyed.
558
+ *
559
+ * Returns a locked, referenced pointer to the head request - which after
560
+ * this call is guaranteed to be the only request associated with the page.
561
+ * Returns NULL if no requests are found for @page, or a ERR_PTR if an
562
+ * error was encountered.
563
+ */
564
+ static struct nfs_page *
565
+ nfs_lock_and_join_requests (struct page * page )
566
+ {
567
+ struct inode * inode = page_file_mapping (page )-> host ;
568
+ struct nfs_page * head ;
569
+ int ret ;
542
570
543
- nfs_destroy_unlinked_subrequests (destroy_list , head , inode );
571
+ /*
572
+ * A reference is taken only on the head request which acts as a
573
+ * reference to the whole page group - the group will not be destroyed
574
+ * until the head reference is released.
575
+ */
576
+ head = nfs_find_and_lock_page_request (page );
577
+ if (IS_ERR_OR_NULL (head ))
578
+ return head ;
544
579
545
- /* Did we lose a race with nfs_inode_remove_request()? */
546
- if (!(PagePrivate (page ) || PageSwapCache (page ))) {
580
+ /* lock each request in the page group */
581
+ ret = nfs_page_group_lock_subrequests (head );
582
+ if (ret < 0 ) {
547
583
nfs_unlock_and_release_request (head );
548
- return NULL ;
584
+ return ERR_PTR ( ret ) ;
549
585
}
550
586
551
- /* still holds ref on head from nfs_page_find_head_request
552
- * and still has lock on head from lock loop */
553
- return head ;
587
+ nfs_join_page_group (head , inode );
554
588
555
- release_request :
556
- nfs_unlock_and_release_request (head );
557
- return ERR_PTR (ret );
589
+ return head ;
558
590
}
559
591
560
592
static void nfs_write_error (struct nfs_page * req , int error )
0 commit comments