[pnfs] [PATCH 4/6] pnfs: remove spin_unlock from put_unlock_current_layout

William A. (Andy) Adamson androsadamson at gmail.com
Thu Jul 24 08:37:55 EDT 2008


On Wed, Jul 23, 2008 at 4:44 PM, Fredric Isaman <iisaman at citi.umich.edu> wrote:
>
>
> On Wed, 23 Jul 2008, andros at netapp.com wrote:
>
>> From: Andy Adamson <andros at localhost.localdomain>
>>
>> Separate the unlocking of the nfs_inode lo_lock from the
>> pnfs_layout_type reference counting.
>>
>> This allows us to get rid of un-needed lock/unlock just to decrement the
>> atomic ref count.
>>
>> Signed-off-by: Andy Adamson<andros at netapp.com>
>> ---
>> fs/nfs/pnfs.c |   32 ++++++++++++++++----------------
>> 1 files changed, 16 insertions(+), 16 deletions(-)
>>
>> diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
>> index 26e4c7f..d5f2b07 100644
>> --- a/fs/nfs/pnfs.c
>> +++ b/fs/nfs/pnfs.c
>> @@ -343,19 +343,22 @@ destroy_layout(struct kref *kref)
>>       struct nfs_client *clp = NFS_SERVER(&nfsi->vfs_inode)->nfs_client;
>>
>>       dprintk("%s: freeing layout %p\n", __func__, lo);
>> +
>> +     spin_lock(&nfsi->lo_lock);
>>       io_ops->free_layout(lo);
>>
>>       nfsi->current_layout = NULL;
>
> Does nfsi->current_layout count as a reference or not?  As is, the patch
> series says not, but this leaves a window where it is possible to do a
> kref_get based on nfsi->current_layout while it is in the process of being
> destroyed.  Once the entire patch series is applied, you can get in this
> situation:
>
> thread1           thread2
> kref_put()
> refcnt==0
>                   pnfs_update_layout() (no lsegs, so...)
>                   get_layout()
> destroy_layout()
> current_layout==NULL
>
>                   pnfs_layout_process()
>                   CRASH

You're right, the above can happen. But, I don't think it's because of
a reference on
the nfsi->current_layout. It's because I removed the spin_lock from
put_unlock_current_layout.
With the lo_lock held, when thread1 puts the refcnt to zero, thread2
would be blocked in pnfs_update_layout from obtaining
nfsi->current_layout, and thread1 would destroy_layout prior to
thread2 getting the layout..

I'll leave put_unlock_current_layout alone.

-->Andy


> Fred
>
>> +     spin_unlock(&nfsi->lo_lock);
>>
>>       /* Unlist the inode.
>> -     * Note that nfsi->lo_lock must be released before getting
>> -     * cl_sem as the latter can sleep
>> -     */
>> -     spin_unlock(&nfsi->lo_lock);
>> +      * Note that nfsi->lo_lock must be released before getting
>> +      * cl_sem as the latter can sleep
>> +      */
>>       down_write(&clp->cl_sem);
>>       spin_lock(&nfsi->lo_lock);
>>       if (!nfsi->current_layout)
>>               list_del_init(&nfsi->lo_inodes);
>> +     spin_unlock(&nfsi->lo_lock);
>>       up_write(&clp->cl_sem);
>> }
>>
>> @@ -363,21 +366,15 @@ destroy_layout(struct kref *kref)
>>  * put and unlock nfs->current_layout
>>  */
>> static inline void
>> -put_unlock_current_layout(struct nfs_inode *nfsi,
>> -                         struct pnfs_layout_type *lo)
>> +put_current_layout(struct pnfs_layout_type *lo)
>> {
>> -     BUG_ON_UNLOCKED_LO(lo);
>>       kref_put(&lo->refcount, destroy_layout);
>> -     spin_unlock(&nfsi->lo_lock);
>> }
>>
>> void
>> pnfs_layout_release(struct pnfs_layout_type *lo)
>> {
>> -     struct nfs_inode *nfsi = NFS_I(lo->inode);
>> -
>> -     spin_lock(&nfsi->lo_lock);
>> -     put_unlock_current_layout(nfsi, lo);
>> +     put_current_layout(lo);
>> }
>>
>> static inline void
>> @@ -754,7 +751,7 @@ static int pnfs_wait_schedule(void *word)
>>  * get, possibly allocate, and lock current_layout
>>  *
>>  * Note: If successful, nfsi->lo_lock is taken and the caller
>> - * must put and unlock current_layout by using put_unlock_current_layout()
>> + * must put and unlock current_layout
>>  * when the returned layout is released.
>>  */
>> static struct pnfs_layout_type *
>> @@ -867,7 +864,8 @@ pnfs_find_get_lseg(struct inode *inode,
>>       range.offset = pos;
>>       range.length = count;
>>       lseg = pnfs_has_layout(lo, &range, 1);
>> -     put_unlock_current_layout(nfsi, lo);
>> +     spin_unlock(&nfsi->lo_lock);
>> +     put_current_layout(lo);
>>       return lseg;
>> }
>>
>> @@ -941,7 +939,8 @@ out:
>> out_put:
>>       if (lsegpp)
>>               *lsegpp = lseg;
>> -     put_unlock_current_layout(nfsi, lo);
>> +     spin_unlock(&nfsi->lo_lock);
>> +     put_current_layout(lo);
>>       goto out;
>> }
>>
>> @@ -1162,7 +1161,8 @@ pnfs_getboundary(struct inode *inode)
>>       lo = get_lock_current_layout(nfsi);;
>>       if (lo) {
>>               stripe_size = policy_ops->get_stripesize(lo);
>> -             put_unlock_current_layout(nfsi, lo);
>> +             spin_unlock(&nfsi->lo_lock);
>> +             put_current_layout(lo);
>>       }
>> out:
>>       return stripe_size;
>> --
>> 1.5.4.1
>>
>> _______________________________________________
>> pNFS mailing list
>> pNFS at linux-nfs.org
>> http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
>>
> _______________________________________________
> pNFS mailing list
> pNFS at linux-nfs.org
> http://linux-nfs.org/cgi-bin/mailman/listinfo/pnfs
>
>


More information about the pNFS mailing list