[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 08/13] trans: fix reference counting and destruction of fake
From: |
Samuel Thibault |
Subject: |
Re: [PATCH 08/13] trans: fix reference counting and destruction of fake nodes |
Date: |
Tue, 10 Dec 2013 01:09:40 +0100 |
User-agent: |
Mutt/1.5.21+34 (58baf7c9f32f) (2010-12-30) |
Justus Winter, le Mon 09 Dec 2013 15:16:36 +0100, a écrit :
> Previously, fakeroot tried to do too much in netfs_node_norefs. This
> function is meant to deallocate nodes. Fakeroot however also tries to
> remove the node from the hash table and to prolong the lifetime of the
> node object by re-referencing it.
>
> Removing the object from the hash table is highly problematic, because
> at this point we already have the node locked. With proper locking in
> netfs_S_dir_lookup, acquiring the hash table lock while we hold the
> node locked results in dead-locks, releasing the node lock before
> acquiring the hash table lock results in a race condition.
>
> Prolonging the lifetime of the node by re-acquiring a reference is
> clearly a hack that surprisingly works to some degree. The nodes
> transbox, however, is already gone at this point.
>
> This code was never actually run because of a reference-counting bug
> in fakeroot.
>
> Fix this by installing our own clean routine in the
> netfs_protid_class. This function is called without the associated
> node being locked, allowing us to acquire the locks in the proper
> order and to keep the hash table locked while the node is being
> destroyed.
Ack.
> * trans/fakeroot.c (netfs_node_norefs): Just free the associated
> resources.
> (fakeroot_netfs_release_protid): New function doing cleanly what
> netfs_node_norefs did before.
> (netfs_S_dir_lookup): Reuse the fake reference.
> (main): Install fakeroot_netfs_release_protid as clean routine.
>
> fixup_fix_refc_destruction
> ---
> trans/fakeroot.c | 71
> ++++++++++++++++++++++++++++++++++++++----------------
> 1 file changed, 50 insertions(+), 21 deletions(-)
>
> diff --git a/trans/fakeroot.c b/trans/fakeroot.c
> index 1233104..eff5225 100644
> --- a/trans/fakeroot.c
> +++ b/trans/fakeroot.c
> @@ -128,6 +128,31 @@ void
> netfs_node_norefs (struct node *np)
> {
> assert (np->nn->np == np);
> + mach_port_deallocate (mach_task_self (), np->nn->file);
> + mach_port_deallocate (mach_task_self (), np->nn->idport);
> + free (np->nn);
> + free (np);
> +}
> +
> +/* This is the cleanup function we install in netfs_protid_class. If
> + the associated nodes reference count would also drop to zero, and
> + the node has no faked attributes, we destroy it as well. */
> +static void
> +fakeroot_netfs_release_protid (void *cookie)
> +{
> + struct node *np = ((struct protid *) cookie)->po->np;
> + assert (np->nn->np == np);
> +
> + pthread_mutex_lock (&idport_ihash_lock);
> + pthread_mutex_lock (&np->lock);
> +
> + assert ((np->nn->faked & FAKE_REFERENCE) == 0);
> +
> + /* Check if someone else reacquired a reference to the node besides
> + ours that is about to be dropped. */
> + if (np->references > 1)
> + goto out;
> +
> if (np->nn->faked != 0
> && netfs_validate_stat (np, 0) == 0 && np->nn_stat.st_nlink > 0)
> {
> @@ -139,30 +164,24 @@ netfs_node_norefs (struct node *np)
> until this fakeroot filesystem dies. One easy solution
> would be to scan nodes with references=1 for st_nlink=0
> at some convenient time, periodically or in syncfs. */
> - if ((np->nn->faked & FAKE_REFERENCE) == 0)
> - {
> - np->nn->faked |= FAKE_REFERENCE;
> - ++np->references;
> - }
> - pthread_mutex_unlock (&np->lock);
> - return;
> - }
>
> - pthread_spin_unlock (&netfs_node_refcnt_lock); /* Avoid deadlock. */
> - pthread_mutex_lock (&idport_ihash_lock);
> - pthread_spin_lock (&netfs_node_refcnt_lock);
> - /* Previous holder of this lock might have just got a reference. */
> - if (np->references > 0)
> - {
> - pthread_mutex_unlock (&idport_ihash_lock);
> - return;
> + /* Keep a fake reference. */
> + netfs_nref (np);
> +
> + /* Set the FAKE_REFERENCE flag so that we can properly
> + account for that fake reference. */
> + np->nn->faked |= FAKE_REFERENCE;
> +
> + /* We keep our node. */
> + goto out;
> }
> +
> hurd_ihash_locp_remove (&idport_ihash, np->nn->idport_locp);
> +
> + out:
> + pthread_mutex_unlock (&np->lock);
> + netfs_release_protid (cookie);
> pthread_mutex_unlock (&idport_ihash_lock);
> - mach_port_deallocate (mach_task_self (), np->nn->file);
> - mach_port_deallocate (mach_task_self (), np->nn->idport);
> - free (np->nn);
> - free (np);
> }
>
> /* Given an existing node, make sure it has NEWMODES in its openmodes.
> @@ -326,7 +345,14 @@ netfs_S_dir_lookup (struct protid *diruser,
> pthread_mutex_lock (&np->lock);
> err = check_openmodes (np->nn, (flags & (O_RDWR|O_EXEC)), file);
> if (!err)
> - netfs_nref (np);
> + {
> + /* If the looked-up file carries a fake reference, we
> + use that and clear the FAKE_REFERENCE flag. */
> + if (np->nn->faked & FAKE_REFERENCE)
> + np->nn->faked &= ~FAKE_REFERENCE;
> + else
> + netfs_nref (np);
> + }
> pthread_mutex_unlock (&np->lock);
> pthread_mutex_unlock (&idport_ihash_lock);
> }
> @@ -957,6 +983,9 @@ any user to open nodes regardless of permissions as is
> done for root." };
> task_get_bootstrap_port (mach_task_self (), &bootstrap);
> netfs_init ();
>
> + /* Install our own clean routine. */
> + netfs_protid_class->clean_routine = fakeroot_netfs_release_protid;
> +
> /* Get our underlying node (we presume it's a directory) and use
> that to make the root node of the filesystem. */
> err = new_node (netfs_startup (bootstrap, O_READ), MACH_PORT_NULL, 0,
> O_READ,
> --
> 1.7.10.4
>
--
Samuel
<m> bouhouhouh, b il m'a abandonné. Tout ca parce que je regardais plus mon
emacs que lui !
<m> s/lui/ses messages irc/
-+- #ens-mim esseulé -+-
- Re: [PATCH 03/13] trans: fix the use of the hash table in fakeroot.c, (continued)
- [PATCH 08/13] trans: fix reference counting and destruction of fake nodes, Justus Winter, 2013/12/09
- Re: [PATCH 08/13] trans: fix reference counting and destruction of fake nodes,
Samuel Thibault <=
- [PATCH 11/13] trans: improve the error handling in fakeauth, Justus Winter, 2013/12/09
- [PATCH 09/13] trans: fix locking in fakeroot's netfs_S_dir_lookup, Justus Winter, 2013/12/09
- [PATCH 12/13] trans: unlock nodes with faked attributes in fakeroot, Justus Winter, 2013/12/09
- [PATCH 05/13] trans: handle invalid responses to dir_lookup requests in fakeroot, Justus Winter, 2013/12/09
- [PATCH 10/13] trans: fix reference counting bug in fakeroot, Justus Winter, 2013/12/09