Thread (3 messages) 3 messages, 3 authors, 2021-07-28

Re: [PATCH] libbtrfsutil: fix race between subvolume iterator and deletion

From: David Sterba <hidden>
Date: 2021-07-28 11:18:10

On Tue, Jul 27, 2021 at 04:53:28PM -0700, Omar Sandoval wrote:
From: Omar Sandoval <redacted>

Subvolume iteration has a window between when we get a root ref (with
BTRFS_IOC_TREE_SEARCH or BTRFS_IOC_GET_SUBVOL_ROOTREF) and when we look
up the path of the parent directory (with BTRFS_IOC_INO_LOOKUP{,_USER}).
If the subvolume is moved or deleted and its old parent directory is
deleted during that window, then BTRFS_IOC_INO_LOOKUP{,_USER} will fail
with ENOENT. The iteration will then fail with ENOENT as well.

We originally encountered this bug with an application that called
`btrfs subvolume show` (which iterates subvolumes to find snapshots) in
parallel with other threads creating and deleting subvolumes. It can be
reproduced almost instantly with the following script:

  import multiprocessing
  import os

  import btrfsutil

  def create_and_delete_subvolume(i):
      dir_name = f"subvol_iter_race{i}"
      subvol_name = dir_name + "/subvol"
      while True:
          os.mkdir(dir_name)
          btrfsutil.create_subvolume(subvol_name)
          btrfsutil.delete_subvolume(subvol_name)
          os.rmdir(dir_name)

  def iterate_subvolumes():
      fd = os.open(".", os.O_RDONLY | os.O_DIRECTORY)
      while True:
          with btrfsutil.SubvolumeIterator(fd, 5) as it:
              for _ in it:
                  pass

  if __name__ == "__main__":
      for i in range(10):
          multiprocessing.Process(target=create_and_delete_subvolume, args=(i,), daemon=True).start()
      iterate_subvolumes()
Can you please turn this into a test case?
Subvolume iteration should be robust against concurrent modifications to
subvolumes. So, if a subvolume's parent directory no longer exists, just
skip the subvolume, as it must have been deleted or moved elsewhere.

Signed-off-by: Omar Sandoval <redacted>
Added to devel, thanks.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help