Skip to content

Commit 2cf0f71

Browse files
committed
Merge tag 'nfs-for-6.6-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client fixes from Anna Schumaker: "Various O_DIRECT related fixes from Trond: - Error handling - Locking issues - Use the correct commit info for joining page groups - Fixes for rescheduling IO Sunrpc bad verifier fixes: - Report EINVAL errors from connect() - Revalidate creds that the server has rejected - Revert "SUNRPC: Fail faster on bad verifier" Misc: - Fix pNFS session trunking when MDS=DS - Fix zero-value filehandles for post-open getattr operations - Fix compiler warning about tautological comparisons - Revert 'SUNRPC: clean up integer overflow check' before Trond's fix" * tag 'nfs-for-6.6-2' of git://git.linux-nfs.org/projects/anna/linux-nfs: SUNRPC: Silence compiler complaints about tautological comparisons Revert "SUNRPC: clean up integer overflow check" NFSv4.1: fix zero value filehandle in post open getattr NFSv4.1: fix pnfs MDS=DS session trunking Revert "SUNRPC: Fail faster on bad verifier" SUNRPC: Mark the cred for revalidation if the server rejects it NFS/pNFS: Report EINVAL errors from connect() to the server NFS: More fixes for nfs_direct_write_reschedule_io() NFS: Use the correct commit info in nfs_join_page_group() NFS: More O_DIRECT accounting fixes for error paths NFS: Fix O_DIRECT locking issues NFS: Fix error handling for O_DIRECT write scheduling
2 parents df1c357 + 993b566 commit 2cf0f71

File tree

9 files changed

+132
-61
lines changed

9 files changed

+132
-61
lines changed

fs/nfs/direct.c

Lines changed: 93 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,10 @@ nfs_direct_handle_truncated(struct nfs_direct_req *dreq,
9393
dreq->max_count = dreq_len;
9494
if (dreq->count > dreq_len)
9595
dreq->count = dreq_len;
96-
97-
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags))
98-
dreq->error = hdr->error;
99-
else /* Clear outstanding error if this is EOF */
100-
dreq->error = 0;
10196
}
97+
98+
if (test_bit(NFS_IOHDR_ERROR, &hdr->flags) && !dreq->error)
99+
dreq->error = hdr->error;
102100
}
103101

104102
static void
@@ -120,6 +118,18 @@ nfs_direct_count_bytes(struct nfs_direct_req *dreq,
120118
dreq->count = dreq_len;
121119
}
122120

121+
static void nfs_direct_truncate_request(struct nfs_direct_req *dreq,
122+
struct nfs_page *req)
123+
{
124+
loff_t offs = req_offset(req);
125+
size_t req_start = (size_t)(offs - dreq->io_start);
126+
127+
if (req_start < dreq->max_count)
128+
dreq->max_count = req_start;
129+
if (req_start < dreq->count)
130+
dreq->count = req_start;
131+
}
132+
123133
/**
124134
* nfs_swap_rw - NFS address space operation for swap I/O
125135
* @iocb: target I/O control block
@@ -488,7 +498,9 @@ static void nfs_direct_add_page_head(struct list_head *list,
488498
kref_get(&head->wb_kref);
489499
}
490500

491-
static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
501+
static void nfs_direct_join_group(struct list_head *list,
502+
struct nfs_commit_info *cinfo,
503+
struct inode *inode)
492504
{
493505
struct nfs_page *req, *subreq;
494506

@@ -510,7 +522,7 @@ static void nfs_direct_join_group(struct list_head *list, struct inode *inode)
510522
nfs_release_request(subreq);
511523
}
512524
} while ((subreq = subreq->wb_this_page) != req);
513-
nfs_join_page_group(req, inode);
525+
nfs_join_page_group(req, cinfo, inode);
514526
}
515527
}
516528

@@ -528,48 +540,56 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
528540
static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
529541
{
530542
struct nfs_pageio_descriptor desc;
531-
struct nfs_page *req, *tmp;
543+
struct nfs_page *req;
532544
LIST_HEAD(reqs);
533545
struct nfs_commit_info cinfo;
534-
LIST_HEAD(failed);
535546

536547
nfs_init_cinfo_from_dreq(&cinfo, dreq);
537548
nfs_direct_write_scan_commit_list(dreq->inode, &reqs, &cinfo);
538549

539-
nfs_direct_join_group(&reqs, dreq->inode);
550+
nfs_direct_join_group(&reqs, &cinfo, dreq->inode);
540551

541-
dreq->count = 0;
542-
dreq->max_count = 0;
543-
list_for_each_entry(req, &reqs, wb_list)
544-
dreq->max_count += req->wb_bytes;
545552
nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
546553
get_dreq(dreq);
547554

548555
nfs_pageio_init_write(&desc, dreq->inode, FLUSH_STABLE, false,
549556
&nfs_direct_write_completion_ops);
550557
desc.pg_dreq = dreq;
551558

552-
list_for_each_entry_safe(req, tmp, &reqs, wb_list) {
559+
while (!list_empty(&reqs)) {
560+
req = nfs_list_entry(reqs.next);
553561
/* Bump the transmission count */
554562
req->wb_nio++;
555563
if (!nfs_pageio_add_request(&desc, req)) {
556-
nfs_list_move_request(req, &failed);
557-
spin_lock(&cinfo.inode->i_lock);
558-
dreq->flags = 0;
559-
if (desc.pg_error < 0)
564+
spin_lock(&dreq->lock);
565+
if (dreq->error < 0) {
566+
desc.pg_error = dreq->error;
567+
} else if (desc.pg_error != -EAGAIN) {
568+
dreq->flags = 0;
569+
if (!desc.pg_error)
570+
desc.pg_error = -EIO;
560571
dreq->error = desc.pg_error;
561-
else
562-
dreq->error = -EIO;
563-
spin_unlock(&cinfo.inode->i_lock);
572+
} else
573+
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
574+
spin_unlock(&dreq->lock);
575+
break;
564576
}
565577
nfs_release_request(req);
566578
}
567579
nfs_pageio_complete(&desc);
568580

569-
while (!list_empty(&failed)) {
570-
req = nfs_list_entry(failed.next);
581+
while (!list_empty(&reqs)) {
582+
req = nfs_list_entry(reqs.next);
571583
nfs_list_remove_request(req);
572584
nfs_unlock_and_release_request(req);
585+
if (desc.pg_error == -EAGAIN) {
586+
nfs_mark_request_commit(req, NULL, &cinfo, 0);
587+
} else {
588+
spin_lock(&dreq->lock);
589+
nfs_direct_truncate_request(dreq, req);
590+
spin_unlock(&dreq->lock);
591+
nfs_release_request(req);
592+
}
573593
}
574594

575595
if (put_dreq(dreq))
@@ -589,8 +609,6 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
589609
if (status < 0) {
590610
/* Errors in commit are fatal */
591611
dreq->error = status;
592-
dreq->max_count = 0;
593-
dreq->count = 0;
594612
dreq->flags = NFS_ODIRECT_DONE;
595613
} else {
596614
status = dreq->error;
@@ -601,15 +619,20 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
601619
while (!list_empty(&data->pages)) {
602620
req = nfs_list_entry(data->pages.next);
603621
nfs_list_remove_request(req);
604-
if (status >= 0 && !nfs_write_match_verf(verf, req)) {
622+
if (status < 0) {
623+
spin_lock(&dreq->lock);
624+
nfs_direct_truncate_request(dreq, req);
625+
spin_unlock(&dreq->lock);
626+
nfs_release_request(req);
627+
} else if (!nfs_write_match_verf(verf, req)) {
605628
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
606629
/*
607630
* Despite the reboot, the write was successful,
608631
* so reset wb_nio.
609632
*/
610633
req->wb_nio = 0;
611634
nfs_mark_request_commit(req, NULL, &cinfo, 0);
612-
} else /* Error or match */
635+
} else
613636
nfs_release_request(req);
614637
nfs_unlock_and_release_request(req);
615638
}
@@ -662,6 +685,7 @@ static void nfs_direct_write_clear_reqs(struct nfs_direct_req *dreq)
662685
while (!list_empty(&reqs)) {
663686
req = nfs_list_entry(reqs.next);
664687
nfs_list_remove_request(req);
688+
nfs_direct_truncate_request(dreq, req);
665689
nfs_release_request(req);
666690
nfs_unlock_and_release_request(req);
667691
}
@@ -711,7 +735,8 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
711735
}
712736

713737
nfs_direct_count_bytes(dreq, hdr);
714-
if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags)) {
738+
if (test_bit(NFS_IOHDR_UNSTABLE_WRITES, &hdr->flags) &&
739+
!test_bit(NFS_IOHDR_ERROR, &hdr->flags)) {
715740
if (!dreq->flags)
716741
dreq->flags = NFS_ODIRECT_DO_COMMIT;
717742
flags = dreq->flags;
@@ -755,18 +780,23 @@ static void nfs_write_sync_pgio_error(struct list_head *head, int error)
755780
static void nfs_direct_write_reschedule_io(struct nfs_pgio_header *hdr)
756781
{
757782
struct nfs_direct_req *dreq = hdr->dreq;
783+
struct nfs_page *req;
784+
struct nfs_commit_info cinfo;
758785

759786
trace_nfs_direct_write_reschedule_io(dreq);
760787

788+
nfs_init_cinfo_from_dreq(&cinfo, dreq);
761789
spin_lock(&dreq->lock);
762-
if (dreq->error == 0) {
790+
if (dreq->error == 0)
763791
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
764-
/* fake unstable write to let common nfs resend pages */
765-
hdr->verf.committed = NFS_UNSTABLE;
766-
hdr->good_bytes = hdr->args.offset + hdr->args.count -
767-
hdr->io_start;
768-
}
792+
set_bit(NFS_IOHDR_REDO, &hdr->flags);
769793
spin_unlock(&dreq->lock);
794+
while (!list_empty(&hdr->pages)) {
795+
req = nfs_list_entry(hdr->pages.next);
796+
nfs_list_remove_request(req);
797+
nfs_unlock_request(req);
798+
nfs_mark_request_commit(req, NULL, &cinfo, 0);
799+
}
770800
}
771801

772802
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = {
@@ -794,9 +824,11 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
794824
{
795825
struct nfs_pageio_descriptor desc;
796826
struct inode *inode = dreq->inode;
827+
struct nfs_commit_info cinfo;
797828
ssize_t result = 0;
798829
size_t requested_bytes = 0;
799830
size_t wsize = max_t(size_t, NFS_SERVER(inode)->wsize, PAGE_SIZE);
831+
bool defer = false;
800832

801833
trace_nfs_direct_write_schedule_iovec(dreq);
802834

@@ -837,17 +869,37 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
837869
break;
838870
}
839871

840-
nfs_lock_request(req);
841-
if (!nfs_pageio_add_request(&desc, req)) {
842-
result = desc.pg_error;
843-
nfs_unlock_and_release_request(req);
844-
break;
845-
}
846872
pgbase = 0;
847873
bytes -= req_len;
848874
requested_bytes += req_len;
849875
pos += req_len;
850876
dreq->bytes_left -= req_len;
877+
878+
if (defer) {
879+
nfs_mark_request_commit(req, NULL, &cinfo, 0);
880+
continue;
881+
}
882+
883+
nfs_lock_request(req);
884+
if (nfs_pageio_add_request(&desc, req))
885+
continue;
886+
887+
/* Exit on hard errors */
888+
if (desc.pg_error < 0 && desc.pg_error != -EAGAIN) {
889+
result = desc.pg_error;
890+
nfs_unlock_and_release_request(req);
891+
break;
892+
}
893+
894+
/* If the error is soft, defer remaining requests */
895+
nfs_init_cinfo_from_dreq(&cinfo, dreq);
896+
spin_lock(&dreq->lock);
897+
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
898+
spin_unlock(&dreq->lock);
899+
nfs_unlock_request(req);
900+
nfs_mark_request_commit(req, NULL, &cinfo, 0);
901+
desc.pg_error = 0;
902+
defer = true;
851903
}
852904
nfs_direct_release_pages(pagevec, npages);
853905
kvfree(pagevec);

fs/nfs/flexfilelayout/flexfilelayout.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg,
12351235
case -EPFNOSUPPORT:
12361236
case -EPROTONOSUPPORT:
12371237
case -EOPNOTSUPP:
1238+
case -EINVAL:
12381239
case -ECONNREFUSED:
12391240
case -ECONNRESET:
12401241
case -EHOSTDOWN:

fs/nfs/nfs4client.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
417417
.net = old->cl_net,
418418
.servername = old->cl_hostname,
419419
};
420+
int max_connect = test_bit(NFS_CS_PNFS, &clp->cl_flags) ?
421+
clp->cl_max_connect : old->cl_max_connect;
420422

421423
if (clp->cl_proto != old->cl_proto)
422424
return;
@@ -430,7 +432,7 @@ static void nfs4_add_trunk(struct nfs_client *clp, struct nfs_client *old)
430432
xprt_args.addrlen = clp_salen;
431433

432434
rpc_clnt_add_xprt(old->cl_rpcclient, &xprt_args,
433-
rpc_clnt_test_and_add_xprt, NULL);
435+
rpc_clnt_test_and_add_xprt, &max_connect);
434436
}
435437

436438
/**
@@ -1010,6 +1012,8 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
10101012
__set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
10111013

10121014
__set_bit(NFS_CS_DS, &cl_init.init_flags);
1015+
__set_bit(NFS_CS_PNFS, &cl_init.init_flags);
1016+
cl_init.max_connect = NFS_MAX_TRANSPORTS;
10131017
/*
10141018
* Set an authflavor equual to the MDS value. Use the MDS nfs_client
10151019
* cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS

fs/nfs/nfs4proc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2703,8 +2703,12 @@ static int _nfs4_proc_open(struct nfs4_opendata *data,
27032703
return status;
27042704
}
27052705
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) {
2706+
struct nfs_fh *fh = &o_res->fh;
2707+
27062708
nfs4_sequence_free_slot(&o_res->seq_res);
2707-
nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, NULL);
2709+
if (o_arg->claim == NFS4_OPEN_CLAIM_FH)
2710+
fh = NFS_FH(d_inode(data->dentry));
2711+
nfs4_proc_getattr(server, fh, o_res->f_attr, NULL);
27082712
}
27092713
return 0;
27102714
}

fs/nfs/write.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops;
5959
static const struct nfs_commit_completion_ops nfs_commit_completion_ops;
6060
static const struct nfs_rw_ops nfs_rw_write_ops;
6161
static void nfs_inode_remove_request(struct nfs_page *req);
62-
static void nfs_clear_request_commit(struct nfs_page *req);
62+
static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
63+
struct nfs_page *req);
6364
static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo,
6465
struct inode *inode);
6566
static struct nfs_page *
@@ -502,8 +503,8 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list,
502503
* the (former) group. All subrequests are removed from any write or commit
503504
* lists, unlinked from the group and destroyed.
504505
*/
505-
void
506-
nfs_join_page_group(struct nfs_page *head, struct inode *inode)
506+
void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
507+
struct inode *inode)
507508
{
508509
struct nfs_page *subreq;
509510
struct nfs_page *destroy_list = NULL;
@@ -533,7 +534,7 @@ nfs_join_page_group(struct nfs_page *head, struct inode *inode)
533534
* Commit list removal accounting is done after locks are dropped */
534535
subreq = head;
535536
do {
536-
nfs_clear_request_commit(subreq);
537+
nfs_clear_request_commit(cinfo, subreq);
537538
subreq = subreq->wb_this_page;
538539
} while (subreq != head);
539540

@@ -566,8 +567,10 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
566567
{
567568
struct inode *inode = folio_file_mapping(folio)->host;
568569
struct nfs_page *head;
570+
struct nfs_commit_info cinfo;
569571
int ret;
570572

573+
nfs_init_cinfo_from_inode(&cinfo, inode);
571574
/*
572575
* A reference is taken only on the head request which acts as a
573576
* reference to the whole page group - the group will not be destroyed
@@ -584,7 +587,7 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
584587
return ERR_PTR(ret);
585588
}
586589

587-
nfs_join_page_group(head, inode);
590+
nfs_join_page_group(head, &cinfo, inode);
588591

589592
return head;
590593
}
@@ -955,18 +958,16 @@ static void nfs_folio_clear_commit(struct folio *folio)
955958
}
956959

957960
/* Called holding the request lock on @req */
958-
static void
959-
nfs_clear_request_commit(struct nfs_page *req)
961+
static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
962+
struct nfs_page *req)
960963
{
961964
if (test_bit(PG_CLEAN, &req->wb_flags)) {
962965
struct nfs_open_context *ctx = nfs_req_openctx(req);
963966
struct inode *inode = d_inode(ctx->dentry);
964-
struct nfs_commit_info cinfo;
965967

966-
nfs_init_cinfo_from_inode(&cinfo, inode);
967968
mutex_lock(&NFS_I(inode)->commit_mutex);
968-
if (!pnfs_clear_request_commit(req, &cinfo)) {
969-
nfs_request_remove_commit_list(req, &cinfo);
969+
if (!pnfs_clear_request_commit(req, cinfo)) {
970+
nfs_request_remove_commit_list(req, cinfo);
970971
}
971972
mutex_unlock(&NFS_I(inode)->commit_mutex);
972973
nfs_folio_clear_commit(nfs_page_to_folio(req));

include/linux/nfs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct nfs_client {
4848
#define NFS_CS_NOPING 6 /* - don't ping on connect */
4949
#define NFS_CS_DS 7 /* - Server is a DS */
5050
#define NFS_CS_REUSEPORT 8 /* - reuse src port on reconnect */
51+
#define NFS_CS_PNFS 9 /* - Server used for pnfs */
5152
struct sockaddr_storage cl_addr; /* server identifier */
5253
size_t cl_addrlen;
5354
char * cl_hostname; /* hostname of server */

0 commit comments

Comments
 (0)