nfs: count DIO good bytes correctly with mirroring
When resending to MDS, we might resend multiple mirroring
requests to MDS. As a result, nfs_direct_good_bytes() ends
up counting bytes multiple times, causing application to
get wrong return results in read/write syscalls.
Fix it by tracking start of a dreq and checking the range of
pgio header.
Cc: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 4fad6b7..3715b49 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -88,6 +88,7 @@
ssize_t count, /* bytes actually processed */
bytes_left, /* bytes left to be sent */
+ io_start, /* start of IO */
error; /* any reported error */
struct completion completion; /* wait for i/o completion */
@@ -130,10 +131,11 @@
WARN_ON_ONCE(hdr->pgio_mirror_idx >= dreq->mirror_count);
- dreq->mirrors[hdr->pgio_mirror_idx].count += hdr->good_bytes;
-
- if (hdr->pgio_mirror_idx == 0)
- dreq->count += hdr->good_bytes;
+ count = dreq->mirrors[hdr->pgio_mirror_idx].count;
+ if (count + dreq->io_start < hdr->io_start + hdr->good_bytes) {
+ count = hdr->io_start + hdr->good_bytes - dreq->io_start;
+ dreq->mirrors[hdr->pgio_mirror_idx].count = count;
+ }
/* update the dreq->count by finding the minimum agreed count from all
* mirrors */
@@ -594,6 +596,7 @@
dreq->inode = inode;
dreq->bytes_left = count;
+ dreq->io_start = pos;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx);
if (IS_ERR(l_ctx)) {
@@ -1002,6 +1005,7 @@
dreq->inode = inode;
dreq->bytes_left = count;
+ dreq->io_start = pos;
dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
l_ctx = nfs_get_lock_context(dreq->ctx);
if (IS_ERR(l_ctx)) {