• Filipe Manana's avatar
    Btrfs: fix race between enabling quotas and subvolume creation · 552f0329
    Filipe Manana authored
    We have a race between enabling quotas end subvolume creation that cause
    subvolume creation to fail with -EINVAL, and the following diagram shows
    how it happens:
    
                  CPU 0                                          CPU 1
    
     btrfs_ioctl()
      btrfs_ioctl_quota_ctl()
       btrfs_quota_enable()
        mutex_lock(fs_info->qgroup_ioctl_lock)
    
                                                      btrfs_ioctl()
                                                       create_subvol()
                                                        btrfs_qgroup_inherit()
                                                         -> save fs_info->quota_root
                                                            into quota_root
                                                         -> stores a NULL value
                                                         -> tries to lock the mutex
                                                            qgroup_ioctl_lock
                                                            -> blocks waiting for
                                                               the task at CPU0
    
       -> sets BTRFS_FS_QUOTA_ENABLED in fs_info
       -> sets quota_root in fs_info->quota_root
          (non-NULL value)
    
       mutex_unlock(fs_info->qgroup_ioctl_lock)
    
                                                         -> checks quota enabled
                                                            flag is set
                                                         -> returns -EINVAL because
                                                            fs_info->quota_root was
                                                            NULL before it acquired
                                                            the mutex
                                                            qgroup_ioctl_lock
                                                       -> ioctl returns -EINVAL
    
    Returning -EINVAL to user space will be confusing if all the arguments
    passed to the subvolume creation ioctl were valid.
    
    Fix it by grabbing the value from fs_info->quota_root after acquiring
    the mutex.
    
    CC: stable@vger.kernel.org # 4.4+
    Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    552f0329
qgroup.c 97.5 KB