<html><body><div style="font-family: garamond,new york,times,serif; font-size: 12pt; color: #000000"><div><br></div><div><br></div><hr id="zwchr"><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;" data-mce-style="border-left: 2px solid #1010FF; margin-left: 5px; padding-left: 5px; color: #000; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica,Arial,sans-serif; font-size: 12pt;"><b>From: </b>"Anand Avati" &lt;aavati@redhat.com&gt;<br><b>To: </b>"Krutika Dhananjay" &lt;kdhananj@redhat.com&gt;, "Pranith Kumar Karampuri" &lt;pkarampu@redhat.com&gt;<br><b>Cc: </b>gluster-devel@gluster.org<br><b>Sent: </b>Thursday, June 5, 2014 12:38:41 PM<br><b>Subject: </b>Re: [Gluster-devel] Regarding doing away with refkeeper in locks xlator<br><div><br></div>On 6/4/14, 9:43 PM, Krutika Dhananjay wrote:<br>&gt;<br>&gt;<br>&gt; ------------------------------------------------------------------------<br>&gt;<br>&gt; &nbsp; &nbsp; *From: *"Pranith Kumar Karampuri" &lt;pkarampu@redhat.com&gt;<br>&gt; &nbsp; &nbsp; *To: *"Krutika Dhananjay" &lt;kdhananj@redhat.com&gt;, "Anand Avati"<br>&gt; &nbsp; &nbsp; &lt;aavati@redhat.com&gt;<br>&gt; &nbsp; &nbsp; *Cc: *gluster-devel@gluster.org<br>&gt; &nbsp; &nbsp; *Sent: *Wednesday, June 4, 2014 12:23:59 PM<br>&gt; &nbsp; &nbsp; *Subject: *Re: [Gluster-devel] Regarding doing away with refkeeper<br>&gt; &nbsp; &nbsp; in locks xlator<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; On 06/04/2014 12:02 PM, Pranith Kumar Karampuri wrote:<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; On 06/04/2014 11:37 AM, Krutika Dhananjay wrote:<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Hi,<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Recently there was a crash in locks translator (BZ 1103347,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BZ 1097102) with the following backtrace:<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (gdb) bt<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #0 &nbsp;uuid_unpack (in=0x8 &lt;Address 0x8 out of bounds&gt;,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; uu=0x7fffea6c6a60) at ../../contrib/uuid/unpack.c:44<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #1 &nbsp;0x00007feeba9e19d6 in uuid_unparse_x (uu=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;, out=0x2350fc0<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "081bbc7a-7551-44ac-85c7-aad5e2633db9",<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fmt=0x7feebaa08e00<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x") at<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ../../contrib/uuid/unparse.c:55<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #2 &nbsp;0x00007feeba9be837 in uuid_utoa (uuid=0x8 &lt;Address 0x8<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out of bounds&gt;) at common-utils.c:2138<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #3 &nbsp;0x00007feeb06e8a58 in pl_inodelk_log_cleanup<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (this=0x230d910, ctx=0x7fee700f0c60) at inodelk.c:396<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #4 &nbsp;pl_inodelk_client_cleanup (this=0x230d910,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx=0x7fee700f0c60) at inodelk.c:428<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #5 &nbsp;0x00007feeb06ddf3a in pl_client_disconnect_cbk<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (this=0x230d910, client=&lt;value optimized out&gt;) at posix.c:2550<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #6 &nbsp;0x00007feeba9fa2dd in gf_client_disconnect<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (client=0x27724a0) at client_t.c:368<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #7 &nbsp;0x00007feeab77ed48 in server_connection_cleanup<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (this=0x2316390, client=0x27724a0, flags=&lt;value optimized<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; out&gt;) at server-helpers.c:354<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #8 &nbsp;0x00007feeab77ae2c in server_rpc_notify (rpc=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;, xl=0x2316390, event=&lt;value optimized out&gt;,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data=0x2bf51c0) at server.c:527<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #9 &nbsp;0x00007feeba775155 in rpcsvc_handle_disconnect<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (svc=0x2325980, trans=0x2bf51c0) at rpcsvc.c:720<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #10 0x00007feeba776c30 in rpcsvc_notify (trans=0x2bf51c0,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mydata=&lt;value optimized out&gt;, event=&lt;value optimized out&gt;,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data=0x2bf51c0) at rpcsvc.c:758<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #11 0x00007feeba778638 in rpc_transport_notify (this=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;, event=&lt;value optimized out&gt;, data=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;) at rpc-transport.c:512<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #12 0x00007feeb115e971 in socket_event_poll_err (fd=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;, idx=&lt;value optimized out&gt;, data=0x2bf51c0,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; poll_in=&lt;value optimized out&gt;, poll_out=0,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;poll_err=0) at socket.c:1071<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #13 socket_event_handler (fd=&lt;value optimized out&gt;,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; idx=&lt;value optimized out&gt;, data=0x2bf51c0, poll_in=&lt;value<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; optimized out&gt;, poll_out=0, poll_err=0) at socket.c:2240<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #14 0x00007feeba9fc6a7 in event_dispatch_epoll_handler<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (event_pool=0x22e2d00) at event-epoll.c:384<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #15 event_dispatch_epoll (event_pool=0x22e2d00) at<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; event-epoll.c:445<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #16 0x0000000000407e93 in main (argc=19,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; argv=0x7fffea6c7f88) at glusterfsd.c:2023<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (gdb) f 4<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; #4 &nbsp;pl_inodelk_client_cleanup (this=0x230d910,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx=0x7fee700f0c60) at inodelk.c:428<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 428 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pl_inodelk_log_cleanup (l);<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (gdb) p l-&gt;pl_inode-&gt;refkeeper<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $1 = (inode_t *) 0x0<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (gdb)<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pl_inode-&gt;refkeeper was found to be NULL even when there<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; were some blocked inodelks in a certain domain of the inode,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; which when dereferenced by the epoll thread in the cleanup<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; codepath led to a crash.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; On inspecting the code (for want of a consistent<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reproducer), three things were found:<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1. The function where the crash happens<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (pl_inodelk_log_cleanup()), makes an attempt to resolve the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inode to path as can be seen below. But the way inode_path()<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; itself<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;works is to first construct the path based on the given<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inode's ancestry and place it in the buffer provided. And if<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; all else fails, the gfid of the inode is placed in a certain<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; format ("&lt;gfid:%s&gt;").<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;This eliminates the need for statements from line 4<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; through 7 below, thereby "preventing" dereferencing of<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pl_inode-&gt;refkeeper.<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Now, although this change prevents the crash<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; altogether, it still does not fix the race that led to<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pl_inode-&gt;refkeeper becoming NULL, and comes at the cost of<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printing "(null)" in the log message on line 9 every<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time pl_inode-&gt;refkeeper is found to be NULL, rendering the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; logged messages somewhat useless.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;code&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; pl_inode = lock-&gt;pl_inode;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp; &nbsp; &nbsp; &nbsp; inode_path (pl_inode-&gt;refkeeper, NULL, &amp;path);<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp; &nbsp; &nbsp; &nbsp; if (path)<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file = path;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp; &nbsp; &nbsp; &nbsp; else<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file = uuid_utoa<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (pl_inode-&gt;refkeeper-&gt;gfid);<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 8<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;9 &nbsp; &nbsp; &nbsp; &nbsp; gf_log (THIS-&gt;name, GF_LOG_WARNING,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "releasing lock on %s held by "<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 11 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "{client=%p, pid=%"PRId64" lk-owner=%s}",<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 12 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; file, lock-&gt;client, (uint64_t)<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lock-&gt;client_pid,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 13 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lkowner_utoa (&amp;lock-&gt;owner));<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;\code&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; I think this logging code is from the days when gfid handle<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; concept was not there. So it wasn't returning &lt;gfid:gfid-str&gt; in<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; cases the path is not present in the dentries. I believe the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; else block can be deleted safely now.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Pranith<br>&gt;<br>&gt; Posted patch http://review.gluster.org/#/c/7981/1 for review, to fix<br>&gt; problem #1 above.<br>&gt;<br>&gt; -Krutika<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2. There is at least one codepath found that can lead to<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this crash:<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Imagine an inode on which an inodelk operation is<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; attempted by a client and is successfully granted too.<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Now, between the time the lock was granted and<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pl_update_refkeeper() was called by this thread, the client<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; could send a DISCONNECT event,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; causing cleanup codepath to be executed, where the epoll<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; thread crashes on dereferencing pl_inode-&gt;refkeeper which is<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; STILL NULL at this point.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Besides, there are still places in locks xlator where<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; the refkeeper is NOT updated whenever the lists are modified<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - for instance in the cleanup codepath from a DISCONNECT.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3. Also, pl_update_refkeeper() seems to be not taking into<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; account blocked locks on the inode in the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; __pl_inode_is_empty() check, when it should, as there could<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; still be cases<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;where the granted list could be empty but not the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; blocked list at the time of udpating the refkeeper, in which<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case pl_inode must still take ref on the inode.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Avati,<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; There is one more issue, where pl_inode_forget is cleaning<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; up blocked/granted locks which is not handling the new<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; 'client_list'. But if we fix inode ref/unref like Kritika<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; proposed, pl_forget should never come when there is a<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; granted/blocked lock. So may be we should delete that as well.<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Please feel free to comment.<br>&gt;<br>&gt; &nbsp; &nbsp; It is pl_forget not pl_inode_forget. typo :-(.<br>&gt;<br>&gt; &nbsp; &nbsp; Pranith<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Pranith<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Proposed solution to 2/3:<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1. Do away with refkeeper in pl_inode_t altogether.<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2. Let every lock object (inodelk/entryllk/posix_lock) have<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; an inode_t * member to act as a placeholder for the<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; associated inode object on which it is locking.<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3. Let each lock object hold a ref on the inode at the time<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; of its creation and unref the inode during its destruction.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Please let me know what you think of the above.<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -Krutika<br>&gt;<br>&gt;<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _______________________________________________<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Gluster-devel mailing list<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Gluster-devel@gluster.orghttp://supercolony.gluster.org/mailman/listinfo/gluster-devel<br>&gt;<br>&gt;<br>&gt;<br>&gt;<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; _______________________________________________<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Gluster-devel mailing list<br>&gt; &nbsp; &nbsp; &nbsp; &nbsp; Gluster-devel@gluster.orghttp://supercolony.gluster.org/mailman/listinfo/gluster-devel<br>&gt;<br>&gt;<br>&gt;<br><div><br></div>To summarize, the real "problems" are:<br><div><br></div>- Deref of pl_inode-&gt;refkeeper as an inode_t in the cleanup logger. It <br>is an internal artifact of pl_update_refkeeper() working and nobody else <br>is supposed to "touch" it.</blockquote><div>For this, the solution I have in mind is to</div><div>a. have a placeholder for gfid in pl_inode_t object,</div><div>b. remember the gfid of the inode at the time of pl_inode_t creation in pl_ctx_get(), and</div><div>c. print pl_inode-&gt;gfid in the log message in pl_{inodelk,entrylk}_log_cleanup().<br></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;" data-mce-style="border-left: 2px solid #1010FF; margin-left: 5px; padding-left: 5px; color: #000; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica,Arial,sans-serif; font-size: 12pt;"><div><br></div>- Missing call to pl_update_refkeeper() in client_disconnect_cbk(). This <br>can result in a potential leak of inode ref (not a leak if the same <br>inode gets any locking activity by another client in the future).<br></blockquote><div>As far as updates to refkeeper is concerned during DISCONNECT is concerned, Pranith and I did have discussions at length but could<br>not find a single safe place in cleanup functions to call pl_update_refkeeper() that does not lead to illegal memory access,</div><div>whether before or after the call to __pl_inodelk_unref() in the third for loop.</div><div><br></div><div>Case #1 explained:<br></div><div>=============<br></div><div><br></div><div>&lt;snip&gt;<br></div><div>list_for_each_entry_safe() {<br></div><div>...<br></div><div>...<br></div><div>pl_update_refkeeper(inode);<br></div><div>pthread_mutex_lock (&amp;pl_inode-&gt;mutex);<br></div><div>&nbsp;&nbsp;&nbsp;&nbsp; __pl_inodelk_unref(l);<br></div><div>pthread_mutex_unlock (&amp;pl_inode-&gt;mutex);<br></div><div>&lt;/snip&gt;<br></div><div><br></div><div>This causes the last unref in pl_update_refkeeper() to implicitly call pl_forget() where pl_inode_t object is destroyed while it is<br></div><div>still needed in terms of having to obtain pl_inode-&gt;mutex before unrefing the lock object.<br></div><div><br></div><div>Case 2 explained:<br></div><div>=============<br></div><div><div>&lt;snip&gt;<br></div><div>list_for_each_entry_safe() {<br></div><div>...<br></div><div>...<br></div><div>pthread_mutex_lock (&amp;pl_inode-&gt;mutex);<br></div><div>&nbsp;&nbsp;&nbsp;&nbsp; __pl_inodelk_unref(l);<br></div><div>pthread_mutex_unlock (&amp;pl_inode-&gt;mutex);<br></div><div>pl_update_refkeeper(inode);</div>&lt;/snip&gt;</div><div><br></div><div>After the first for loop is processed, the domain's lists could have been emptied. And at this point, there could well come a second thread that could update refkeeper,<br></div><div>triggering last unref on the inode leading to a call to pl_forget() (where pl_inode_t is freed), after which the DISCONNECT thread would be trying to perform illegal<br></div><div>memory access in its call to pl_update_refkeeper() during its turn.<br></div><div><br></div><div>So the solution Pranith and I came up with involves making sure that the inode_t object is alive for as long as there is atleast one lock on it:<br></div><div><br></div><div>1. refkeeper will not be used for inodelks and entrylks (but will continue to be used in fcntl locks).<br></div><div>2. Each pl_inode_t object will also host an inode_t member which is initialised during a call to pl_inode_get() in pl_common_{inodelk, entrylks}().<br></div><div>3. Everytime a lock is granted/blocked, pl_inode-&gt;inode is ref'd (in pl_inode_setlk() after successful locking.<br></div><div>4. Everytime a lock is unlocked, pl_inode-&gt;inode is unref'd.<br></div><div>5. In disconnect codepath, as part of "released" list processing, the inodes associated with the client are unref'd in the same loop right after every lock object is unref'd.</div><div><br></div><div>With all this, there is one problem with the lock object that is found to be in both blocked and granted list in the transient state, when there's a race between the unlocking thread<br></div><div>and the disconnecting thread. This can be best explained with the following example:<br></div><div>&lt;example&gt;<br></div><div>Consider an inode I on which there's a granted lock G and a blocked lock B, from clients C1 and C2 respectively. With this approach, at this point the number of refs taken<br></div><div>by the locks xlator on I would be 2.<br></div><div>C1 unlocks B, at which point I's refcount becomes 1.<br></div><div>Now as part of granting other blocked locks in unlock codepath, B is put in granted list.<br></div><div>Now B's client C2 sends a DISCONNECT event, which would cause I to be unref'd again. This being the last unref, pl_forget() is called on I causing its pl_inode to be destroyed</div><div>At this point, the unlocking thread could try to do a mutex lock on pl_inode-&gt;mutex in grant_blocked_{inode,entry}_locks() (whereas pl_inode is now already destroyed) leading to a crash.</div><div>&lt;/example&gt;<br></div><div><br></div><div>The problem described in the example can be fixed by making sure grant_blocked_{inode,entry}_locks() refs the inode first thing and then unrefs it just before returning.</div><div>This would fix illegal memory access. <br></div><div>&nbsp; <br></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;" data-mce-style="border-left: 2px solid #1010FF; margin-left: 5px; padding-left: 5px; color: #000; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica,Arial,sans-serif; font-size: 12pt;">Nice to have (not necessary):<br><div><br></div>- Include blocked locks in pl_inode_is_empty(), for the sake of <br>symmetry. I don't see how this will make a difference thoough, given the <br>goal of pl_update_refkeeper (which is, ensure inode-&gt;ref &gt; 0 while a <br>user's locks are existing).</blockquote><div>Done.<br></div><blockquote style="border-left:2px solid #1010FF;margin-left:5px;padding-left:5px;color:#000;font-weight:normal;font-style:normal;text-decoration:none;font-family:Helvetica,Arial,sans-serif;font-size:12pt;" data-mce-style="border-left: 2px solid #1010FF; margin-left: 5px; padding-left: 5px; color: #000; font-weight: normal; font-style: normal; text-decoration: none; font-family: Helvetica,Arial,sans-serif; font-size: 12pt;"><div><br></div>Avati<br><div><br></div></blockquote><div><br></div></div></body></html>