ext4: improve ext4lazyinit scalability
[cascardo/linux.git] / fs / ext4 / super.c
index 5819b0e..50912cc 100644 (file)
@@ -2749,7 +2749,6 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
        sb = elr->lr_super;
        ngroups = EXT4_SB(sb)->s_groups_count;
 
-       sb_start_write(sb);
        for (group = elr->lr_next_group; group < ngroups; group++) {
                gdp = ext4_get_group_desc(sb, group, NULL);
                if (!gdp) {
@@ -2776,8 +2775,6 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
                elr->lr_next_sched = jiffies + elr->lr_timeout;
                elr->lr_next_group = group + 1;
        }
-       sb_end_write(sb);
-
        return ret;
 }
 
@@ -2842,19 +2839,43 @@ cont_thread:
                        mutex_unlock(&eli->li_list_mtx);
                        goto exit_thread;
                }
-
                list_for_each_safe(pos, n, &eli->li_request_list) {
+                       int err = 0;
+                       int progress = 0;
                        elr = list_entry(pos, struct ext4_li_request,
                                         lr_request);
 
-                       if (time_after_eq(jiffies, elr->lr_next_sched)) {
-                               if (ext4_run_li_request(elr) != 0) {
-                                       /* error, remove the lazy_init job */
-                                       ext4_remove_li_request(elr);
-                                       continue;
+                       if (time_before(jiffies, elr->lr_next_sched)) {
+                               if (time_before(elr->lr_next_sched, next_wakeup))
+                                       next_wakeup = elr->lr_next_sched;
+                               continue;
+                       }
+                       if (down_read_trylock(&elr->lr_super->s_umount)) {
+                               if (sb_start_write_trylock(elr->lr_super)) {
+                                       progress = 1;
+                                       /*
+                                        * We hold sb->s_umount, sb can not
+                                        * be removed from the list, it is
+                                        * now safe to drop li_list_mtx
+                                        */
+                                       mutex_unlock(&eli->li_list_mtx);
+                                       err = ext4_run_li_request(elr);
+                                       sb_end_write(elr->lr_super);
+                                       mutex_lock(&eli->li_list_mtx);
+                                       n = pos->next;
                                }
+                               up_read((&elr->lr_super->s_umount));
+                       }
+                       /* error, remove the lazy_init job */
+                       if (err) {
+                               ext4_remove_li_request(elr);
+                               continue;
+                       }
+                       if (!progress) {
+                               elr->lr_next_sched = jiffies +
+                                       (prandom_u32()
+                                        % (EXT4_DEF_LI_MAX_START_DELAY * HZ));
                        }
-
                        if (time_before(elr->lr_next_sched, next_wakeup))
                                next_wakeup = elr->lr_next_sched;
                }