@@ -1519,6 +1519,15 @@ struct btrfs_new_fs_root_args *btrfs_alloc_new_fs_root_args(void)
if (err)
goto error;
+ args->snapshot_lock = kzalloc(sizeof(*args->snapshot_lock), GFP_KERNEL);
+ if (!args->snapshot_lock) {
+ err = -ENOMEM;
+ goto error;
+ }
+ err = btrfs_drew_lock_init(args->snapshot_lock);
+ if (err)
+ goto error;
+
return args;
error:
@@ -1530,6 +1539,10 @@ void btrfs_free_new_fs_root_args(struct btrfs_new_fs_root_args *args)
{
if (!args)
return;
+ if (args->snapshot_lock) {
+ btrfs_drew_lock_destroy(args->snapshot_lock);
+ kfree(args->snapshot_lock);
+ }
if (args->anon_dev)
free_anon_bdev(args->anon_dev);
kfree(args);
@@ -1546,20 +1559,25 @@ static int btrfs_init_fs_root(struct btrfs_root *root,
int ret;
unsigned int nofs_flag;
- root->snapshot_lock = kzalloc(sizeof(*root->snapshot_lock), GFP_NOFS);
- if (!root->snapshot_lock) {
- ret = -ENOMEM;
- goto fail;
+ if (new_fs_root_args && new_fs_root_args->snapshot_lock) {
+ root->snapshot_lock = new_fs_root_args->snapshot_lock;
+ new_fs_root_args->snapshot_lock = NULL;
+ } else {
+ root->snapshot_lock = kzalloc(sizeof(*root->snapshot_lock), GFP_NOFS);
+ if (!root->snapshot_lock) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ /*
+ * We might be called under a transaction (e.g. indirect backref
+ * resolution) which could deadlock if it triggers memory reclaim.
+ */
+ nofs_flag = memalloc_nofs_save();
+ ret = btrfs_drew_lock_init(root->snapshot_lock);
+ memalloc_nofs_restore(nofs_flag);
+ if (ret)
+ goto fail;
}
- /*
- * We might be called under a transaction (e.g. indirect backref
- * resolution) which could deadlock if it triggers memory reclaim
- */
- nofs_flag = memalloc_nofs_save();
- ret = btrfs_drew_lock_init(root->snapshot_lock);
- memalloc_nofs_restore(nofs_flag);
- if (ret)
- goto fail;
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
!btrfs_is_data_reloc_root(root)) {
@@ -28,6 +28,8 @@ static inline u64 btrfs_sb_offset(int mirror)
struct btrfs_new_fs_root_args {
/* Preallocated anonymous block device number */
dev_t anon_dev;
+ /* Preallocated snapshot lock */
+ struct btrfs_drew_lock *snapshot_lock;
};
struct btrfs_device;