Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / btrfs / volumes.c
index ec3a874..464485a 100644 (file)
@@ -558,6 +558,8 @@ static int btrfs_free_stale_devices(const char *path,
        struct btrfs_device *device, *tmp_device;
        int ret = 0;
 
+       lockdep_assert_held(&uuid_mutex);
+
        if (path)
                ret = -ENOENT;
 
@@ -988,11 +990,12 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
        struct btrfs_device *orig_dev;
        int ret = 0;
 
+       lockdep_assert_held(&uuid_mutex);
+
        fs_devices = alloc_fs_devices(orig->fsid, NULL);
        if (IS_ERR(fs_devices))
                return fs_devices;
 
-       mutex_lock(&orig->device_list_mutex);
        fs_devices->total_devices = orig->total_devices;
 
        list_for_each_entry(orig_dev, &orig->devices, dev_list) {
@@ -1024,10 +1027,8 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
        }
-       mutex_unlock(&orig->device_list_mutex);
        return fs_devices;
 error:
-       mutex_unlock(&orig->device_list_mutex);
        free_fs_devices(fs_devices);
        return ERR_PTR(ret);
 }
@@ -1869,15 +1870,17 @@ out:
  * Function to update ctime/mtime for a given device path.
  * Mainly used for ctime/mtime based probe like libblkid.
  */
-static void update_dev_time(const char *path_name)
+static void update_dev_time(struct block_device *bdev)
 {
-       struct file *filp;
+       struct inode *inode = bdev->bd_inode;
+       struct timespec64 now;
 
-       filp = filp_open(path_name, O_RDWR, 0);
-       if (IS_ERR(filp))
+       /* Shouldn't happen but just in case. */
+       if (!inode)
                return;
-       file_update_time(filp);
-       filp_close(filp, NULL);
+
+       now = current_time(inode);
+       generic_update_time(inode, &now, S_MTIME | S_CTIME);
 }
 
 static int btrfs_rm_dev_item(struct btrfs_device *device)
@@ -2053,11 +2056,11 @@ void btrfs_scratch_superblocks(struct btrfs_fs_info *fs_info,
        btrfs_kobject_uevent(bdev, KOBJ_CHANGE);
 
        /* Update ctime/mtime for device path for libblkid */
-       update_dev_time(device_path);
+       update_dev_time(bdev);
 }
 
 int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
-                   u64 devid)
+                   u64 devid, struct block_device **bdev, fmode_t *mode)
 {
        struct btrfs_device *device;
        struct btrfs_fs_devices *cur_devices;
@@ -2171,15 +2174,26 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,
        mutex_unlock(&fs_devices->device_list_mutex);
 
        /*
-        * at this point, the device is zero sized and detached from
-        * the devices list.  All that's left is to zero out the old
-        * supers and free the device.
+        * At this point, the device is zero sized and detached from the
+        * devices list.  All that's left is to zero out the old supers and
+        * free the device.
+        *
+        * We cannot call btrfs_close_bdev() here because we're holding the sb
+        * write lock, and blkdev_put() will pull in the ->open_mutex on the
+        * block device and it's dependencies.  Instead just flush the device
+        * and let the caller do the final blkdev_put.
         */
-       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state))
+       if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state)) {
                btrfs_scratch_superblocks(fs_info, device->bdev,
                                          device->name->str);
+               if (device->bdev) {
+                       sync_blockdev(device->bdev);
+                       invalidate_bdev(device->bdev);
+               }
+       }
 
-       btrfs_close_bdev(device);
+       *bdev = device->bdev;
+       *mode = device->mode;
        synchronize_rcu();
        btrfs_free_device(device);
 
@@ -2706,7 +2720,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
        btrfs_forget_devices(device_path);
 
        /* Update ctime/mtime for blkid or udev */
-       update_dev_time(device_path);
+       update_dev_time(bdev);
 
        return ret;