3604df
From dd56ebdefdc8e3d0fe1bbeea6185b72ba0e57871 Mon Sep 17 00:00:00 2001
3604df
From: Krutika Dhananjay <kdhananj@redhat.com>
3604df
Date: Mon, 17 Oct 2016 15:13:28 +0530
3604df
Subject: [PATCH 141/141] compound fops: Fix file corruption issue
3604df
3604df
        Backport of: http://review.gluster.org/#/c/15654/
3604df
3604df
1. Address of a local variable @args is copied into state->req
3604df
in server3_3_compound (). But even after the function has gone out of
3604df
scope, in server_compound_resume () this pointer is accessed and
3604df
dereferenced. This patch fixes that.
3604df
3604df
2. Compound fops, by virtue of NOT having a vector sizer (like the one
3604df
writev has), ends up having both the header and the data (in case one of
3604df
its member fops is WRITEV) in the same hdr_iobuf. This buffer was not
3604df
being preserved through the lifetime of the compound fop, causing it to
3604df
be overwritten by a parallel write fop, even when the writev associated
3604df
with the currently executing compound fop is yet to hit the desk, thereby
3604df
corrupting the file's data. This is fixed by associating the hdr_iobuf with
3604df
the iobref so its memory remains valid through the lifetime of the fop.
3604df
3604df
3. Also fixed a use-after-free bug in protocol/client in compound fops cbk,
3604df
missed by Linux but caught by NetBSD.
3604df
3604df
Finally, big thanks to Pranith Kumar K and Raghavendra Gowdappa for their
3604df
help in debugging this file corruption issue.
3604df
3604df
Change-Id: I0e926dc84b7cc8b9b34b7433ed392516ecdd44bd
3604df
BUG: 1379919
3604df
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/87999
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
Tested-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 rpc/rpc-lib/src/rpc-transport.c               |    6 +---
3604df
 rpc/rpc-lib/src/rpc-transport.h               |    1 -
3604df
 rpc/rpc-lib/src/rpcsvc.c                      |    6 ----
3604df
 rpc/rpc-lib/src/rpcsvc.h                      |    3 --
3604df
 tests/basic/afr/compounded-write-txns.t       |   37 +++++++++++++++++++++++++
3604df
 xlators/protocol/client/src/client-rpc-fops.c |    9 +++---
3604df
 xlators/protocol/server/src/server-rpc-fops.c |    4 +-
3604df
 xlators/protocol/server/src/server.h          |    2 +-
3604df
 8 files changed, 46 insertions(+), 22 deletions(-)
3604df
 create mode 100644 tests/basic/afr/compounded-write-txns.t
3604df
3604df
diff --git a/rpc/rpc-lib/src/rpc-transport.c b/rpc/rpc-lib/src/rpc-transport.c
3604df
index a74aa22..f3ebe2d 100644
3604df
--- a/rpc/rpc-lib/src/rpc-transport.c
3604df
+++ b/rpc/rpc-lib/src/rpc-transport.c
3604df
@@ -123,10 +123,6 @@ rpc_transport_pollin_destroy (rpc_transport_pollin_t *pollin)
3604df
                 iobref_unref (pollin->iobref);
3604df
         }
3604df
 
3604df
-        if (pollin->hdr_iobuf) {
3604df
-                iobuf_unref (pollin->hdr_iobuf);
3604df
-        }
3604df
-
3604df
         if (pollin->private) {
3604df
                 /* */
3604df
                 GF_FREE (pollin->private);
3604df
@@ -158,7 +154,7 @@ rpc_transport_pollin_alloc (rpc_transport_t *this, struct iovec *vector,
3604df
         msg->iobref = iobref_ref (iobref);
3604df
         msg->private = private;
3604df
         if (hdr_iobuf)
3604df
-                msg->hdr_iobuf = iobuf_ref (hdr_iobuf);
3604df
+                iobref_add (iobref, hdr_iobuf);
3604df
 
3604df
 out:
3604df
         return msg;
3604df
diff --git a/rpc/rpc-lib/src/rpc-transport.h b/rpc/rpc-lib/src/rpc-transport.h
3604df
index 227911a..1d4b444 100644
3604df
--- a/rpc/rpc-lib/src/rpc-transport.h
3604df
+++ b/rpc/rpc-lib/src/rpc-transport.h
3604df
@@ -163,7 +163,6 @@ struct rpc_transport_pollin {
3604df
         char vectored;
3604df
         void *private;
3604df
         struct iobref *iobref;
3604df
-        struct iobuf  *hdr_iobuf;
3604df
         char is_reply;
3604df
 };
3604df
 typedef struct rpc_transport_pollin rpc_transport_pollin_t;
3604df
diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c
3604df
index 05d2696..2a2ca64 100644
3604df
--- a/rpc/rpc-lib/src/rpcsvc.c
3604df
+++ b/rpc/rpc-lib/src/rpcsvc.c
3604df
@@ -373,9 +373,6 @@ rpcsvc_request_destroy (rpcsvc_request_t *req)
3604df
                 iobref_unref (req->iobref);
3604df
         }
3604df
 
3604df
-        if (req->hdr_iobuf)
3604df
-                iobuf_unref (req->hdr_iobuf);
3604df
-
3604df
         /* This marks the "end" of an RPC request. Reply is
3604df
            completely written to the socket and is on the way
3604df
            to the client. It is time to decrement the
3604df
@@ -690,9 +687,6 @@ rpcsvc_handle_rpc_call (rpcsvc_t *svc, rpc_transport_t *trans,
3604df
                 }
3604df
 
3604df
                 if (req->synctask) {
3604df
-                        if (msg->hdr_iobuf)
3604df
-                                req->hdr_iobuf = iobuf_ref (msg->hdr_iobuf);
3604df
-
3604df
                         ret = synctask_new (THIS->ctx->env,
3604df
                                             (synctask_fn_t) actor_fn,
3604df
                                             rpcsvc_check_and_reply_error, NULL,
3604df
diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h
3604df
index 02e467e..63a6dad 100644
3604df
--- a/rpc/rpc-lib/src/rpcsvc.h
3604df
+++ b/rpc/rpc-lib/src/rpcsvc.h
3604df
@@ -244,9 +244,6 @@ struct rpcsvc_request {
3604df
         /* Container for transport to store request-specific item */
3604df
         void                    *trans_private;
3604df
 
3604df
-        /* we need to ref the 'iobuf' in case of 'synctasking' it */
3604df
-        struct iobuf            *hdr_iobuf;
3604df
-
3604df
         /* pointer to cached reply for use in DRC */
3604df
         drc_cached_op_t         *reply;
3604df
 };
3604df
diff --git a/tests/basic/afr/compounded-write-txns.t b/tests/basic/afr/compounded-write-txns.t
3604df
new file mode 100644
3604df
index 0000000..7cecd87
3604df
--- /dev/null
3604df
+++ b/tests/basic/afr/compounded-write-txns.t
3604df
@@ -0,0 +1,37 @@
3604df
+#!/bin/bash
3604df
+. $(dirname $0)/../../include.rc
3604df
+. $(dirname $0)/../../volume.rc
3604df
+
3604df
+cleanup
3604df
+
3604df
+TEST glusterd
3604df
+TEST pidof glusterd
3604df
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2}
3604df
+TEST $CLI volume set $V0 write-behind off
3604df
+TEST $CLI volume set $V0 client-io-threads off
3604df
+TEST $CLI volume start $V0
3604df
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
3604df
+
3604df
+# Create and generate data into a src file
3604df
+
3604df
+TEST `printf %1024s |tr " " "1" > /tmp/source`
3604df
+TEST `printf %1024s |tr " " "2" >> /tmp/source`
3604df
+
3604df
+TEST dd if=/tmp/source of=$M0/file bs=1024 count=2 2>/dev/null
3604df
+md5sum_file=$(md5sum $M0/file | awk '{print $1}')
3604df
+
3604df
+TEST $CLI volume set $V0 cluster.use-compound-fops on
3604df
+
3604df
+TEST dd if=$M0/file of=$M0/file-copy bs=1024 count=2 2>/dev/null
3604df
+
3604df
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
3604df
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
3604df
+
3604df
+EXPECT "$md5sum_file" echo `md5sum $M0/file-copy | awk '{print $1}'`
3604df
+
3604df
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
3604df
+TEST $CLI volume stop $V0
3604df
+TEST $CLI volume delete $V0
3604df
+
3604df
+TEST rm -f /tmp/source
3604df
+cleanup
3604df
diff --git a/xlators/protocol/client/src/client-rpc-fops.c b/xlators/protocol/client/src/client-rpc-fops.c
3604df
index c122941..8085aec 100644
3604df
--- a/xlators/protocol/client/src/client-rpc-fops.c
3604df
+++ b/xlators/protocol/client/src/client-rpc-fops.c
3604df
@@ -3166,7 +3166,8 @@ client3_3_compound_cbk (struct rpc_req *req, struct iovec *iov, int count,
3604df
         dict_t                  *xdata           = NULL;
3604df
         clnt_local_t            *local           = NULL;
3604df
         int                     op_errno         = 0;
3604df
-        int                     i,length         = 0;
3604df
+        int                     i                = 0;
3604df
+        int                     length           = 0;
3604df
         int                     ret              = -1;
3604df
 
3604df
         this = THIS;
3604df
@@ -3187,12 +3188,12 @@ client3_3_compound_cbk (struct rpc_req *req, struct iovec *iov, int count,
3604df
                 goto out;
3604df
         }
3604df
 
3604df
+        length =  local->length;
3604df
+
3604df
         GF_PROTOCOL_DICT_UNSERIALIZE (this, xdata, (rsp.xdata.xdata_val),
3604df
                                       (rsp.xdata.xdata_len), rsp.op_ret,
3604df
                                        rsp.op_errno, out);
3604df
 
3604df
-        length =  local->length;
3604df
-
3604df
         args_cbk = compound_args_cbk_alloc (length, xdata);
3604df
         if (!args_cbk) {
3604df
                 op_errno = ENOMEM;
3604df
@@ -3215,7 +3216,7 @@ out:
3604df
 
3604df
         free (rsp.xdata.xdata_val);
3604df
 
3604df
-        client_compound_rsp_cleanup (&rsp, local->length);
3604df
+        client_compound_rsp_cleanup (&rsp, length);
3604df
 
3604df
         if (xdata)
3604df
                 dict_unref (xdata);
3604df
diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c
3604df
index 756275e..d8ad6a7 100644
3604df
--- a/xlators/protocol/server/src/server-rpc-fops.c
3604df
+++ b/xlators/protocol/server/src/server-rpc-fops.c
3604df
@@ -3332,7 +3332,7 @@ server_compound_resume (call_frame_t *frame, xlator_t *bound_xl)
3604df
                 goto err;
3604df
         }
3604df
 
3604df
-        req = state->req;
3604df
+        req = &state->req;
3604df
 
3604df
         length = req->compound_req_array.compound_req_array_len;
3604df
         state->args = compound_fop_alloc (length, req->compound_fop_enum,
3604df
@@ -6736,7 +6736,7 @@ server3_3_compound (rpcsvc_request_t *req)
3604df
                 goto out;
3604df
         }
3604df
 
3604df
-        state->req           = &arg;;
3604df
+        state->req           = args;
3604df
         state->iobref        = iobref_ref (req->iobref);
3604df
 
3604df
         if (len < req->msg[0].iov_len) {
3604df
diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h
3604df
index f50e9ab..3272106 100644
3604df
--- a/xlators/protocol/server/src/server.h
3604df
+++ b/xlators/protocol/server/src/server.h
3604df
@@ -191,7 +191,7 @@ struct _server_state {
3604df
         struct gf_lease   lease;
3604df
         lock_migration_info_t locklist;
3604df
         /* required for compound fops */
3604df
-        gfs3_compound_req *req;
3604df
+        gfs3_compound_req  req;
3604df
         /* last length till which iovec for compound
3604df
          * writes was processed */
3604df
         int               write_length;
3604df
-- 
3604df
1.7.1
3604df