@@ -136,8 +136,10 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
136
136
* syncing the tree wait for us to finish
137
137
*/
138
138
static int start_log_trans (struct btrfs_trans_handle * trans ,
139
- struct btrfs_root * root )
139
+ struct btrfs_root * root ,
140
+ struct btrfs_log_ctx * ctx )
140
141
{
142
+ int index ;
141
143
int ret ;
142
144
143
145
mutex_lock (& root -> log_mutex );
@@ -151,6 +153,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
151
153
152
154
atomic_inc (& root -> log_batch );
153
155
atomic_inc (& root -> log_writers );
156
+ if (ctx ) {
157
+ index = root -> log_transid % 2 ;
158
+ list_add_tail (& ctx -> list , & root -> log_ctxs [index ]);
159
+ }
154
160
mutex_unlock (& root -> log_mutex );
155
161
return 0 ;
156
162
}
@@ -172,6 +178,10 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
172
178
root -> log_start_pid = current -> pid ;
173
179
atomic_inc (& root -> log_batch );
174
180
atomic_inc (& root -> log_writers );
181
+ if (ctx ) {
182
+ index = root -> log_transid % 2 ;
183
+ list_add_tail (& ctx -> list , & root -> log_ctxs [index ]);
184
+ }
175
185
out :
176
186
mutex_unlock (& root -> log_mutex );
177
187
return ret ;
@@ -2361,25 +2371,18 @@ static int update_log_root(struct btrfs_trans_handle *trans,
2361
2371
return ret ;
2362
2372
}
2363
2373
2364
- static int wait_log_commit (struct btrfs_trans_handle * trans ,
2365
- struct btrfs_root * root , int transid )
2374
+ static void wait_log_commit (struct btrfs_trans_handle * trans ,
2375
+ struct btrfs_root * root , int transid )
2366
2376
{
2367
2377
DEFINE_WAIT (wait );
2368
2378
int index = transid % 2 ;
2369
- int ret = 0 ;
2370
2379
2371
2380
/*
2372
2381
* we only allow two pending log transactions at a time,
2373
2382
* so we know that if ours is more than 2 older than the
2374
2383
* current transaction, we're done
2375
2384
*/
2376
2385
do {
2377
- if (ACCESS_ONCE (root -> fs_info -> last_trans_log_full_commit ) ==
2378
- trans -> transid ) {
2379
- ret = - EAGAIN ;
2380
- break ;
2381
- }
2382
-
2383
2386
prepare_to_wait (& root -> log_commit_wait [index ],
2384
2387
& wait , TASK_UNINTERRUPTIBLE );
2385
2388
mutex_unlock (& root -> log_mutex );
@@ -2392,27 +2395,55 @@ static int wait_log_commit(struct btrfs_trans_handle *trans,
2392
2395
mutex_lock (& root -> log_mutex );
2393
2396
} while (root -> log_transid < transid + 2 &&
2394
2397
atomic_read (& root -> log_commit [index ]));
2395
-
2396
- return ret ;
2397
2398
}
2398
2399
2399
2400
static void wait_for_writer (struct btrfs_trans_handle * trans ,
2400
2401
struct btrfs_root * root )
2401
2402
{
2402
2403
DEFINE_WAIT (wait );
2403
- while ( ACCESS_ONCE ( root -> fs_info -> last_trans_log_full_commit ) !=
2404
- trans -> transid && atomic_read (& root -> log_writers )) {
2404
+
2405
+ while ( atomic_read (& root -> log_writers )) {
2405
2406
prepare_to_wait (& root -> log_writer_wait ,
2406
2407
& wait , TASK_UNINTERRUPTIBLE );
2407
2408
mutex_unlock (& root -> log_mutex );
2408
- if (ACCESS_ONCE (root -> fs_info -> last_trans_log_full_commit ) !=
2409
- trans -> transid && atomic_read (& root -> log_writers ))
2409
+ if (atomic_read (& root -> log_writers ))
2410
2410
schedule ();
2411
2411
mutex_lock (& root -> log_mutex );
2412
2412
finish_wait (& root -> log_writer_wait , & wait );
2413
2413
}
2414
2414
}
2415
2415
2416
+ static inline void btrfs_remove_log_ctx (struct btrfs_root * root ,
2417
+ struct btrfs_log_ctx * ctx )
2418
+ {
2419
+ if (!ctx )
2420
+ return ;
2421
+
2422
+ mutex_lock (& root -> log_mutex );
2423
+ list_del_init (& ctx -> list );
2424
+ mutex_unlock (& root -> log_mutex );
2425
+ }
2426
+
2427
+ /*
2428
+ * Invoked in log mutex context, or be sure there is no other task which
2429
+ * can access the list.
2430
+ */
2431
+ static inline void btrfs_remove_all_log_ctxs (struct btrfs_root * root ,
2432
+ int index , int error )
2433
+ {
2434
+ struct btrfs_log_ctx * ctx ;
2435
+
2436
+ if (!error ) {
2437
+ INIT_LIST_HEAD (& root -> log_ctxs [index ]);
2438
+ return ;
2439
+ }
2440
+
2441
+ list_for_each_entry (ctx , & root -> log_ctxs [index ], list )
2442
+ ctx -> log_ret = error ;
2443
+
2444
+ INIT_LIST_HEAD (& root -> log_ctxs [index ]);
2445
+ }
2446
+
2416
2447
/*
2417
2448
* btrfs_sync_log does sends a given tree log down to the disk and
2418
2449
* updates the super blocks to record it. When this call is done,
@@ -2426,7 +2457,7 @@ static void wait_for_writer(struct btrfs_trans_handle *trans,
2426
2457
* that has happened.
2427
2458
*/
2428
2459
int btrfs_sync_log (struct btrfs_trans_handle * trans ,
2429
- struct btrfs_root * root )
2460
+ struct btrfs_root * root , struct btrfs_log_ctx * ctx )
2430
2461
{
2431
2462
int index1 ;
2432
2463
int index2 ;
@@ -2435,15 +2466,16 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2435
2466
struct btrfs_root * log = root -> log_root ;
2436
2467
struct btrfs_root * log_root_tree = root -> fs_info -> log_root_tree ;
2437
2468
int log_transid = 0 ;
2469
+ struct btrfs_log_ctx root_log_ctx ;
2438
2470
struct blk_plug plug ;
2439
2471
2440
2472
mutex_lock (& root -> log_mutex );
2441
2473
log_transid = root -> log_transid ;
2442
2474
index1 = root -> log_transid % 2 ;
2443
2475
if (atomic_read (& root -> log_commit [index1 ])) {
2444
- ret = wait_log_commit (trans , root , root -> log_transid );
2476
+ wait_log_commit (trans , root , root -> log_transid );
2445
2477
mutex_unlock (& root -> log_mutex );
2446
- return ret ;
2478
+ return ctx -> log_ret ;
2447
2479
}
2448
2480
atomic_set (& root -> log_commit [index1 ], 1 );
2449
2481
@@ -2534,13 +2566,18 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2534
2566
}
2535
2567
2536
2568
index2 = log_root_tree -> log_transid % 2 ;
2569
+
2570
+ btrfs_init_log_ctx (& root_log_ctx );
2571
+ list_add_tail (& root_log_ctx .list , & log_root_tree -> log_ctxs [index2 ]);
2572
+
2537
2573
if (atomic_read (& log_root_tree -> log_commit [index2 ])) {
2538
2574
blk_finish_plug (& plug );
2539
2575
btrfs_wait_marked_extents (log , & log -> dirty_log_pages , mark );
2540
- ret = wait_log_commit (trans , log_root_tree ,
2541
- log_root_tree -> log_transid );
2576
+ wait_log_commit (trans , log_root_tree ,
2577
+ log_root_tree -> log_transid );
2542
2578
btrfs_free_logged_extents (log , log_transid );
2543
2579
mutex_unlock (& log_root_tree -> log_mutex );
2580
+ ret = root_log_ctx .log_ret ;
2544
2581
goto out ;
2545
2582
}
2546
2583
atomic_set (& log_root_tree -> log_commit [index2 ], 1 );
@@ -2609,12 +2646,31 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
2609
2646
mutex_unlock (& root -> log_mutex );
2610
2647
2611
2648
out_wake_log_root :
2649
+ /*
2650
+ * We needn't get log_mutex here because we are sure all
2651
+ * the other tasks are blocked.
2652
+ */
2653
+ btrfs_remove_all_log_ctxs (log_root_tree , index2 , ret );
2654
+
2655
+ /*
2656
+ * It is dangerous if log_commit is changed before we set
2657
+ * ->log_ret of log ctx. Because the readers may not get
2658
+ * the return value.
2659
+ */
2660
+ smp_wmb ();
2661
+
2612
2662
atomic_set (& log_root_tree -> log_commit [index2 ], 0 );
2613
2663
smp_mb ();
2614
2664
if (waitqueue_active (& log_root_tree -> log_commit_wait [index2 ]))
2615
2665
wake_up (& log_root_tree -> log_commit_wait [index2 ]);
2616
2666
out :
2667
+ /* See above. */
2668
+ btrfs_remove_all_log_ctxs (root , index1 , ret );
2669
+
2670
+ /* See above. */
2671
+ smp_wmb ();
2617
2672
atomic_set (& root -> log_commit [index1 ], 0 );
2673
+
2618
2674
smp_mb ();
2619
2675
if (waitqueue_active (& root -> log_commit_wait [index1 ]))
2620
2676
wake_up (& root -> log_commit_wait [index1 ]);
@@ -4076,7 +4132,8 @@ static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans,
4076
4132
*/
4077
4133
static int btrfs_log_inode_parent (struct btrfs_trans_handle * trans ,
4078
4134
struct btrfs_root * root , struct inode * inode ,
4079
- struct dentry * parent , int exists_only )
4135
+ struct dentry * parent , int exists_only ,
4136
+ struct btrfs_log_ctx * ctx )
4080
4137
{
4081
4138
int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL ;
4082
4139
struct super_block * sb ;
@@ -4113,7 +4170,7 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4113
4170
goto end_no_trans ;
4114
4171
}
4115
4172
4116
- ret = start_log_trans (trans , root );
4173
+ ret = start_log_trans (trans , root , ctx );
4117
4174
if (ret )
4118
4175
goto end_no_trans ;
4119
4176
@@ -4163,6 +4220,9 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4163
4220
root -> fs_info -> last_trans_log_full_commit = trans -> transid ;
4164
4221
ret = 1 ;
4165
4222
}
4223
+
4224
+ if (ret )
4225
+ btrfs_remove_log_ctx (root , ctx );
4166
4226
btrfs_end_log_trans (root );
4167
4227
end_no_trans :
4168
4228
return ret ;
@@ -4175,12 +4235,14 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
4175
4235
* data on disk.
4176
4236
*/
4177
4237
int btrfs_log_dentry_safe (struct btrfs_trans_handle * trans ,
4178
- struct btrfs_root * root , struct dentry * dentry )
4238
+ struct btrfs_root * root , struct dentry * dentry ,
4239
+ struct btrfs_log_ctx * ctx )
4179
4240
{
4180
4241
struct dentry * parent = dget_parent (dentry );
4181
4242
int ret ;
4182
4243
4183
- ret = btrfs_log_inode_parent (trans , root , dentry -> d_inode , parent , 0 );
4244
+ ret = btrfs_log_inode_parent (trans , root , dentry -> d_inode , parent ,
4245
+ 0 , ctx );
4184
4246
dput (parent );
4185
4247
4186
4248
return ret ;
@@ -4417,6 +4479,6 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
4417
4479
root -> fs_info -> last_trans_committed ))
4418
4480
return 0 ;
4419
4481
4420
- return btrfs_log_inode_parent (trans , root , inode , parent , 1 );
4482
+ return btrfs_log_inode_parent (trans , root , inode , parent , 1 , NULL );
4421
4483
}
4422
4484
0 commit comments