[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 3/6] ext2fs: use a seperate lock to protect nodehash
From: |
Justus Winter |
Subject: |
Re: [PATCH 3/6] ext2fs: use a seperate lock to protect nodehash |
Date: |
Mon, 02 Jun 2014 07:24:59 +0200 |
User-agent: |
alot/0.3.4 |
Quoting Samuel Thibault (2014-06-02 03:41:55)
> Justus Winter, le Sun 01 Jun 2014 22:03:01 +0200, a écrit :
> > @@ -46,8 +46,18 @@
> > #define INOHASH(ino) (((unsigned)(ino))%INOHSZ)
> > #endif
> >
> > +/* The nodehash is a cache of nodes.
> > +
> > + Access to nodehash and nodehash_nr_items is protected by
> > + nodecache_lock.
> > +
> > + Every node in the nodehash carries a light reference. When we are
> > + asked to give up that light reference, we reacquire our lock
> > + momentarily to check whether someone else reacquired a reference
> > + through the nodehash. */
> > static struct node *nodehash[INOHSZ];
> > static size_t nodehash_nr_items;
> > +static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER;
>
> Please also document that this is to be taken before
> diskfs_node_refcnt_lock.
Actually, the whole point of this excercise is to get rid of
diskfs_node_refcnt_lock.
>
> > @@ -71,24 +81,22 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
> > struct node *np;
> > struct disknode *dn;
> >
> > - pthread_spin_lock (&diskfs_node_refcnt_lock);
> > + pthread_rwlock_rdlock (&nodecache_lock);
> > for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
> > if (np->cache_id == inum)
> > {
> > - np->references++;
> > - pthread_spin_unlock (&diskfs_node_refcnt_lock);
> > + diskfs_nref (np);
> > + pthread_rwlock_unlock (&nodecache_lock);
> > pthread_mutex_lock (&np->lock);
> > *npp = np;
> > return 0;
> > }
> > + pthread_rwlock_unlock (&nodecache_lock);
>
> But what if two threads call diskfs_cached_lookup for the same node at
> the same time? They'll both think it's not in the hash yet, and will
> both create the node and add it to the hash. So...
>
> > /* Format specific data for the new node. */
> > dn = malloc (sizeof (struct disknode));
> > if (! dn)
> > - {
> > - pthread_spin_unlock (&diskfs_node_refcnt_lock);
> > - return ENOMEM;
> > - }
> > + return ENOMEM;
> > dn->dirents = 0;
> > dn->dir_idx = 0;
> > dn->pager = 0;
> > @@ -102,14 +110,15 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
> > pthread_mutex_lock (&np->lock);
> >
> > /* Put NP in NODEHASH. */
> > + pthread_rwlock_wrlock (&nodecache_lock);
>
> ... after taking the pthread_rwlock_wrlock again in wr mode, you need to
> check for the existence of the node again.
Good point...
Justus
>
> > dn->hnext = nodehash[INOHASH(inum)];
> > if (dn->hnext)
> > dn->hnext->dn->hprevp = &dn->hnext;
> > dn->hprevp = &nodehash[INOHASH(inum)];
> > nodehash[INOHASH(inum)] = np;
> > + diskfs_nref_light (np);
> > nodehash_nr_items += 1;
> > -
> > - pthread_spin_unlock (&diskfs_node_refcnt_lock);
> > + pthread_rwlock_unlock (&nodecache_lock);
> >
> > /* Get the contents of NP off disk. */
> > err = read_node (np);
>
> Samuel