• David Howells's avatar
    afs: Fix directory page locking · b61f7dcf
    David Howells authored
    The afs directory loading code (primarily afs_read_dir()) locks all the
    pages that hold a directory's content blob to defend against
    getdents/getdents races and getdents/lookup races where the competitors
    issue conflicting reads on the same data.  As the reads will complete
    consecutively, they may retrieve different versions of the data and
    one may overwrite the data that the other is busy parsing.
    
    Fix this by not locking the pages at all, but rather by turning the
    validation lock into an rwsem and getting an exclusive lock on it whilst
    reading the data or validating the attributes and a shared lock whilst
    parsing the data.  Sharing the attribute validation lock should be fine as
    the data fetch will retrieve the attributes also.
    
    The individual page locks aren't needed at all as the only place they're
    being used is to serialise data loading.
    
    Without this patch, the:
    
     	if (!test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) {
    		...
    	}
    
    part of afs_read_dir() may be skipped, leaving the pages unlocked when we
    hit the success: clause - in which case we try to unlock the not-locked
    pages, leading to the following oops:
    
      page:ffffe38b405b4300 count:3 mapcount:0 mapping:ffff98156c83a978 index:0x0
      flags: 0xfffe000001004(referenced|private)
      raw: 000fffe000001004 ffff98156c83a978 0000000000000000 00000003ffffffff
      raw: dead000000000100 dead000000000200 0000000000000001 ffff98156b27c000
      page dumped because: VM_BUG_ON_PAGE(!PageLocked(page))
      page->mem_cgroup:ffff98156b27c000
      ------------[ cut here ]------------
      kernel BUG at mm/filemap.c:1205!
      ...
      RIP: 0010:unlock_page+0x43/0x50
      ...
      Call Trace:
       afs_dir_iterate+0x789/0x8f0 [kafs]
       ? _cond_resched+0x15/0x30
       ? kmem_cache_alloc_trace+0x166/0x1d0
       ? afs_do_lookup+0x69/0x490 [kafs]
       ? afs_do_lookup+0x101/0x490 [kafs]
       ? key_default_cmp+0x20/0x20
       ? request_key+0x3c/0x80
       ? afs_lookup+0xf1/0x340 [kafs]
       ? __lookup_slow+0x97/0x150
       ? lookup_slow+0x35/0x50
       ? walk_component+0x1bf/0x490
       ? path_lookupat.isra.52+0x75/0x200
       ? filename_lookup.part.66+0xa0/0x170
       ? afs_end_vnode_operation+0x41/0x60 [kafs]
       ? __check_object_size+0x9c/0x171
       ? strncpy_from_user+0x4a/0x170
       ? vfs_statx+0x73/0xe0
       ? __do_sys_newlstat+0x39/0x70
       ? __x64_sys_getdents+0xc9/0x140
       ? __x64_sys_getdents+0x140/0x140
       ? do_syscall_64+0x5b/0x160
       ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
    
    Fixes: f3ddee8d ("afs: Fix directory handling")
    Reported-by: default avatarMarc Dionne <marc.dionne@auristor.com>
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    b61f7dcf
inode.c 14.5 KB