@@ -4320,6 +4320,110 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
4320
4320
return ret ;
4321
4321
}
4322
4322
4323
+ /*
4324
+ * Log all prealloc extents beyond the inode's i_size to make sure we do not
4325
+ * lose them after doing a fast fsync and replaying the log. We scan the
4326
+ * subvolume's root instead of iterating the inode's extent map tree because
4327
+ * otherwise we can log incorrect extent items based on extent map conversion.
4328
+ * That can happen due to the fact that extent maps are merged when they
4329
+ * are not in the extent map tree's list of modified extents.
4330
+ */
4331
+ static int btrfs_log_prealloc_extents (struct btrfs_trans_handle * trans ,
4332
+ struct btrfs_inode * inode ,
4333
+ struct btrfs_path * path )
4334
+ {
4335
+ struct btrfs_root * root = inode -> root ;
4336
+ struct btrfs_key key ;
4337
+ const u64 i_size = i_size_read (& inode -> vfs_inode );
4338
+ const u64 ino = btrfs_ino (inode );
4339
+ struct btrfs_path * dst_path = NULL ;
4340
+ u64 last_extent = (u64 )- 1 ;
4341
+ int ins_nr = 0 ;
4342
+ int start_slot ;
4343
+ int ret ;
4344
+
4345
+ if (!(inode -> flags & BTRFS_INODE_PREALLOC ))
4346
+ return 0 ;
4347
+
4348
+ key .objectid = ino ;
4349
+ key .type = BTRFS_EXTENT_DATA_KEY ;
4350
+ key .offset = i_size ;
4351
+ ret = btrfs_search_slot (NULL , root , & key , path , 0 , 0 );
4352
+ if (ret < 0 )
4353
+ goto out ;
4354
+
4355
+ while (true) {
4356
+ struct extent_buffer * leaf = path -> nodes [0 ];
4357
+ int slot = path -> slots [0 ];
4358
+
4359
+ if (slot >= btrfs_header_nritems (leaf )) {
4360
+ if (ins_nr > 0 ) {
4361
+ ret = copy_items (trans , inode , dst_path , path ,
4362
+ & last_extent , start_slot ,
4363
+ ins_nr , 1 , 0 );
4364
+ if (ret < 0 )
4365
+ goto out ;
4366
+ ins_nr = 0 ;
4367
+ }
4368
+ ret = btrfs_next_leaf (root , path );
4369
+ if (ret < 0 )
4370
+ goto out ;
4371
+ if (ret > 0 ) {
4372
+ ret = 0 ;
4373
+ break ;
4374
+ }
4375
+ continue ;
4376
+ }
4377
+
4378
+ btrfs_item_key_to_cpu (leaf , & key , slot );
4379
+ if (key .objectid > ino )
4380
+ break ;
4381
+ if (WARN_ON_ONCE (key .objectid < ino ) ||
4382
+ key .type < BTRFS_EXTENT_DATA_KEY ||
4383
+ key .offset < i_size ) {
4384
+ path -> slots [0 ]++ ;
4385
+ continue ;
4386
+ }
4387
+ if (last_extent == (u64 )- 1 ) {
4388
+ last_extent = key .offset ;
4389
+ /*
4390
+ * Avoid logging extent items logged in past fsync calls
4391
+ * and leading to duplicate keys in the log tree.
4392
+ */
4393
+ do {
4394
+ ret = btrfs_truncate_inode_items (trans ,
4395
+ root -> log_root ,
4396
+ & inode -> vfs_inode ,
4397
+ i_size ,
4398
+ BTRFS_EXTENT_DATA_KEY );
4399
+ } while (ret == - EAGAIN );
4400
+ if (ret )
4401
+ goto out ;
4402
+ }
4403
+ if (ins_nr == 0 )
4404
+ start_slot = slot ;
4405
+ ins_nr ++ ;
4406
+ path -> slots [0 ]++ ;
4407
+ if (!dst_path ) {
4408
+ dst_path = btrfs_alloc_path ();
4409
+ if (!dst_path ) {
4410
+ ret = - ENOMEM ;
4411
+ goto out ;
4412
+ }
4413
+ }
4414
+ }
4415
+ if (ins_nr > 0 ) {
4416
+ ret = copy_items (trans , inode , dst_path , path , & last_extent ,
4417
+ start_slot , ins_nr , 1 , 0 );
4418
+ if (ret > 0 )
4419
+ ret = 0 ;
4420
+ }
4421
+ out :
4422
+ btrfs_release_path (path );
4423
+ btrfs_free_path (dst_path );
4424
+ return ret ;
4425
+ }
4426
+
4323
4427
static int btrfs_log_changed_extents (struct btrfs_trans_handle * trans ,
4324
4428
struct btrfs_root * root ,
4325
4429
struct btrfs_inode * inode ,
@@ -4362,6 +4466,11 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4362
4466
if (em -> generation <= test_gen )
4363
4467
continue ;
4364
4468
4469
+ /* We log prealloc extents beyond eof later. */
4470
+ if (test_bit (EXTENT_FLAG_PREALLOC , & em -> flags ) &&
4471
+ em -> start >= i_size_read (& inode -> vfs_inode ))
4472
+ continue ;
4473
+
4365
4474
if (em -> start < logged_start )
4366
4475
logged_start = em -> start ;
4367
4476
if ((em -> start + em -> len - 1 ) > logged_end )
@@ -4374,31 +4483,6 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4374
4483
num ++ ;
4375
4484
}
4376
4485
4377
- /*
4378
- * Add all prealloc extents beyond the inode's i_size to make sure we
4379
- * don't lose them after doing a fast fsync and replaying the log.
4380
- */
4381
- if (inode -> flags & BTRFS_INODE_PREALLOC ) {
4382
- struct rb_node * node ;
4383
-
4384
- for (node = rb_last (& tree -> map ); node ; node = rb_prev (node )) {
4385
- em = rb_entry (node , struct extent_map , rb_node );
4386
- if (em -> start < i_size_read (& inode -> vfs_inode ))
4387
- break ;
4388
- if (!list_empty (& em -> list ))
4389
- continue ;
4390
- /* Same as above loop. */
4391
- if (++ num > 32768 ) {
4392
- list_del_init (& tree -> modified_extents );
4393
- ret = - EFBIG ;
4394
- goto process ;
4395
- }
4396
- refcount_inc (& em -> refs );
4397
- set_bit (EXTENT_FLAG_LOGGING , & em -> flags );
4398
- list_add_tail (& em -> list , & extents );
4399
- }
4400
- }
4401
-
4402
4486
list_sort (NULL , & extents , extent_cmp );
4403
4487
btrfs_get_logged_extents (inode , logged_list , logged_start , logged_end );
4404
4488
/*
@@ -4443,6 +4527,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
4443
4527
up_write (& inode -> dio_sem );
4444
4528
4445
4529
btrfs_release_path (path );
4530
+ if (!ret )
4531
+ ret = btrfs_log_prealloc_extents (trans , inode , path );
4532
+
4446
4533
return ret ;
4447
4534
}
4448
4535
@@ -4827,6 +4914,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
4827
4914
struct extent_map_tree * em_tree = & inode -> extent_tree ;
4828
4915
u64 logged_isize = 0 ;
4829
4916
bool need_log_inode_item = true;
4917
+ bool xattrs_logged = false;
4830
4918
4831
4919
path = btrfs_alloc_path ();
4832
4920
if (!path )
@@ -5128,6 +5216,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
5128
5216
err = btrfs_log_all_xattrs (trans , root , inode , path , dst_path );
5129
5217
if (err )
5130
5218
goto out_unlock ;
5219
+ xattrs_logged = true;
5131
5220
if (max_key .type >= BTRFS_EXTENT_DATA_KEY && !fast_search ) {
5132
5221
btrfs_release_path (path );
5133
5222
btrfs_release_path (dst_path );
@@ -5140,6 +5229,11 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
5140
5229
btrfs_release_path (dst_path );
5141
5230
if (need_log_inode_item ) {
5142
5231
err = log_inode_item (trans , log , dst_path , inode );
5232
+ if (!err && !xattrs_logged ) {
5233
+ err = btrfs_log_all_xattrs (trans , root , inode , path ,
5234
+ dst_path );
5235
+ btrfs_release_path (path );
5236
+ }
5143
5237
if (err )
5144
5238
goto out_unlock ;
5145
5239
}
0 commit comments