diff --git a/src/core/channel/census_filter.c b/src/core/channel/census_filter.c
index 4285b284cec275e87f5851c1789c0309319c9a01..d610a6fc9d6fde1eaf876141d9183b53e7c2bffc 100644
--- a/src/core/channel/census_filter.c
+++ b/src/core/channel/census_filter.c
@@ -72,7 +72,8 @@ static void extract_and_annotate_method_tag(grpc_call_op* op, call_data* calld,
   }
 }
 
-static void client_call_op(grpc_call_element* elem, grpc_call_op* op) {
+static void client_call_op(grpc_call_element* elem,
+                           grpc_call_element* from_elem, grpc_call_op* op) {
   call_data* calld = elem->call_data;
   channel_data* chand = elem->channel_data;
   GPR_ASSERT(calld != NULL);
@@ -92,7 +93,8 @@ static void client_call_op(grpc_call_element* elem, grpc_call_op* op) {
   grpc_call_next_op(elem, op);
 }
 
-static void server_call_op(grpc_call_element* elem, grpc_call_op* op) {
+static void server_call_op(grpc_call_element* elem,
+                           grpc_call_element* from_elem, grpc_call_op* op) {
   call_data* calld = elem->call_data;
   channel_data* chand = elem->channel_data;
   GPR_ASSERT(calld != NULL);
@@ -112,7 +114,8 @@ static void server_call_op(grpc_call_element* elem, grpc_call_op* op) {
   grpc_call_next_op(elem, op);
 }
 
-static void channel_op(grpc_channel_element* elem, grpc_channel_op* op) {
+static void channel_op(grpc_channel_element* elem,
+                       grpc_channel_element* from_elem, grpc_channel_op* op) {
   switch (op->type) {
     case GRPC_TRANSPORT_CLOSED:
       /* TODO(hongyu): Annotate trace information for all calls of the channel
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index a403db35c2863ed29a640c4af057a3a9a3fc638b..5ee412bf7d0cc57d5c8bfaf5caffaf58e376a837 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -180,12 +180,12 @@ void grpc_call_stack_destroy(grpc_call_stack *stack) {
 
 void grpc_call_next_op(grpc_call_element *elem, grpc_call_op *op) {
   grpc_call_element *next_elem = elem + op->dir;
-  next_elem->filter->call_op(next_elem, op);
+  next_elem->filter->call_op(next_elem, elem, op);
 }
 
 void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
   grpc_channel_element *next_elem = elem + op->dir;
-  next_elem->filter->channel_op(next_elem, op);
+  next_elem->filter->channel_op(next_elem, elem, op);
 }
 
 grpc_channel_stack *grpc_channel_stack_from_top_element(
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index 67cd356ef9fa323b41c641b7c9238fff7ce1572a..b837caf97b4f2e38158d20aed21987a9026ade85 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -170,11 +170,13 @@ typedef struct {
 typedef struct {
   /* Called to eg. send/receive data on a call.
      See grpc_call_next_op on how to call the next element in the stack */
-  void (*call_op)(grpc_call_element *elem, grpc_call_op *op);
+  void (*call_op)(grpc_call_element *elem, grpc_call_element *from_elem,
+                  grpc_call_op *op);
   /* Called to handle channel level operations - e.g. new calls, or transport
      closure.
      See grpc_channel_next_op on how to call the next element in the stack */
-  void (*channel_op)(grpc_channel_element *elem, grpc_channel_op *op);
+  void (*channel_op)(grpc_channel_element *elem,
+                     grpc_channel_element *from_elem, grpc_channel_op *op);
 
   /* sizeof(per call data) */
   size_t sizeof_call_data;
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 0ceffba62a8c4f7007c17966e0c3c83293e8f8dc..9ec19df8a9eec8e8fc0705b5676cfd5665c4eec7 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -51,12 +51,13 @@ typedef struct { grpc_channel_element *back; } lb_channel_data;
 
 typedef struct { grpc_call_element *back; } lb_call_data;
 
-static void lb_call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void lb_call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                       grpc_call_op *op) {
   lb_call_data *calld = elem->call_data;
 
   switch (op->dir) {
     case GRPC_CALL_UP:
-      calld->back->filter->call_op(calld->back, op);
+      calld->back->filter->call_op(calld->back, elem, op);
       break;
     case GRPC_CALL_DOWN:
       grpc_call_next_op(elem, op);
@@ -65,12 +66,14 @@ static void lb_call_op(grpc_call_element *elem, grpc_call_op *op) {
 }
 
 /* Currently we assume all channel operations should just be pushed up. */
-static void lb_channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void lb_channel_op(grpc_channel_element *elem,
+                          grpc_channel_element *from_elem,
+                          grpc_channel_op *op) {
   lb_channel_data *chand = elem->channel_data;
 
   switch (op->dir) {
     case GRPC_CALL_UP:
-      chand->back->filter->channel_op(chand->back, op);
+      chand->back->filter->channel_op(chand->back, elem, op);
       break;
     case GRPC_CALL_DOWN:
       grpc_channel_next_op(elem, op);
@@ -201,8 +204,9 @@ static int prepare_activate(call_data *calld, child_entry *on_child) {
 
 static void do_nothing(void *ignored, grpc_op_error error) {}
 
-static void complete_activate(call_data *calld, child_entry *on_child,
+static void complete_activate(grpc_call_element *elem, child_entry *on_child,
                               grpc_call_op *op) {
+  call_data *calld = elem->call_data;
   grpc_call_element *child_elem =
       grpc_call_stack_element(calld->s.active.child_stack, 0);
 
@@ -219,15 +223,17 @@ static void complete_activate(call_data *calld, child_entry *on_child,
     dop.data.deadline = calld->deadline;
     dop.done_cb = do_nothing;
     dop.user_data = NULL;
-    child_elem->filter->call_op(child_elem, &dop);
+    child_elem->filter->call_op(child_elem, elem, &dop);
   }
 
   /* continue the start call down the stack, this nees to happen after metadata
      are flushed*/
-  child_elem->filter->call_op(child_elem, op);
+  child_elem->filter->call_op(child_elem, elem, op);
 }
 
-static void start_rpc(call_data *calld, channel_data *chand, grpc_call_op *op) {
+static void start_rpc(grpc_call_element *elem, grpc_call_op *op) {
+  call_data *calld = elem->call_data;
+  channel_data *chand = elem->channel_data;
   gpr_mu_lock(&chand->mu);
   if (calld->state == CALL_CANCELLED) {
     gpr_mu_unlock(&chand->mu);
@@ -241,7 +247,7 @@ static void start_rpc(call_data *calld, channel_data *chand, grpc_call_op *op) {
     if (prepare_activate(calld, chand->active_child)) {
       gpr_mu_unlock(&chand->mu);
       /* activate the request (pass it down) outside the lock */
-      complete_activate(calld, chand->active_child, op);
+      complete_activate(elem, chand->active_child, op);
     } else {
       gpr_mu_unlock(&chand->mu);
     }
@@ -299,7 +305,7 @@ static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) {
     case CALL_ACTIVE:
       child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
       gpr_mu_unlock(&chand->mu);
-      child_elem->filter->call_op(child_elem, op);
+      child_elem->filter->call_op(child_elem, elem, op);
       return; /* early out */
     case CALL_WAITING:
       remove_waiting_child(chand, calld);
@@ -333,9 +339,9 @@ static void cancel_rpc(grpc_call_element *elem, grpc_call_op *op) {
   abort();
 }
 
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
   grpc_call_element *child_elem;
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
@@ -350,7 +356,7 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
       break;
     case GRPC_SEND_START:
       /* filter out the start event to find which child to send on */
-      start_rpc(calld, chand, op);
+      start_rpc(elem, op);
       break;
     case GRPC_CANCEL_OP:
       cancel_rpc(elem, op);
@@ -363,7 +369,7 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
         case GRPC_CALL_DOWN:
           child_elem = grpc_call_stack_element(calld->s.active.child_stack, 0);
           GPR_ASSERT(calld->state == CALL_ACTIVE);
-          child_elem->filter->call_op(child_elem, op);
+          child_elem->filter->call_op(child_elem, elem, op);
           break;
       }
       break;
@@ -395,7 +401,7 @@ static void broadcast_channel_op_down(grpc_channel_element *elem,
     if (op->type == GRPC_CHANNEL_GOAWAY) {
       gpr_slice_ref(op->data.goaway.message);
     }
-    child_elem->filter->channel_op(child_elem, op);
+    child_elem->filter->channel_op(child_elem, elem, op);
   }
   if (op->type == GRPC_CHANNEL_GOAWAY) {
     gpr_slice_unref(op->data.goaway.message);
@@ -411,7 +417,8 @@ static void broadcast_channel_op_down(grpc_channel_element *elem,
   gpr_free(children);
 }
 
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   GPR_ASSERT(elem->filter == &grpc_client_channel_filter);
 
   switch (op->type) {
@@ -627,7 +634,7 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
      that guarantee we need to do some curly locking here */
   for (i = 0; i < waiting_child_count; i++) {
     if (waiting_children[i]) {
-      complete_activate(waiting_children[i], child_ent, &call_ops[i]);
+      complete_activate(waiting_children[i]->elem, child_ent, &call_ops[i]);
     }
   }
   gpr_free(waiting_children);
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index fb2d5ad3281d94555c8d1e37a6a9f50e2b8bb5db..5dc4d7a5d411fab4dafa534ddf8e1b26cde0faec 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -113,7 +113,8 @@ static void end_bufferable_op(grpc_call_op *op, channel_data *chand,
 
 /* Intercept a call operation and either push it directly up or translate it
    into transport stream operations */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
@@ -164,7 +165,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 }
 
 /* Currently we assume all channel operations should just be pushed up. */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
 
@@ -282,7 +284,7 @@ static void accept_stream(void *user_data, grpc_transport *transport,
   op.dir = GRPC_CALL_UP;
   op.data.accept_call.transport = transport;
   op.data.accept_call.transport_server_data = transport_server_data;
-  channel_op(elem, &op);
+  channel_op(elem, NULL, &op);
 }
 
 static void recv_error(channel_data *chand, call_data *calld, int line,
@@ -481,7 +483,7 @@ static void transport_goaway(void *user_data, grpc_transport *transport,
   op.dir = GRPC_CALL_UP;
   op.data.goaway.status = status;
   op.data.goaway.message = debug;
-  channel_op(elem, &op);
+  channel_op(elem, NULL, &op);
 }
 
 static void transport_closed(void *user_data, grpc_transport *transport) {
@@ -495,7 +497,7 @@ static void transport_closed(void *user_data, grpc_transport *transport) {
 
   op.type = GRPC_TRANSPORT_CLOSED;
   op.dir = GRPC_CALL_UP;
-  channel_op(elem, &op);
+  channel_op(elem, NULL, &op);
 }
 
 const grpc_transport_callbacks connected_channel_transport_callbacks = {
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index b82c7352d33c04708e4e1da43a001ffff5c363ff..949f1fefeb6a4ccf53327a36599048d92f4f2421 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -48,7 +48,8 @@ static void ignore_unused(void *ignored) {}
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -71,7 +72,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 
 /* Called on special channel events, such as disconnection or new incoming
    calls on the server */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
diff --git a/src/core/channel/http_filter.c b/src/core/channel/http_filter.c
index b5c154144ef8e7e048d5d5ee528c0a65434fe4db..6cfe34695c4d933a17feb9bcd0fbd70d933c44da 100644
--- a/src/core/channel/http_filter.c
+++ b/src/core/channel/http_filter.c
@@ -50,7 +50,8 @@ static void ignore_unused(void *ignored) {}
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -69,7 +70,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 
 /* Called on special channel events, such as disconnection or new incoming
    calls on the server */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 9c6dd45206c854adc7941e0412acdae51d445d32..9a20d79c61fa20d8112e576b9fecba9d37f19f33 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -49,7 +49,8 @@ static void ignore_unused(void *ignored) {}
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -97,7 +98,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 
 /* Called on special channel events, such as disconnection or new incoming
    calls on the server */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
index 705df4a7075f92231eba2ce31d264bcf79fb4b1b..b6b3f661f7b49d3fb2ebc6dfd978c8924ca5d52b 100644
--- a/src/core/channel/noop_filter.c
+++ b/src/core/channel/noop_filter.c
@@ -50,7 +50,8 @@ static void ignore_unused(void *ignored) {}
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -68,7 +69,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 
 /* Called on special channel events, such as disconnection or new incoming
    calls on the server */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   /* grab pointers to our data from the channel element */
   channel_data *channeld = elem->channel_data;
 
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 9ce0c69d96f399c9f4d744d7d01a08ca90c233bc..f743b2583827e24c40c79397ea41a63b1c88594f 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -67,7 +67,8 @@ static void on_credentials_metadata(void *user_data, grpc_mdelem **md_elems,
      - a network event (or similar) from below, to receive something
    op contains type and call direction information, in addition to the data
    that is being sent or received. */
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
@@ -103,7 +104,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
 
 /* Called on special channel events, such as disconnection or new incoming
    calls on the server */
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   grpc_channel_next_op(elem, op);
 }
 
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index 1cffe3d32a2493ca4e26a24845db4d507271c46a..d9d157c5487f6f85106bd1c6ed1720df8be5837e 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -276,7 +276,7 @@ grpc_call_error grpc_call_cancel(grpc_call *c) {
   op.user_data = NULL;
 
   elem = CALL_ELEM_FROM_CALL(c, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -285,7 +285,7 @@ void grpc_call_execute_op(grpc_call *call, grpc_call_op *op) {
   grpc_call_element *elem;
   GPR_ASSERT(op->dir == GRPC_CALL_DOWN);
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, op);
+  elem->filter->call_op(elem, NULL, op);
 }
 
 grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
@@ -307,7 +307,7 @@ grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
       metadata->value_length);
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -404,7 +404,7 @@ grpc_call_error grpc_call_start_invoke(grpc_call *call,
   op.user_data = call;
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -475,7 +475,7 @@ grpc_call_error grpc_call_server_end_initial_metadata(grpc_call *call,
   op.user_data = NULL;
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -542,7 +542,7 @@ static void request_more_data(grpc_call *call) {
   op.user_data = NULL;
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 }
 
 grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
@@ -630,7 +630,7 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
   op.data.message = byte_buffer;
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -669,7 +669,7 @@ grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
   op.user_data = call;
 
   elem = CALL_ELEM_FROM_CALL(call, 0);
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
@@ -709,7 +709,7 @@ grpc_call_error grpc_call_start_write_status(grpc_call *call,
     op.done_cb = do_nothing;
     op.user_data = NULL;
     op.data.metadata = md;
-    elem->filter->call_op(elem, &op);
+    elem->filter->call_op(elem, NULL, &op);
   }
 
   /* always send status */
@@ -726,7 +726,7 @@ grpc_call_error grpc_call_start_write_status(grpc_call *call,
     op.done_cb = do_nothing;
     op.user_data = NULL;
     op.data.metadata = md;
-    elem->filter->call_op(elem, &op);
+    elem->filter->call_op(elem, NULL, &op);
   }
 
   grpc_cq_begin_op(call->cq, call, GRPC_FINISH_ACCEPTED);
@@ -741,7 +741,7 @@ grpc_call_error grpc_call_start_write_status(grpc_call *call,
   op.done_cb = done_writes_done;
   op.user_data = call;
 
-  elem->filter->call_op(elem, &op);
+  elem->filter->call_op(elem, NULL, &op);
 
   return GRPC_CALL_OK;
 }
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index dfb47b3a535d28b49ba27a80864e0daafabaab78..fe7a3afcc9dc1f5abd572a7212d706658af8ee02 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -133,11 +133,11 @@ void grpc_channel_destroy(grpc_channel *channel) {
   op.dir = GRPC_CALL_DOWN;
   op.data.goaway.status = GRPC_STATUS_OK;
   op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
-  elem->filter->channel_op(elem, &op);
+  elem->filter->channel_op(elem, NULL, &op);
 
   op.type = GRPC_CHANNEL_DISCONNECT;
   op.dir = GRPC_CALL_DOWN;
-  elem->filter->channel_op(elem, &op);
+  elem->filter->channel_op(elem, NULL, &op);
 
   grpc_channel_internal_unref(channel);
 }
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
index f78a45f07322473abb8fb1f8f630c9ffd47a7904..98cb460d630905a4f3b316147943f2fe4bee3d77 100644
--- a/src/core/surface/client.c
+++ b/src/core/surface/client.c
@@ -42,7 +42,8 @@ typedef struct { void *unused; } call_data;
 
 typedef struct { void *unused; } channel_data;
 
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 
   switch (op->type) {
@@ -75,7 +76,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
   }
 }
 
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   switch (op->type) {
     case GRPC_ACCEPT_CALL:
       gpr_log(GPR_ERROR, "Client cannot accept new calls");
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index 3744b5b6db359483b416e903fe7e44bfdb18f778..6a832436cae8b67f78e5c5915a48449428c0b7c2 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -44,7 +44,8 @@ typedef struct { void *unused; } call_data;
 
 typedef struct { void *unused; } channel_data;
 
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                    grpc_call_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 
   switch (op->type) {
@@ -61,7 +62,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
   op->done_cb(op->user_data, GRPC_OP_ERROR);
 }
 
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   switch (op->type) {
     case GRPC_CHANNEL_GOAWAY:
       gpr_slice_unref(op->data.goaway.message);
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index cfff6631f34f337f89fd6613ede30a5dd9791937..9eaa3c0602925a8b01abfd4e2feddc7b7fc04a4f 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -276,7 +276,8 @@ static void finish_rpc(grpc_call_element *elem, int is_full_close) {
   gpr_mu_unlock(&chand->server->mu);
 }
 
-static void call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void call_op(grpc_call_element *elem, grpc_call_element *from_elemn,
+                    grpc_call_op *op) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   switch (op->type) {
     case GRPC_RECV_METADATA:
@@ -306,7 +307,8 @@ static void call_op(grpc_call_element *elem, grpc_call_op *op) {
   }
 }
 
-static void channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_op(grpc_channel_element *elem,
+                       grpc_channel_element *from_elem, grpc_channel_op *op) {
   channel_data *chand = elem->channel_data;
 
   switch (op->type) {
@@ -341,7 +343,7 @@ static void finish_shutdown_channel(void *cd, grpc_iomgr_cb_status status) {
   op.dir = GRPC_CALL_DOWN;
   channel_op(grpc_channel_stack_element(
                  grpc_channel_get_channel_stack(chand->channel), 0),
-             &op);
+             NULL, &op);
   grpc_channel_internal_unref(chand->channel);
 }
 
@@ -558,7 +560,7 @@ void grpc_server_shutdown(grpc_server *server) {
     op.dir = GRPC_CALL_DOWN;
     op.data.goaway.status = GRPC_STATUS_OK;
     op.data.goaway.message = gpr_slice_from_copied_string("Server shutdown");
-    elem->filter->channel_op(elem, &op);
+    elem->filter->channel_op(elem, NULL, &op);
 
     grpc_channel_internal_unref(c->channel);
   }
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 44ede2f1d9825e2c414179bea15be5a44beb1095..06b090108feeb5a787870a25eb328075ad07ea93 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -66,11 +66,13 @@ static void call_destroy_func(grpc_call_element *elem) {
   ++*(int *)(elem->channel_data);
 }
 
-static void call_func(grpc_call_element *elem, grpc_call_op *op) {
+static void call_func(grpc_call_element *elem, grpc_call_element *from_elem,
+                      grpc_call_op *op) {
   ++*(int *)(elem->call_data);
 }
 
-static void channel_func(grpc_channel_element *elem, grpc_channel_op *op) {
+static void channel_func(grpc_channel_element *elem,
+                         grpc_channel_element *from_elem, grpc_channel_op *op) {
   ++*(int *)(elem->channel_data);
 }
 
diff --git a/test/core/channel/metadata_buffer_test.c b/test/core/channel/metadata_buffer_test.c
index 4a60b53f8181bf453085d40f2db25f804c00e710..aa2399272f7a35be286c45b346c75edda7d17813 100644
--- a/test/core/channel/metadata_buffer_test.c
+++ b/test/core/channel/metadata_buffer_test.c
@@ -61,10 +61,14 @@ typedef struct {
   size_t value_prefix_len;
 } channel_data;
 
-static void fail_call_op(grpc_call_element *elem, grpc_call_op *op) { abort(); }
+static void fail_call_op(grpc_call_element *elem, grpc_call_element *from_elem,
+                         grpc_call_op *op) {
+  abort();
+}
 
 /* verify that the metadata passed on during flush is the same as we expect */
-static void expect_call_op(grpc_call_element *elem, grpc_call_op *op) {
+static void expect_call_op(grpc_call_element *elem,
+                           grpc_call_element *from_elem, grpc_call_op *op) {
   size_t *n = elem->call_data;
   channel_data *cd = elem->channel_data;
   gpr_slice key = construct_buffer(cd->key_prefix_len, *n);
@@ -85,7 +89,9 @@ static void expect_call_op(grpc_call_element *elem, grpc_call_op *op) {
   grpc_mdelem_unref(op->data.metadata);
 }
 
-static void fail_channel_op(grpc_channel_element *elem, grpc_channel_op *op) {
+static void fail_channel_op(grpc_channel_element *elem,
+                            grpc_channel_element *from_elem,
+                            grpc_channel_op *op) {
   abort();
 }