Skip to content

Commit 1f28476

Browse files
author
Trond Myklebust
committed
NFS: Fix O_DIRECT commit verifier handling
Instead of trying to save the commit verifiers and checking them against previous writes, adopt the same strategy as for buffered writes, of just checking the verifiers at commit time. Signed-off-by: Trond Myklebust <[email protected]>
1 parent fb5f7f2 commit 1f28476

File tree

3 files changed

+22
-124
lines changed

3 files changed

+22
-124
lines changed

fs/nfs/direct.c

Lines changed: 13 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ struct nfs_direct_req {
9595
/* for read */
9696
#define NFS_ODIRECT_SHOULD_DIRTY (3) /* dirty user-space page after read */
9797
#define NFS_ODIRECT_DONE INT_MAX /* write verification failed */
98-
struct nfs_writeverf verf; /* unstable write verifier */
9998
};
10099

101100
static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops;
@@ -152,106 +151,6 @@ nfs_direct_count_bytes(struct nfs_direct_req *dreq,
152151
dreq->count = dreq_len;
153152
}
154153

155-
/*
156-
* nfs_direct_select_verf - select the right verifier
157-
* @dreq - direct request possibly spanning multiple servers
158-
* @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs
159-
* @commit_idx - commit bucket index for the DS
160-
*
161-
* returns the correct verifier to use given the role of the server
162-
*/
163-
static struct nfs_writeverf *
164-
nfs_direct_select_verf(struct nfs_direct_req *dreq,
165-
struct nfs_client *ds_clp,
166-
int commit_idx)
167-
{
168-
struct nfs_writeverf *verfp = &dreq->verf;
169-
170-
#ifdef CONFIG_NFS_V4_1
171-
/*
172-
* pNFS is in use, use the DS verf except commit_through_mds is set
173-
* for layout segment where nbuckets is zero.
174-
*/
175-
if (ds_clp && dreq->ds_cinfo.nbuckets > 0) {
176-
if (commit_idx >= 0 && commit_idx < dreq->ds_cinfo.nbuckets)
177-
verfp = &dreq->ds_cinfo.buckets[commit_idx].direct_verf;
178-
else
179-
WARN_ON_ONCE(1);
180-
}
181-
#endif
182-
return verfp;
183-
}
184-
185-
186-
/*
187-
* nfs_direct_set_hdr_verf - set the write/commit verifier
188-
* @dreq - direct request possibly spanning multiple servers
189-
* @hdr - pageio header to validate against previously seen verfs
190-
*
191-
* Set the server's (MDS or DS) "seen" verifier
192-
*/
193-
static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq,
194-
struct nfs_pgio_header *hdr)
195-
{
196-
struct nfs_writeverf *verfp;
197-
198-
verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx);
199-
WARN_ON_ONCE(verfp->committed >= 0);
200-
memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf));
201-
WARN_ON_ONCE(verfp->committed < 0);
202-
}
203-
204-
static int nfs_direct_cmp_verf(const struct nfs_writeverf *v1,
205-
const struct nfs_writeverf *v2)
206-
{
207-
return nfs_write_verifier_cmp(&v1->verifier, &v2->verifier);
208-
}
209-
210-
/*
211-
* nfs_direct_cmp_hdr_verf - compare verifier for pgio header
212-
* @dreq - direct request possibly spanning multiple servers
213-
* @hdr - pageio header to validate against previously seen verf
214-
*
215-
* set the server's "seen" verf if not initialized.
216-
* returns result of comparison between @hdr->verf and the "seen"
217-
* verf of the server used by @hdr (DS or MDS)
218-
*/
219-
static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq,
220-
struct nfs_pgio_header *hdr)
221-
{
222-
struct nfs_writeverf *verfp;
223-
224-
verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, hdr->ds_commit_idx);
225-
if (verfp->committed < 0) {
226-
nfs_direct_set_hdr_verf(dreq, hdr);
227-
return 0;
228-
}
229-
return nfs_direct_cmp_verf(verfp, &hdr->verf);
230-
}
231-
232-
/*
233-
* nfs_direct_cmp_commit_data_verf - compare verifier for commit data
234-
* @dreq - direct request possibly spanning multiple servers
235-
* @data - commit data to validate against previously seen verf
236-
*
237-
* returns result of comparison between @data->verf and the verf of
238-
* the server used by @data (DS or MDS)
239-
*/
240-
static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
241-
struct nfs_commit_data *data)
242-
{
243-
struct nfs_writeverf *verfp;
244-
245-
verfp = nfs_direct_select_verf(dreq, data->ds_clp,
246-
data->ds_commit_index);
247-
248-
/* verifier not set so always fail */
249-
if (verfp->committed < 0 || data->res.verf->committed <= NFS_UNSTABLE)
250-
return 1;
251-
252-
return nfs_direct_cmp_verf(verfp, data->res.verf);
253-
}
254-
255154
/**
256155
* nfs_direct_IO - NFS address space operation for direct I/O
257156
* @iocb: target I/O control block
@@ -307,7 +206,6 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
307206
init_completion(&dreq->completion);
308207
INIT_LIST_HEAD(&dreq->mds_cinfo.list);
309208
pnfs_init_ds_commit_info(&dreq->ds_cinfo);
310-
dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */
311209
INIT_WORK(&dreq->work, nfs_direct_write_schedule_work);
312210
spin_lock_init(&dreq->lock);
313211

@@ -637,7 +535,6 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
637535
dreq->max_count = 0;
638536
list_for_each_entry(req, &reqs, wb_list)
639537
dreq->max_count += req->wb_bytes;
640-
dreq->verf.committed = NFS_INVALID_STABLE_HOW;
641538
nfs_clear_pnfs_ds_commit_verifiers(&dreq->ds_cinfo);
642539
get_dreq(dreq);
643540

@@ -674,6 +571,7 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
674571

675572
static void nfs_direct_commit_complete(struct nfs_commit_data *data)
676573
{
574+
const struct nfs_writeverf *verf = data->res.verf;
677575
struct nfs_direct_req *dreq = data->dreq;
678576
struct nfs_commit_info cinfo;
679577
struct nfs_page *req;
@@ -689,21 +587,19 @@ static void nfs_direct_commit_complete(struct nfs_commit_data *data)
689587
status = dreq->error;
690588

691589
nfs_init_cinfo_from_dreq(&cinfo, dreq);
692-
if (nfs_direct_cmp_commit_data_verf(dreq, data))
693-
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
694590

695591
while (!list_empty(&data->pages)) {
696592
req = nfs_list_entry(data->pages.next);
697593
nfs_list_remove_request(req);
698-
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) {
594+
if (status >= 0 && !nfs_write_match_verf(verf, req)) {
595+
dreq->flags = NFS_ODIRECT_RESCHED_WRITES;
699596
/*
700597
* Despite the reboot, the write was successful,
701598
* so reset wb_nio.
702599
*/
703600
req->wb_nio = 0;
704-
/* Note the rewrite will go through mds */
705601
nfs_mark_request_commit(req, NULL, &cinfo, 0);
706-
} else
602+
} else /* Error or match */
707603
nfs_release_request(req);
708604
nfs_unlock_and_release_request(req);
709605
}
@@ -799,20 +695,15 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr)
799695
}
800696

801697
nfs_direct_count_bytes(dreq, hdr);
802-
if (hdr->good_bytes != 0) {
803-
if (nfs_write_need_commit(hdr)) {
804-
if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES)
805-
request_commit = true;
806-
else if (dreq->flags == 0) {
807-
nfs_direct_set_hdr_verf(dreq, hdr);
808-
request_commit = true;
809-
dreq->flags = NFS_ODIRECT_DO_COMMIT;
810-
} else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) {
811-
request_commit = true;
812-
if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr))
813-
dreq->flags =
814-
NFS_ODIRECT_RESCHED_WRITES;
815-
}
698+
if (hdr->good_bytes != 0 && nfs_write_need_commit(hdr)) {
699+
switch (dreq->flags) {
700+
case 0:
701+
dreq->flags = NFS_ODIRECT_DO_COMMIT;
702+
request_commit = true;
703+
break;
704+
case NFS_ODIRECT_RESCHED_WRITES:
705+
case NFS_ODIRECT_DO_COMMIT:
706+
request_commit = true;
816707
}
817708
}
818709
spin_unlock(&dreq->lock);

fs/nfs/internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,14 @@ nfs_write_verifier_cmp(const struct nfs_write_verifier *v1,
544544
return memcmp(v1->data, v2->data, sizeof(v1->data));
545545
}
546546

547+
static inline bool
548+
nfs_write_match_verf(const struct nfs_writeverf *verf,
549+
struct nfs_page *req)
550+
{
551+
return verf->committed > NFS_UNSTABLE &&
552+
!nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier);
553+
}
554+
547555
/* unlink.c */
548556
extern struct rpc_task *
549557
nfs_async_rename(struct inode *old_dir, struct inode *new_dir,

fs/nfs/write.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,8 +1874,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
18741874

18751875
/* Okay, COMMIT succeeded, apparently. Check the verifier
18761876
* returned by the server against all stored verfs. */
1877-
if (verf->committed > NFS_UNSTABLE &&
1878-
!nfs_write_verifier_cmp(&req->wb_verf, &verf->verifier)) {
1877+
if (nfs_write_match_verf(verf, req)) {
18791878
/* We have a match */
18801879
if (req->wb_page)
18811880
nfs_inode_remove_request(req);

0 commit comments

Comments
 (0)