On 2019/2/15 17:09, Gao Xiang wrote:
> Hi Chao,
> 
> On 2019/2/15 15:29, Chao Yu wrote:
>> On 2019/2/14 23:34, Gao Xiang wrote:
>>> In real scenario, there could be several threads accessing xattrs
>>> of the same xattr-uninitialized inode, and init_inode_xattrs()
>>> almost at the same time.
>>
>> Yeah, nice catch!
>>
>>>
>>> That's actually an unexpected behavior, this patch closes the race.
>>>
>>> Fixes: b17500a0fdba ("staging: erofs: introduce xattr & acl support")
>>> Cc: <[email protected]> # 4.19+
>>> Signed-off-by: Gao Xiang <[email protected]>
>>> ---
>>>  drivers/staging/erofs/internal.h | 11 ++++++++---
>>>  drivers/staging/erofs/xattr.c    | 41 
>>> ++++++++++++++++++++++++++++------------
>>>  2 files changed, 37 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/staging/erofs/internal.h 
>>> b/drivers/staging/erofs/internal.h
>>> index 3a27c255950b..e3bfde00c7d2 100644
>>> --- a/drivers/staging/erofs/internal.h
>>> +++ b/drivers/staging/erofs/internal.h
>>> @@ -327,12 +327,17 @@ static inline erofs_off_t iloc(struct erofs_sb_info 
>>> *sbi, erofs_nid_t nid)
>>>     return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
>>>  }
>>>  
>>> -#define inode_set_inited_xattr(inode)   (EROFS_V(inode)->flags |= 1)
>>> -#define inode_has_inited_xattr(inode)   (EROFS_V(inode)->flags & 1)
>>> +/* atomic flag definitions */
>>> +#define EROFS_V_EA_INITED_BIT      0
>>> +
>>> +/* bitlock definitions (arranged in reverse order) */
>>> +#define EROFS_V_BL_XATTR_BIT       (BITS_PER_LONG - 1)
>>>  
>>>  struct erofs_vnode {
>>>     erofs_nid_t nid;
>>> -   unsigned int flags;
>>> +
>>> +   /* atomic flags (including bitlocks) */
>>> +   unsigned long flags;
>>>  
>>>     unsigned char data_mapping_mode;
>>>     /* inline size in bytes */
>>> diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c
>>> index 8c48b0ab31fd..a188aad00bf8 100644
>>> --- a/drivers/staging/erofs/xattr.c
>>> +++ b/drivers/staging/erofs/xattr.c
>>> @@ -44,18 +44,25 @@ static inline void xattr_iter_end_final(struct 
>>> xattr_iter *it)
>>>  
>>>  static int init_inode_xattrs(struct inode *inode)
>>>  {
>>> +   struct erofs_vnode *const vi = EROFS_V(inode);
>>>     struct xattr_iter it;
>>>     unsigned int i;
>>>     struct erofs_xattr_ibody_header *ih;
>>>     struct super_block *sb;
>>>     struct erofs_sb_info *sbi;
>>> -   struct erofs_vnode *vi;
>>>     bool atomic_map;
>>> +   int ret = 0;
>>>  
>>> -   if (likely(inode_has_inited_xattr(inode)))
>>> +   /* the most case is that xattrs of this inode are initialized. */
>>> +   if (likely(test_bit(EROFS_V_EA_INITED_BIT, &vi->flags)))
>>>             return 0;
>>>  
>>> -   vi = EROFS_V(inode);
>>> +   if (wait_on_bit_lock(&vi->flags, EROFS_V_BL_XATTR_BIT, TASK_KILLABLE))
>>> +           return -ERESTARTSYS;
>>> +
>>> +   /* someone has initialized xattrs for us? */
>>> +   if (unlikely(test_bit(EROFS_V_EA_INITED_BIT, &vi->flags)))
>>> +           goto out_unlock;
>>>  
>>>     /*
>>>      * bypass all xattr operations if ->xattr_isize is not greater than
>>> @@ -68,13 +75,16 @@ static int init_inode_xattrs(struct inode *inode)
>>>     if (vi->xattr_isize == sizeof(struct erofs_xattr_ibody_header)) {
>>>             errln("xattr_isize %d of nid %llu is not supported yet",
>>>                   vi->xattr_isize, vi->nid);
>>> -           return -ENOTSUPP;
>>> +           ret = -ENOTSUPP;
>>> +           goto out_unlock;
>>>     } else if (vi->xattr_isize < sizeof(struct erofs_xattr_ibody_header)) {
>>>             if (unlikely(vi->xattr_isize)) {
>>>                     DBG_BUGON(1);
>>> -                   return -EIO;    /* xattr ondisk layout error */
>>> +                   ret = -EIO;
>>> +                   goto out_unlock;        /* xattr ondisk layout error */
>>>             }
>>> -           return -ENOATTR;
>>> +           ret = -ENOATTR;
>>> +           goto out_unlock;
>>>     }
>>>  
>>>     sb = inode->i_sb;
>>> @@ -83,8 +93,10 @@ static int init_inode_xattrs(struct inode *inode)
>>>     it.ofs = erofs_blkoff(iloc(sbi, vi->nid) + vi->inode_isize);
>>>  
>>>     it.page = erofs_get_inline_page(inode, it.blkaddr);
>>> -   if (IS_ERR(it.page))
>>> -           return PTR_ERR(it.page);
>>> +   if (IS_ERR(it.page)) {
>>> +           ret = PTR_ERR(it.page);
>>> +           goto out_unlock;
>>> +   }
>>>  
>>>     /* read in shared xattr array (non-atomic, see kmalloc below) */
>>>     it.kaddr = kmap(it.page);
>>> @@ -97,7 +109,8 @@ static int init_inode_xattrs(struct inode *inode)
>>>                                             sizeof(uint), GFP_KERNEL);
>>>     if (vi->xattr_shared_xattrs == NULL) {
>>>             xattr_iter_end(&it, atomic_map);
>>> -           return -ENOMEM;
>>> +           ret = -ENOMEM;
>>> +           goto out_unlock;
>>>     }
>>>  
>>>     /* let's skip ibody header */
>>> @@ -114,7 +127,8 @@ static int init_inode_xattrs(struct inode *inode)
>>>                     if (IS_ERR(it.page)) {
>>>                             kfree(vi->xattr_shared_xattrs);
>>>                             vi->xattr_shared_xattrs = NULL;
>>> -                           return PTR_ERR(it.page);
>>> +                           ret = PTR_ERR(it.page);
>>> +                           goto out_unlock;
>>>                     }
>>>  
>>>                     it.kaddr = kmap_atomic(it.page);
>>> @@ -127,8 +141,11 @@ static int init_inode_xattrs(struct inode *inode)
>>>     }
>>>     xattr_iter_end(&it, atomic_map);
>>>  
>>> -   inode_set_inited_xattr(inode);
>>> -   return 0;
>>> +   set_bit(EROFS_V_EA_INITED_BIT, &vi->flags);
>>
>> Should it be?
>>
>> set_bit();
>> wake_up_bit();
>> return 0;
> 
> set_bit(EROFS_V_EA_INITED_BIT, &vi->flags);    <- set xattrs initialized
> clear_and_wake_up_bit(EROFS_V_BL_XATTR_BIT, &vi->flags);  <- clear 
> EROFS_V_BL_XATTR_BIT bitlock and wake up waiting tasks...

Yes, you're right, I just missed some points...

Reviewed-by: Chao Yu <[email protected]>

Thanks,

> 
> Thanks,
> Gao Xiang
> 
>>
>>> +
>>> +out_unlock:
>>> +   clear_and_wake_up_bit(EROFS_V_BL_XATTR_BIT, &vi->flags);
>>> +   return ret;
>>>  }
>>>  
>>>  /*
>>>
>>
> 
> .
> 

Reply via email to