<div dir="ltr"><div dir="ltr">On Thu, Jun 6, 2019 at 7:57 PM NeilBrown &lt;<a href="mailto:neilb@suse.com">neilb@suse.com</a>&gt; wrote:<br>&gt;<br>&gt; On Thu, Jun 06 2019, Shaun Tancheff wrote:<br>&gt;<br>&gt; &gt; Ensure all uses of cl_page-&gt;cp_state are smp-safe.<br>&gt; &gt;<br>&gt; &gt; LBUG Output:<br>&gt; &gt; In __cl_page_state_set()<br>&gt; &gt; ..<br>&gt; &gt;   old = page-&gt;cp_state;<br>&gt; &gt;   PASSERT(env, page, allowed_transitions[old][state]);<br>&gt; &gt; ..<br>&gt; &gt; Asserted with the following:<br>&gt; &gt;   page@ffff80be1fcd6600[3 ffff80be1fca5cc0 0 1 ffff809e60e2 8cc0]<br>&gt;<br>&gt; What do all these fields mean?  Or where is this printed?<br>&gt; The closest I can find is in cl_page_header_print() which uses the<br>&gt; format string:<br>&gt;<br>&gt;                    &quot;page@%p[%d %p %d %d %p]\n&quot;,<br>&gt;<br>&gt; But that only has 5 fields in the [], while the output you provided has<br>&gt; 6.<br>&gt;<br><br>Sorry for the confusion, here is my (long) explanation with source snippets:<br><br>The LBUG in full<br><br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) page@ffff80be1fcd6600[3 ffff80be1fca5cc0 0 1 ffff809e60e28cc0]<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) vvp-page@ffff80be1fcd6650(0:0) vm@ffff7e02fa0e60c0 5000000000001029 4:0 ffff80be1fcd6600 1049548 lru<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) lov-page@ffff80be1fcd6690, comp index: 0, gen: 0<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) osc-page@ffff80be1fcd66c8 1049548: 1&lt; 0x845fed 2 0 - - &gt; 2&lt; 4298948608 0 4096 0x0 0x420 |           (null) ffff809e473708e8 ffff80be199c1e40 &gt; 3&lt; 0 0 0 &gt; 4&lt; 5 13 64 0 + | - - - - &gt; 5&lt; - - - - | 0 - | 0 - -&gt;<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) end page@ffff80be1fcd6600<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) allowed_transitions[old][state]<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) ASSERTION( 0 ) failed:<br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) LBUG<br><br>The source snippet around L342<br>...<br>   339 <br>   340          ENTRY;<br>   341          old = page-&gt;cp_state;<br>   342          PASSERT(env, page, allowed_transitions[old][state]);<br>   343          CL_PAGE_HEADER(D_TRACE, env, page, &quot;%d -&gt; %d\n&quot;, old, state);<br>   344          PASSERT(env, page, page-&gt;cp_state == old);<br>   345          PASSERT(env, page, equi(state == CPS_OWNED, page-&gt;cp_owner != NULL));<br>   346 <br>   347          cs_pagestate_dec(page-&gt;cp_obj, page-&gt;cp_state);<br>   348          cs_pagestate_inc(page-&gt;cp_obj, state);<br><br>The PASSERT macro ...<br>...<br># define PASSERT(env, page, expr)                                       \<br>  do {                                                                    \<br>          if (unlikely(!(expr))) {                                      \<br>                  CL_PAGE_DEBUG(D_ERROR, (env), (page), #expr &quot;\n&quot;);    \<br>                  LASSERT(0);                                           \<br>          }                                                             \<br>  } while (0)<br>#else /* !LIBCFS_DEBUG */<br>...<br><br>/**<br> * Helper macro, dumping detailed information about \a page into a log.<br> */<br>#define CL_PAGE_DEBUG(mask, env, page, format, ...)                     \<br>do {                                                                    \<br>        if (cfs_cdebug_show(mask, DEBUG_SUBSYSTEM)) {                   \<br>                LIBCFS_DEBUG_MSG_DATA_DECL(msgdata, mask, NULL);        \<br>                cl_page_print(env, &amp;msgdata, lu_cdebug_printer, page);  \<br>                CDEBUG(mask, format , ## __VA_ARGS__);                  \<br>        }                                                               \<br>} while (0)<br><br>Almost there<br>...<br>  1062  /**<br>  1063   * Prints human readable representation of \a pg to the \a f.<br>  1064   */<br>  1065  void cl_page_print(const struct lu_env *env, void *cookie,<br>  1066                     lu_printer_t printer, const struct cl_page *pg)<br>  1067  {<br>  1068          const struct cl_page_slice *slice;<br>  1069          int result = 0;<br>  1070 <br>  1071          cl_page_header_print(env, cookie, printer, pg);<br>  1072          list_for_each_entry(slice, &amp;pg-&gt;cp_layers, cpl_linkage) {<br>  1073                  if (slice-&gt;cpl_ops-&gt;cpo_print != NULL)<br>  1074                          result = (*slice-&gt;cpl_ops-&gt;cpo_print)(env, slice,<br>  1075                                                               cookie, printer);<br><br>Finally the &#39;good stuff&#39;<br>...<br>  1051  void cl_page_header_print(const struct lu_env *env, void *cookie,<br>  1052                            lu_printer_t printer, const struct cl_page *pg)<br>  1053  {<br>  1054          (*printer)(env, cookie,<br>  1055                     &quot;page@%p[%d %p %d %d %p]\n&quot;,<br>  1056                     pg, atomic_read(&amp;pg-&gt;cp_ref), pg-&gt;cp_obj,<br>  1057                     pg-&gt;cp_state, pg-&gt;cp_type,<br>  1058                     pg-&gt;cp_owner);<br>  1059  }<br>...<br><br>Given the above along with the first line from the LBUG ....<div><br>LustreError: 86407:0:(cl_page.c:342:cl_page_state_set0()) page@ffff80be1fcd6600[3 ffff80be1fca5cc0 0 1 ffff809e60e28cc0]<br><br>Implies the following:</div><div><br>pg == ffff80be1fcd6600<br>pg-&gt;cp_ref == 3<br>pg-&gt;cp_obj == ffff80be1fca5cc0<br>pg-&gt;cp_state == 0 (state == CPS_CACHED)<br>pg-&gt;cp_type == 1<br>pg-&gt;cp_owner == ffff809e60e28cc0<br><br>Also known caller was cl_page_assume+0xdc/0x3e0 [obdclass] (from the backtrace)<br>So we know the on-stack / register value of state == CPS_OWNED</div><div><br></div><div>The backtrace:<br>...<br> dump_backtrace+0x0/0x248<br> show_stack+0x24/0x30<br> dump_stack+0xbc/0xf4<br> libcfs_call_trace+0xec/0x120 [libcfs]<br> lbug_with_loc+0x4c/0xb8 [libcfs]<br> cl_page_state_set0+0x2b4/0x6e0 [obdclass]<br> cl_page_assume+0xdc/0x3e0 [obdclass]<br> ll_io_read_page+0x144c/0x1de0 [lustre]<br> ll_write_begin+0x3d4/0xee8 [lustre]<br><br></div><div>and the contents of cl_page_assume</div><div><br>   596  void cl_page_assume(const struct lu_env *env,<br>   597                      struct cl_io *io, struct cl_page *pg)<br>   598  {<br>   599          const struct cl_page_slice *slice;<br>   600 <br>   601          PINVRNT(env, pg, cl_object_same(pg-&gt;cp_obj, io-&gt;ci_obj));<br>   602 <br>   603          ENTRY;<br>   604          io = cl_io_top(io);<br>   605 <br>   606          list_for_each_entry(slice, &amp;pg-&gt;cp_layers, cpl_linkage) {<br>   607                  if (slice-&gt;cpl_ops-&gt;cpo_assume != NULL)<br>   608                          (*slice-&gt;cpl_ops-&gt;cpo_assume)(env, slice, io);<br>   609          }<br>   610 <br>   611          PASSERT(env, pg, pg-&gt;cp_owner == NULL);<br>   612          pg-&gt;cp_owner = cl_io_top(io);<br>   613          cl_page_owner_set(pg);<br>   614          cl_page_state_set(env, pg, CPS_OWNED);<br>   615          EXIT;<br>   616  }<br><br></div><div>While I believe my conclusion to be correct I am certainly open to being dead wrong.</div><div><br></div></div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 6, 2019 at 7:57 PM NeilBrown &lt;<a href="mailto:neilb@suse.com">neilb@suse.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On Thu, Jun 06 2019, Shaun Tancheff wrote:<br>
<br>
&gt; Ensure all uses of cl_page-&gt;cp_state are smp-safe.<br>
&gt;<br>
&gt; LBUG Output:<br>
&gt; In __cl_page_state_set()<br>
&gt; ..<br>
&gt;   old = page-&gt;cp_state;<br>
&gt;   PASSERT(env, page, allowed_transitions[old][state]);<br>
&gt; ..<br>
&gt; Asserted with the following:<br>
&gt;   page@ffff80be1fcd6600[3 ffff80be1fca5cc0 0 1 ffff809e60e2 8cc0]<br>
<br>
What do all these fields mean?  Or where is this printed?<br>
The closest I can find is in cl_page_header_print() which uses the<br>
format string:<br>
<br>
                   &quot;page@%p[%d %p %d %d %p]\n&quot;,<br>
<br>
But that only has 5 fields in the [], while the output you provided has<br>
6.<br>
<br>
&gt;<br>
&gt; However cp_state 0 (CPS_CACHED) to 1 (CPS_OWNED) is a valid transition<br>
&gt; leading to the conclusion that cp_state became 0 during the<br>
&gt; assertion.<br>
<br>
Where is the evidence that this was the transition that was happening?<br>
If it was in some part of the LBUG output that wasn&#39;t quoted - then<br>
please fix that by quoting the entire LBUG output.<br>
<br>
We need to understand which change happened at this time to cause the<br>
race.<br>
Then we need to explain why the added barriers actually close the race<br>
window.<br>
<br>
If these barrier do actually fix a race, then there is something *very*<br>
wrong.<br>
The comments say that changes to cp_state are protected by the page lock<br>
on the corresponding VM page.<br>
Locking and unlocking a VM page entails sufficient barriers that changes<br>
made while one thread holds the lock will be visible to another<br>
thread once it also gets the lock.<br>
<br></blockquote><div><br></div><div>True, but a page lock is just a bit on the page flags. And we absolutely wait on I/O while the </div><div>page is &#39;locked&#39; so a ping-pong (our task *can* sleep) is entirely reasonable, as far as</div><div>I understand anyway. Since there is multiple state-changes during a single page lock/unlock</div><div>there is a race, however rare and unlikely, and it&#39;s arch specific based on what I understand</div><div>of the memory barrier rules.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
So the only possible explanation for a race as you suspect, is if the<br>
vmpage *isn&#39;t* locked when something changes cp_state, and that would be<br>
bad.<br>
<br>
Thanks,<br>
NeilBrown<br>
<br>
<br>
&gt;<br>
&gt; Signed-off-by: Shaun Tancheff &lt;<a href="mailto:stancheff@cray.com" target="_blank">stancheff@cray.com</a>&gt;<br>
&gt; ---<br>
&gt;  fs/lustre/include/cl_object.h   | 11 +++++++++++<br>
&gt;  fs/lustre/llite/rw26.c          |  2 +-<br>
&gt;  fs/lustre/llite/vvp_page.c      |  6 +++---<br>
&gt;  fs/lustre/obdclass/cl_page.c    | 34 +++++++++++++++++++--------------<br>
&gt;  fs/lustre/obdecho/echo_client.c |  2 +-<br>
&gt;  fs/lustre/osc/osc_cache.c       | 18 +++++++++--------<br>
&gt;  6 files changed, 46 insertions(+), 27 deletions(-)<br>
&gt;<br>
&gt; diff --git a/fs/lustre/include/cl_object.h b/fs/lustre/include/cl_object.h<br>
&gt; index 691c2f5da53a..d6e1f6f05f50 100644<br>
&gt; --- a/fs/lustre/include/cl_object.h<br>
&gt; +++ b/fs/lustre/include/cl_object.h<br>
&gt; @@ -752,6 +752,17 @@ struct cl_page {<br>
&gt;       struct cl_sync_io               *cp_sync_io;<br>
&gt;  };<br>
&gt;  <br>
&gt; +static inline enum cl_page_state cl_page_state_get(const struct cl_page *pg)<br>
&gt; +{<br>
&gt; +     /*<br>
&gt; +      * Paired with smp_store_release in cl_page_state_set_trust<br>
&gt; +      * and ensures that we see the most recent value of cp_state<br>
&gt; +      * even when the last modification was not performed on the<br>
&gt; +      * current processor<br>
&gt; +      */<br>
&gt; +     return smp_load_acquire(&amp;pg-&gt;cp_state);<br>
&gt; +}<br>
&gt; +<br>
&gt;  /**<br>
&gt;   * Per-layer part of cl_page.<br>
&gt;   *<br>
&gt; diff --git a/fs/lustre/llite/rw26.c b/fs/lustre/llite/rw26.c<br>
&gt; index e4ce3b6f5772..364dec208ccd 100644<br>
&gt; --- a/fs/lustre/llite/rw26.c<br>
&gt; +++ b/fs/lustre/llite/rw26.c<br>
&gt; @@ -200,7 +200,7 @@ static ssize_t ll_direct_IO_seg(const struct lu_env *env, struct cl_io *io,<br>
&gt;  <br>
&gt;               rc = cl_page_own(env, io, clp);<br>
&gt;               if (rc) {<br>
&gt; -                     LASSERT(clp-&gt;cp_state == CPS_FREEING);<br>
&gt; +                     LASSERT(cl_page_state_get(clp) == CPS_FREEING);<br>
&gt;                       cl_page_put(env, clp);<br>
&gt;                       break;<br>
&gt;               }<br>
&gt; diff --git a/fs/lustre/llite/vvp_page.c b/fs/lustre/llite/vvp_page.c<br>
&gt; index 590e5f5e43c9..38b8c488d765 100644<br>
&gt; --- a/fs/lustre/llite/vvp_page.c<br>
&gt; +++ b/fs/lustre/llite/vvp_page.c<br>
&gt; @@ -323,18 +323,18 @@ static int vvp_page_make_ready(const struct lu_env *env,<br>
&gt;  <br>
&gt;       lock_page(vmpage);<br>
&gt;       if (clear_page_dirty_for_io(vmpage)) {<br>
&gt; -             LASSERT(pg-&gt;cp_state == CPS_CACHED);<br>
&gt; +             LASSERT(cl_page_state_get(pg) == CPS_CACHED);<br>
&gt;               /* This actually clears the dirty bit in the radix tree. */<br>
&gt;               set_page_writeback(vmpage);<br>
&gt;               CL_PAGE_HEADER(D_PAGE, env, pg, &quot;readied\n&quot;);<br>
&gt; -     } else if (pg-&gt;cp_state == CPS_PAGEOUT) {<br>
&gt; +     } else if (cl_page_state_get(pg) == CPS_PAGEOUT) {<br>
&gt;               /* is it possible for osc_flush_async_page() to already<br>
&gt;                * make it ready?<br>
&gt;                */<br>
&gt;               result = -EALREADY;<br>
&gt;       } else {<br>
&gt;               CL_PAGE_DEBUG(D_ERROR, env, pg, &quot;Unexpecting page state %d.\n&quot;,<br>
&gt; -                           pg-&gt;cp_state);<br>
&gt; +                           cl_page_state_get(pg));<br>
&gt;               LBUG();<br>
&gt;       }<br>
&gt;       unlock_page(vmpage);<br>
&gt; diff --git a/fs/lustre/obdclass/cl_page.c b/fs/lustre/obdclass/cl_page.c<br>
&gt; index 349f19e014e0..da4429b82932 100644<br>
&gt; --- a/fs/lustre/obdclass/cl_page.c<br>
&gt; +++ b/fs/lustre/obdclass/cl_page.c<br>
&gt; @@ -97,7 +97,7 @@ static void cl_page_free(const struct lu_env *env, struct cl_page *page)<br>
&gt;  <br>
&gt;       PASSERT(env, page, list_empty(&amp;page-&gt;cp_batch));<br>
&gt;       PASSERT(env, page, !page-&gt;cp_owner);<br>
&gt; -     PASSERT(env, page, page-&gt;cp_state == CPS_FREEING);<br>
&gt; +     PASSERT(env, page, cl_page_state_get(page) == CPS_FREEING);<br>
&gt;  <br>
&gt;       while ((slice = list_first_entry_or_null(&amp;page-&gt;cp_layers,<br>
&gt;                                                struct cl_page_slice,<br>
&gt; @@ -119,8 +119,14 @@ static void cl_page_free(const struct lu_env *env, struct cl_page *page)<br>
&gt;  static inline void cl_page_state_set_trust(struct cl_page *page,<br>
&gt;                                          enum cl_page_state state)<br>
&gt;  {<br>
&gt; -     /* bypass const. */<br>
&gt; -     *(enum cl_page_state *)&amp;page-&gt;cp_state = state;<br>
&gt; +     /*<br>
&gt; +      * Paired with smp_load_acquire in cl_page_state_get<br>
&gt; +      * and ensures that we see the most recent value of cp_state<br>
&gt; +      * is available even when the next access is not performed on the<br>
&gt; +      * current processor.<br>
&gt; +      * Note we also cast away const as the only modifier of cp_state.<br>
&gt; +      */<br>
&gt; +     smp_store_release((enum cl_page_state *)&amp;page-&gt;cp_state, state);<br>
&gt;  }<br>
&gt;  <br>
&gt;  struct cl_page *cl_page_alloc(const struct lu_env *env,<br>
&gt; @@ -270,10 +276,10 @@ static void __cl_page_state_set(const struct lu_env *env,<br>
&gt;               }<br>
&gt;       };<br>
&gt;  <br>
&gt; -     old = page-&gt;cp_state;<br>
&gt; +     old = cl_page_state_get(page);<br>
&gt;       PASSERT(env, page, allowed_transitions[old][state]);<br>
&gt;       CL_PAGE_HEADER(D_TRACE, env, page, &quot;%d -&gt; %d\n&quot;, old, state);<br>
&gt; -     PASSERT(env, page, page-&gt;cp_state == old);<br>
&gt; +     PASSERT(env, page, cl_page_state_get(page) == old);<br>
&gt;       PASSERT(env, page, equi(state == CPS_OWNED, page-&gt;cp_owner));<br>
&gt;       cl_page_state_set_trust(page, state);<br>
&gt;  }<br>
&gt; @@ -313,7 +319,7 @@ void cl_page_put(const struct lu_env *env, struct cl_page *page)<br>
&gt;                      refcount_read(&amp;page-&gt;cp_ref));<br>
&gt;  <br>
&gt;       if (refcount_dec_and_test(&amp;page-&gt;cp_ref)) {<br>
&gt; -             LASSERT(page-&gt;cp_state == CPS_FREEING);<br>
&gt; +             LASSERT(cl_page_state_get(page) == CPS_FREEING);<br>
&gt;  <br>
&gt;               LASSERT(refcount_read(&amp;page-&gt;cp_ref) == 0);<br>
&gt;               PASSERT(env, page, !page-&gt;cp_owner);<br>
&gt; @@ -378,7 +384,7 @@ void __cl_page_disown(const struct lu_env *env,<br>
&gt;       const struct cl_page_slice *slice;<br>
&gt;       enum cl_page_state state;<br>
&gt;  <br>
&gt; -     state = pg-&gt;cp_state;<br>
&gt; +     state = cl_page_state_get(pg);<br>
&gt;       cl_page_owner_clear(pg);<br>
&gt;  <br>
&gt;       if (state == CPS_OWNED)<br>
&gt; @@ -402,7 +408,7 @@ int cl_page_is_owned(const struct cl_page *pg, const struct cl_io *io)<br>
&gt;       struct cl_io *top = cl_io_top((struct cl_io *)io);<br>
&gt;  <br>
&gt;       LINVRNT(cl_object_same(pg-&gt;cp_obj, io-&gt;ci_obj));<br>
&gt; -     return pg-&gt;cp_state == CPS_OWNED &amp;&amp; pg-&gt;cp_owner == top;<br>
&gt; +     return cl_page_state_get(pg) == CPS_OWNED &amp;&amp; pg-&gt;cp_owner == top;<br>
&gt;  }<br>
&gt;  EXPORT_SYMBOL(cl_page_is_owned);<br>
&gt;  <br>
&gt; @@ -434,7 +440,7 @@ static int __cl_page_own(const struct lu_env *env, struct cl_io *io,<br>
&gt;  <br>
&gt;       io = cl_io_top(io);<br>
&gt;  <br>
&gt; -     if (pg-&gt;cp_state == CPS_FREEING) {<br>
&gt; +     if (cl_page_state_get(pg) == CPS_FREEING) {<br>
&gt;               result = -ENOENT;<br>
&gt;               goto out;<br>
&gt;       }<br>
&gt; @@ -453,7 +459,7 @@ static int __cl_page_own(const struct lu_env *env, struct cl_io *io,<br>
&gt;               PASSERT(env, pg, !pg-&gt;cp_owner);<br>
&gt;               pg-&gt;cp_owner = cl_io_top(io);<br>
&gt;               cl_page_owner_set(pg);<br>
&gt; -             if (pg-&gt;cp_state != CPS_FREEING) {<br>
&gt; +             if (cl_page_state_get(pg) != CPS_FREEING) {<br>
&gt;                       cl_page_state_set(env, pg, CPS_OWNED);<br>
&gt;               } else {<br>
&gt;                       __cl_page_disown(env, io, pg);<br>
&gt; @@ -593,7 +599,7 @@ static void __cl_page_delete(const struct lu_env *env, struct cl_page *pg)<br>
&gt;  {<br>
&gt;       const struct cl_page_slice *slice;<br>
&gt;  <br>
&gt; -     PASSERT(env, pg, pg-&gt;cp_state != CPS_FREEING);<br>
&gt; +     PASSERT(env, pg, cl_page_state_get(pg) != CPS_FREEING);<br>
&gt;  <br>
&gt;       /*<br>
&gt;        * Sever all ways to obtain new pointers to @pg.<br>
&gt; @@ -756,7 +762,7 @@ void cl_page_completion(const struct lu_env *env,<br>
&gt;       const struct cl_page_slice *slice;<br>
&gt;  <br>
&gt;       PASSERT(env, pg, crt &lt; CRT_NR);<br>
&gt; -     PASSERT(env, pg, pg-&gt;cp_state == cl_req_type_state(crt));<br>
&gt; +     PASSERT(env, pg, cl_page_state_get(pg) == cl_req_type_state(crt));<br>
&gt;  <br>
&gt;       CL_PAGE_HEADER(D_TRACE, env, pg, &quot;%d %d\n&quot;, crt, ioret);<br>
&gt;  <br>
&gt; @@ -805,7 +811,7 @@ int cl_page_make_ready(const struct lu_env *env, struct cl_page *pg,<br>
&gt;       }<br>
&gt;  <br>
&gt;       if (result &gt;= 0) {<br>
&gt; -             PASSERT(env, pg, pg-&gt;cp_state == CPS_CACHED);<br>
&gt; +             PASSERT(env, pg, cl_page_state_get(pg) == CPS_CACHED);<br>
&gt;               cl_page_io_start(env, pg, crt);<br>
&gt;               result = 0;<br>
&gt;       }<br>
&gt; @@ -870,7 +876,7 @@ void cl_page_header_print(const struct lu_env *env, void *cookie,<br>
&gt;       (*printer)(env, cookie,<br>
&gt;                  &quot;page@%p[%d %p %d %d %p]\n&quot;,<br>
&gt;                  pg, refcount_read(&amp;pg-&gt;cp_ref), pg-&gt;cp_obj,<br>
&gt; -                pg-&gt;cp_state, pg-&gt;cp_type,<br>
&gt; +                cl_page_state_get(pg), pg-&gt;cp_type,<br>
&gt;                  pg-&gt;cp_owner);<br>
&gt;  }<br>
&gt;  EXPORT_SYMBOL(cl_page_header_print);<br>
&gt; diff --git a/fs/lustre/obdecho/echo_client.c b/fs/lustre/obdecho/echo_client.c<br>
&gt; index 317123fd27cb..d879f109e641 100644<br>
&gt; --- a/fs/lustre/obdecho/echo_client.c<br>
&gt; +++ b/fs/lustre/obdecho/echo_client.c<br>
&gt; @@ -1046,7 +1046,7 @@ static int cl_echo_object_brw(struct echo_object *eco, int rw, u64 offset,<br>
&gt;  <br>
&gt;               rc = cl_page_own(env, io, clp);<br>
&gt;               if (rc) {<br>
&gt; -                     LASSERT(clp-&gt;cp_state == CPS_FREEING);<br>
&gt; +                     LASSERT(cl_page_state_get(clp) == CPS_FREEING);<br>
&gt;                       cl_page_put(env, clp);<br>
&gt;                       break;<br>
&gt;               }<br>
&gt; diff --git a/fs/lustre/osc/osc_cache.c b/fs/lustre/osc/osc_cache.c<br>
&gt; index f8fddbfe6a7e..75984b98b229 100644<br>
&gt; --- a/fs/lustre/osc/osc_cache.c<br>
&gt; +++ b/fs/lustre/osc/osc_cache.c<br>
&gt; @@ -1045,7 +1045,7 @@ static int osc_extent_truncate(struct osc_extent *ext, pgoff_t trunc_index,<br>
&gt;                       cl_page_discard(env, io, page);<br>
&gt;                       cl_page_disown(env, io, page);<br>
&gt;               } else {<br>
&gt; -                     LASSERT(page-&gt;cp_state == CPS_FREEING);<br>
&gt; +                     LASSERT(cl_page_state_get(page) == CPS_FREEING);<br>
&gt;                       LASSERT(0);<br>
&gt;               }<br>
&gt;  <br>
&gt; @@ -1356,10 +1356,12 @@ static int osc_completion(const struct lu_env *env, struct osc_async_page *oap,<br>
&gt;       int srvlock;<br>
&gt;  <br>
&gt;       cmd &amp;= ~OBD_BRW_NOQUOTA;<br>
&gt; -     LASSERTF(equi(page-&gt;cp_state == CPS_PAGEIN, cmd == OBD_BRW_READ),<br>
&gt; -              &quot;cp_state:%u, cmd:%d\n&quot;, page-&gt;cp_state, cmd);<br>
&gt; -     LASSERTF(equi(page-&gt;cp_state == CPS_PAGEOUT, cmd == OBD_BRW_WRITE),<br>
&gt; -              &quot;cp_state:%u, cmd:%d\n&quot;, page-&gt;cp_state, cmd);<br>
&gt; +     LASSERTF(equi(cl_page_state_get(page) == CPS_PAGEIN,<br>
&gt; +                   cmd == OBD_BRW_READ),<br>
&gt; +              &quot;cp_state:%u, cmd:%d\n&quot;, cl_page_state_get(page), cmd);<br>
&gt; +     LASSERTF(equi(cl_page_state_get(page) == CPS_PAGEOUT,<br>
&gt; +                   cmd == OBD_BRW_WRITE),<br>
&gt; +              &quot;cp_state:%u, cmd:%d\n&quot;, cl_page_state_get(page), cmd);<br>
&gt;       LASSERT(opg-&gt;ops_transfer_pinned);<br>
&gt;  <br>
&gt;       crt = cmd == OBD_BRW_READ ? CRT_READ : CRT_WRITE;<br>
&gt; @@ -3061,7 +3063,7 @@ bool osc_page_gang_lookup(const struct lu_env *env, struct cl_io *io,<br>
&gt;  <br>
&gt;                       page = ops-&gt;ops_cl.cpl_page;<br>
&gt;                       LASSERT(page-&gt;cp_type == CPT_CACHEABLE);<br>
&gt; -                     if (page-&gt;cp_state == CPS_FREEING)<br>
&gt; +                     if (cl_page_state_get(page) == CPS_FREEING)<br>
&gt;                               continue;<br>
&gt;  <br>
&gt;                       cl_page_get(page);<br>
&gt; @@ -3142,7 +3144,7 @@ static bool check_and_discard_cb(const struct lu_env *env, struct cl_io *io,<br>
&gt;                       cl_page_discard(env, io, page);<br>
&gt;                       cl_page_disown(env, io, page);<br>
&gt;               } else {<br>
&gt; -                     LASSERT(page-&gt;cp_state == CPS_FREEING);<br>
&gt; +                     LASSERT(cl_page_state_get(page) == CPS_FREEING);<br>
&gt;               }<br>
&gt;       }<br>
&gt;  <br>
&gt; @@ -3169,7 +3171,7 @@ static bool discard_cb(const struct lu_env *env, struct cl_io *io,<br>
&gt;               cl_page_discard(env, io, page);<br>
&gt;               cl_page_disown(env, io, page);<br>
&gt;       } else {<br>
&gt; -             LASSERT(page-&gt;cp_state == CPS_FREEING);<br>
&gt; +             LASSERT(cl_page_state_get(page) == CPS_FREEING);<br>
&gt;       }<br>
&gt;  <br>
&gt;       return true;<br>
&gt; -- <br>
&gt; 2.17.1<br>
</blockquote></div></div>