From c16eed2cb64089bf7d958db0fe85352f4ceefb4d Mon Sep 17 00:00:00 2001 From: Justus Winter <4winter@informatik.uni-hamburg.de> Date: Wed, 14 May 2014 11:19:35 +0200 Subject: libdiskfs: lock-less reference counting of nodes * libdiskfs/diskfs.h (struct node): Use refcounts_t for reference counting. (diskfs_node_refcnt_lock): Remove. (diskfs_node_norefs,diskfs_drop_node): Change comments accordingly. * libdiskfs/init-init.c: Adjust accordingly. * libdiskfs/node-drop.c: Likewise. * libdiskfs/node-make.c: Likewise. * libdiskfs/node-nput.c: Likewise. * libdiskfs/node-nputl.c: Likewise. * libdiskfs/node-nref.c: Likewise. * libdiskfs/node-nrefl.c: Likewise. * libdiskfs/node-nrele.c: Likewise. * libdiskfs/node-nrelel.c: Likewise. * ext2fs/inode.c: Likewise. * fatfs/inode.c: Likewise. * isofs/inode.c: Likewise. * tmpfs/node.c: Likewise. * doc/hurd.texi: Likewise. --- libdiskfs/node-nput.c | 52 ++++++++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 32 deletions(-) (limited to 'libdiskfs/node-nput.c') diff --git a/libdiskfs/node-nput.c b/libdiskfs/node-nput.c index 5043ad1a..d23c1037 100644 --- a/libdiskfs/node-nput.c +++ b/libdiskfs/node-nput.c @@ -26,56 +26,44 @@ void diskfs_nput (struct node *np) { - int tried_drop_softrefs = 0; + struct references result; - loop: - pthread_spin_lock (&diskfs_node_refcnt_lock); - assert (np->references); - np->references--; - if (np->references + np->light_references == 0) - diskfs_drop_node (np); - else if (np->references == 0 && !tried_drop_softrefs) - { - pthread_spin_unlock (&diskfs_node_refcnt_lock); + /* While we call the diskfs_try_dropping_softrefs, we need to hold + one reference. We use a weak reference for this purpose, which + we acquire by demoting our hard reference to a weak one. */ + refcounts_demote (&np->refcounts, &result); + if (result.hard == 0) + { /* This is our cue that something akin to "last process closes file" in the POSIX.1 sense happened, so make sure any pending node time updates now happen in a timely fashion. */ diskfs_set_node_times (np); - diskfs_lost_hardrefs (np); if (!np->dn_stat.st_nlink) { - /* There are no links. If there are soft references that - can be dropped, we can't let them postpone deallocation. - So attempt to drop them. But that's a user-supplied - routine, which might result in further recursive calls to - the ref-counting system. So we have to reacquire our - reference around the call to forestall disaster. */ - pthread_spin_lock (&diskfs_node_refcnt_lock); - np->references++; - pthread_spin_unlock (&diskfs_node_refcnt_lock); - if (np->sockaddr != MACH_PORT_NULL) { mach_port_deallocate (mach_task_self (), np->sockaddr); np->sockaddr = MACH_PORT_NULL; } + /* There are no links. If there are soft references that + can be dropped, we can't let them postpone deallocation. + So attempt to drop them. But that's a user-supplied + routine, which might result in further recursive calls to + the ref-counting system. This is not a problem, as we + hold a weak reference ourselves. */ diskfs_try_dropping_softrefs (np); - - /* But there's no value in looping forever in this - routine; only try to drop soft refs once. */ - tried_drop_softrefs = 1; - - /* Now we can drop the reference back... */ - goto loop; } pthread_mutex_unlock (&np->lock); } + + /* Finally get rid of our reference. */ + refcounts_deref_weak (&np->refcounts, &result); + + if (result.hard == 0 && result.weak == 0) + diskfs_drop_node (np); else - { - pthread_spin_unlock (&diskfs_node_refcnt_lock); - pthread_mutex_unlock (&np->lock); - } + pthread_mutex_unlock (&np->lock); } -- cgit v1.2.3