Whamcloud - gitweb
LU-9491 llite: Handle multi-vec append write correctly 86/27086/3
authorJinshan Xiong <jinshan.xiong@intel.com>
Fri, 12 May 2017 17:13:00 +0000 (13:13 -0400)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 20 May 2017 18:44:13 +0000 (18:44 +0000)
http://review.whamcloud.com/20256 cleaned up LLITE code by using
iov_iter for old and new kernels. However, it introduced a bug to
append write with multiple iovec buffers where each buffer was written
separately therefore each of them saw the same file size.

Append write with multiple buffers has to be performed atomically.

Signed-off-by: Jinshan Xiong <jinshan.xiong@intel.com>
Change-Id: I89d59e924c7029fedc096d724a946763c7f7006d
Reviewed-on: https://review.whamcloud.com/27086
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: James Simmons <uja.ornl@yahoo.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/llite/llite_internal.h
lustre/tests/sanity.sh

index ec51a9a..bab7e68 100644 (file)
@@ -1521,6 +1521,30 @@ __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *iter)
        struct iov_iter i;
        ssize_t bytes = 0;
 
+       /* Since LLITE updates file size at the end of I/O in
+        * vvp_io_commit_write(), append write has to be done in atomic when
+        * there are multiple segments because otherwise each iteration to
+        * __generic_file_aio_write() will see original file size */
+       if (unlikely(iocb->ki_filp->f_flags & O_APPEND && iter->nr_segs > 1)) {
+               struct iovec *iov_copy;
+               int count = 0;
+
+               OBD_ALLOC(iov_copy, sizeof(*iov_copy) * iter->nr_segs);
+               if (!iov_copy)
+                       return -ENOMEM;
+
+               iov_for_each(iov, i, *iter)
+                       iov_copy[count++] = iov;
+
+               bytes = __generic_file_aio_write(iocb, iov_copy, count,
+                                                &iocb->ki_pos);
+               OBD_FREE(iov_copy, sizeof(*iov_copy) * iter->nr_segs);
+
+               if (bytes > 0)
+                       iov_iter_advance(iter, bytes);
+               return bytes;
+       }
+
        iov_for_each(iov, i, *iter) {
                ssize_t res;
 
index 83f8305..7d81fef 100755 (executable)
@@ -9576,19 +9576,24 @@ run_test 130e "FIEMAP (test continuation FIEMAP calls)"
 
 # Test for writev/readv
 test_131a() {
-       rwv -f $DIR/$tfile -w -n 3 524288 1048576 1572864 || \
-       error "writev test failed"
-       rwv -f $DIR/$tfile -r -v -n 2 1572864 1048576 || \
-       error "readv failed"
+       rwv -f $DIR/$tfile -w -n 3 524288 1048576 1572864 ||
+               error "writev test failed"
+       rwv -f $DIR/$tfile -r -v -n 2 1572864 1048576 ||
+               error "readv failed"
        rm -f $DIR/$tfile
 }
 run_test 131a "test iov's crossing stripe boundary for writev/readv"
 
 test_131b() {
-       rwv -f $DIR/$tfile -w -a -n 3 524288 1048576 1572864 || \
-       error "append writev test failed"
-       rwv -f $DIR/$tfile -w -a -n 2 1572864 1048576 || \
-       error "append writev test failed"
+       local fsize=$((524288 + 1048576 + 1572864))
+       rwv -f $DIR/$tfile -w -a -n 3 524288 1048576 1572864 &&
+               $CHECKSTAT -t file $DIR/$tfile -s $fsize ||
+                       error "append writev test failed"
+
+       ((fsize += 1572864 + 1048576))
+       rwv -f $DIR/$tfile -w -a -n 2 1572864 1048576 &&
+               $CHECKSTAT -t file $DIR/$tfile -s $fsize ||
+                       error "append writev test failed"
        rm -f $DIR/$tfile
 }
 run_test 131b "test append writev"