]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge tag 'gfs2-4.11.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Feb 2017 15:46:34 +0000 (07:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 21 Feb 2017 15:46:34 +0000 (07:46 -0800)
Pull GFS2 updates from Robert Peterson:
 "We've got eight GFS2 patches for this merge window:

   - Andy Price submitted a patch to make gfs2_write_full_page a static
     function.

   - Dan Carpenter submitted a patch to fix a ERR_PTR thinko.

  Three patches fix bugs related to deleting very large files, which
  cause GFS2 to run out of journal space:

   - The first one prevents GFS2 delete operation from requesting too
     much journal space.

   - The second one fixes a problem whereby GFS2 can hang because it
     wasn't taking journal space demand into its calculations.

   - The third one wakes up IO waiters when a flush is done to restart
     processes stuck waiting for journal space to become available.

  The final three patches are a performance improvement related to
  spin_lock contention between multiple writers:

   - The "tr_touched" variable was switched to a flag to be more atomic
     and eliminate the possibility of some races.

   - Function meta_lo_add was moved inline with its only caller to make
     the code more readable and efficient.

   - Contention on the gfs2_log_lock spinlock was greatly reduced by
     avoiding the lock altogether in cases where we don't really need
     it: buffers that already appear in the appropriate metadata list
     for the journal. Many thanks to Steve Whitehouse for the ideas and
     principles behind these patches"

* tag 'gfs2-4.11.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Make gfs2_write_full_page static
  GFS2: Reduce contention on gfs2_log_lock
  GFS2: Inline function meta_lo_add
  GFS2: Switch tr_touched to flag in transaction
  GFS2: Wake up io waiters whenever a flush is done
  GFS2: Made logd daemon take into account log demand
  GFS2: Limit number of transaction blocks requested for truncates
  GFS2: Fix reference to ERR_PTR in gfs2_glock_iter_next

1  2 
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/glock.c
fs/gfs2/log.c
fs/gfs2/meta_io.c
fs/gfs2/ops_fstype.c

diff --combined fs/gfs2/aops.c
index 6b039d7ce160fce7677c3e5d702cd27a6299bb59,755b81e27e4f74c60f5f1d29131fea831a0214fc..ed7a2e252ad802bf587006b00939696ea2cbe9eb
@@@ -143,8 -143,8 +143,8 @@@ static int gfs2_writepage(struct page *
  /* This is the same as calling block_write_full_page, but it also
   * writes pages outside of i_size
   */
- int gfs2_write_full_page(struct page *page, get_block_t *get_block,
-                        struct writeback_control *wbc)
static int gfs2_write_full_page(struct page *page, get_block_t *get_block,
+                               struct writeback_control *wbc)
  {
        struct inode * const inode = page->mapping->host;
        loff_t i_size = i_size_read(inode);
@@@ -839,10 -839,12 +839,10 @@@ static int gfs2_stuffed_write_end(struc
        BUG_ON((pos + len) > (dibh->b_size - sizeof(struct gfs2_dinode)));
        kaddr = kmap_atomic(page);
        memcpy(buf + pos, kaddr + pos, copied);
 -      memset(kaddr + pos + copied, 0, len - copied);
        flush_dcache_page(page);
        kunmap_atomic(kaddr);
  
 -      if (!PageUptodate(page))
 -              SetPageUptodate(page);
 +      WARN_ON(!PageUptodate(page));
        unlock_page(page);
        put_page(page);
  
diff --combined fs/gfs2/bmap.c
index fc5da4cbe88c1c67a8c5ffcb512ee7edf877bb6c,cbad0ef6806fc7fa5f4607f3829e6af1956d5d87..01b97c012c6e9635540eaf2126cd5358726c1082
@@@ -720,6 -720,7 +720,7 @@@ static int do_strip(struct gfs2_inode *
  {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_rgrp_list rlist;
+       struct gfs2_trans *tr;
        u64 bn, bstart;
        u32 blen, btotal;
        __be64 *p;
        unsigned int revokes = 0;
        int x;
        int error;
+       int jblocks_rqsted;
  
        error = gfs2_rindex_update(sdp);
        if (error)
        if (gfs2_rs_active(&ip->i_res)) /* needs to be done with the rgrp glock held */
                gfs2_rs_deltree(&ip->i_res);
  
-       error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
-                                RES_INDIRECT + RES_STATFS + RES_QUOTA,
-                                revokes);
+ restart:
+       jblocks_rqsted = rg_blocks + RES_DINODE +
+               RES_INDIRECT + RES_STATFS + RES_QUOTA +
+               gfs2_struct2blk(sdp, revokes, sizeof(u64));
+       if (jblocks_rqsted > atomic_read(&sdp->sd_log_thresh2))
+               jblocks_rqsted = atomic_read(&sdp->sd_log_thresh2);
+       error = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
        if (error)
                goto out_rg_gunlock;
  
+       tr = current->journal_info;
        down_write(&ip->i_rw_mutex);
  
        gfs2_trans_add_meta(ip->i_gl, dibh);
                if (!*p)
                        continue;
  
+               /* check for max reasonable journal transaction blocks */
+               if (tr->tr_num_buf_new + RES_STATFS +
+                   RES_QUOTA >= atomic_read(&sdp->sd_log_thresh2)) {
+                       if (rg_blocks >= tr->tr_num_buf_new)
+                               rg_blocks -= tr->tr_num_buf_new;
+                       else
+                               rg_blocks = 0;
+                       break;
+               }
                bn = be64_to_cpu(*p);
  
                if (bstart + blen == bn)
                *p = 0;
                gfs2_add_inode_blocks(&ip->i_inode, -1);
        }
+       if (p == bottom)
+               rg_blocks = 0;
        if (bstart) {
                __gfs2_free_blocks(ip, bstart, blen, metadata);
                btotal += blen;
        gfs2_quota_change(ip, -(s64)btotal, ip->i_inode.i_uid,
                          ip->i_inode.i_gid);
  
 -      ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
 +      ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
  
        gfs2_dinode_out(ip, dibh->b_data);
  
  
        gfs2_trans_end(sdp);
  
+       if (rg_blocks)
+               goto restart;
  out_rg_gunlock:
        gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
  out_rlist:
@@@ -1063,7 -1086,7 +1086,7 @@@ static int trunc_start(struct inode *in
        }
  
        i_size_write(inode, newsize);
 -      ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
 +      ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
        gfs2_dinode_out(ip, dibh->b_data);
  
        if (journaled)
@@@ -1142,7 -1165,7 +1165,7 @@@ static int trunc_end(struct gfs2_inode 
                gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
                gfs2_ordered_del_inode(ip);
        }
 -      ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
 +      ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
        ip->i_diskflags &= ~GFS2_DIF_TRUNC_IN_PROG;
  
        gfs2_trans_add_meta(ip->i_gl, dibh);
@@@ -1252,7 -1275,7 +1275,7 @@@ static int do_grow(struct inode *inode
                goto do_end_trans;
  
        i_size_write(inode, size);
 -      ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
 +      ip->i_inode.i_mtime = ip->i_inode.i_ctime = current_time(&ip->i_inode);
        gfs2_trans_add_meta(ip->i_gl, dibh);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
diff --combined fs/gfs2/glock.c
index 94f50cac91c617b03025d4d596d8d9d65d2c185b,2928f1209b675f828d03305bda8b458b16995ba7..a2d45db32cd5f093a8ddac3feaadcf22c0719ef9
@@@ -21,7 -21,7 +21,7 @@@
  #include <linux/list.h>
  #include <linux/wait.h>
  #include <linux/module.h>
 -#include <asm/uaccess.h>
 +#include <linux/uaccess.h>
  #include <linux/seq_file.h>
  #include <linux/debugfs.h>
  #include <linux/kthread.h>
@@@ -695,7 -695,7 +695,7 @@@ int gfs2_glock_get(struct gfs2_sbd *sdp
        gl->gl_target = LM_ST_UNLOCKED;
        gl->gl_demote_state = LM_ST_EXCLUSIVE;
        gl->gl_ops = glops;
 -      gl->gl_dstamp = ktime_set(0, 0);
 +      gl->gl_dstamp = 0;
        preempt_disable();
        /* We use the global stats to estimate the initial per-glock stats */
        gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type];
@@@ -1802,16 -1802,18 +1802,18 @@@ void gfs2_glock_exit(void
  
  static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi)
  {
-       do {
-               gi->gl = rhashtable_walk_next(&gi->hti);
+       while ((gi->gl = rhashtable_walk_next(&gi->hti))) {
                if (IS_ERR(gi->gl)) {
                        if (PTR_ERR(gi->gl) == -EAGAIN)
                                continue;
                        gi->gl = NULL;
+                       return;
                }
-       /* Skip entries for other sb and dead entries */
-       } while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) ||
-                             __lockref_is_dead(&gi->gl->gl_lockref)));
+               /* Skip entries for other sb and dead entries */
+               if (gi->sdp == gi->gl->gl_name.ln_sbd &&
+                   !__lockref_is_dead(&gi->gl->gl_lockref))
+                       return;
+       }
  }
  
  static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos)
diff --combined fs/gfs2/log.c
index 27c00a16def0a50fc6fe6b40a94184f862196995,4fb76c04e65b729ec56549ce88ca0543c426e06a..f865b96374df2b5c40ecfb13663154499ec09b31
@@@ -349,6 -349,7 +349,7 @@@ int gfs2_log_reserve(struct gfs2_sbd *s
        if (gfs2_assert_warn(sdp, blks) ||
            gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
                return -EINVAL;
+       atomic_add(blks, &sdp->sd_log_blks_needed);
  retry:
        free_blocks = atomic_read(&sdp->sd_log_blks_free);
        if (unlikely(free_blocks <= wanted)) {
                        wake_up(&sdp->sd_reserving_log_wait);
                goto retry;
        }
+       atomic_sub(blks, &sdp->sd_log_blks_needed);
        trace_gfs2_log_blocks(sdp, -blks);
  
        /*
@@@ -657,7 -659,7 +659,7 @@@ static void log_write_header(struct gfs
        struct gfs2_log_header *lh;
        unsigned int tail;
        u32 hash;
 -      int op_flags = WRITE_FLUSH_FUA | REQ_META;
 +      int op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META;
        struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
        enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
        lh = page_address(page);
        if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
                gfs2_ordered_wait(sdp);
                log_flush_wait(sdp);
 -              op_flags = WRITE_SYNC | REQ_META | REQ_PRIO;
 +              op_flags = REQ_SYNC | REQ_META | REQ_PRIO;
        }
  
        sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
@@@ -797,7 -799,7 +799,7 @@@ void gfs2_log_flush(struct gfs2_sbd *sd
  
  static void gfs2_merge_trans(struct gfs2_trans *old, struct gfs2_trans *new)
  {
-       WARN_ON_ONCE(old->tr_attached != 1);
+       WARN_ON_ONCE(!test_bit(TR_ATTACHED, &old->tr_flags));
  
        old->tr_num_buf_new     += new->tr_num_buf_new;
        old->tr_num_databuf_new += new->tr_num_databuf_new;
@@@ -821,9 -823,9 +823,9 @@@ static void log_refund(struct gfs2_sbd 
        if (sdp->sd_log_tr) {
                gfs2_merge_trans(sdp->sd_log_tr, tr);
        } else if (tr->tr_num_buf_new || tr->tr_num_databuf_new) {
-               gfs2_assert_withdraw(sdp, tr->tr_alloced);
+               gfs2_assert_withdraw(sdp, test_bit(TR_ALLOCED, &tr->tr_flags));
                sdp->sd_log_tr = tr;
-               tr->tr_attached = 1;
+               set_bit(TR_ATTACHED, &tr->tr_flags);
        }
  
        sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
@@@ -891,13 -893,16 +893,16 @@@ void gfs2_log_shutdown(struct gfs2_sbd 
  
  static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
  {
-       return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1));
+       return (atomic_read(&sdp->sd_log_pinned) +
+               atomic_read(&sdp->sd_log_blks_needed) >=
+               atomic_read(&sdp->sd_log_thresh1));
  }
  
  static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
  {
        unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);
-       return used_blocks >= atomic_read(&sdp->sd_log_thresh2);
+       return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
+               atomic_read(&sdp->sd_log_thresh2);
  }
  
  /**
@@@ -913,12 -918,15 +918,15 @@@ int gfs2_logd(void *data
        struct gfs2_sbd *sdp = data;
        unsigned long t = 1;
        DEFINE_WAIT(wait);
+       bool did_flush;
  
        while (!kthread_should_stop()) {
  
+               did_flush = false;
                if (gfs2_jrnl_flush_reqd(sdp) || t == 0) {
                        gfs2_ail1_empty(sdp);
                        gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
+                       did_flush = true;
                }
  
                if (gfs2_ail_flush_reqd(sdp)) {
                        gfs2_ail1_wait(sdp);
                        gfs2_ail1_empty(sdp);
                        gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
+                       did_flush = true;
                }
  
-               if (!gfs2_ail_flush_reqd(sdp))
+               if (!gfs2_ail_flush_reqd(sdp) || did_flush)
                        wake_up(&sdp->sd_log_waitq);
  
                t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
diff --combined fs/gfs2/meta_io.c
index 49db8ef13fdff5308e7e49e5765f91cb58d9ab33,a88a347cffe3b6207f5f3b725974b47ec3970bd4..663ffc135ef365a436ae658d3f71965b31cee06e
@@@ -37,7 -37,8 +37,7 @@@ static int gfs2_aspace_writepage(struc
  {
        struct buffer_head *bh, *head;
        int nr_underway = 0;
 -      int write_flags = REQ_META | REQ_PRIO |
 -              (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : 0);
 +      int write_flags = REQ_META | REQ_PRIO | wbc_to_write_flags(wbc);
  
        BUG_ON(!PageLocked(page));
        BUG_ON(!page_has_buffers(page));
@@@ -284,7 -285,7 +284,7 @@@ int gfs2_meta_read(struct gfs2_glock *g
                }
        }
  
 -      gfs2_submit_bhs(REQ_OP_READ, READ_SYNC | REQ_META | REQ_PRIO, bhs, num);
 +      gfs2_submit_bhs(REQ_OP_READ, REQ_META | REQ_PRIO, bhs, num);
        if (!(flags & DIO_WAIT))
                return 0;
  
        wait_on_buffer(bh);
        if (unlikely(!buffer_uptodate(bh))) {
                struct gfs2_trans *tr = current->journal_info;
-               if (tr && tr->tr_touched)
+               if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
                        gfs2_io_error_bh(sdp, bh);
                brelse(bh);
                *bhp = NULL;
@@@ -319,7 -320,7 +319,7 @@@ int gfs2_meta_wait(struct gfs2_sbd *sdp
  
        if (!buffer_uptodate(bh)) {
                struct gfs2_trans *tr = current->journal_info;
-               if (tr && tr->tr_touched)
+               if (tr && test_bit(TR_TOUCHED, &tr->tr_flags))
                        gfs2_io_error_bh(sdp, bh);
                return -EIO;
        }
@@@ -345,7 -346,7 +345,7 @@@ void gfs2_remove_from_journal(struct bu
                        tr->tr_num_buf_rm++;
                else
                        tr->tr_num_databuf_rm++;
-               tr->tr_touched = 1;
+               set_bit(TR_TOUCHED, &tr->tr_flags);
                was_pinned = 1;
                brelse(bh);
        }
@@@ -452,7 -453,7 +452,7 @@@ struct buffer_head *gfs2_meta_ra(struc
        if (buffer_uptodate(first_bh))
                goto out;
        if (!buffer_locked(first_bh))
 -              ll_rw_block(REQ_OP_READ, READ_SYNC | REQ_META, 1, &first_bh);
 +              ll_rw_block(REQ_OP_READ, REQ_META, 1, &first_bh);
  
        dblock++;
        extlen--;
diff --combined fs/gfs2/ops_fstype.c
index a34308df927f4f1395b918f27b30eec5dce60320,86281a918c7af3921a7e6be86062cd9e53223197..58704799f0b94e7f83b1bef756091b9185d13543
@@@ -246,7 -246,7 +246,7 @@@ static int gfs2_read_super(struct gfs2_
  
        bio->bi_end_io = end_bio_io_page;
        bio->bi_private = page;
 -      bio_set_op_attrs(bio, REQ_OP_READ, READ_SYNC | REQ_META);
 +      bio_set_op_attrs(bio, REQ_OP_READ, REQ_META);
        submit_bio(bio);
        wait_on_page_locked(page);
        bio_put(bio);
@@@ -683,6 -683,7 +683,7 @@@ static int init_journal(struct gfs2_sb
                goto fail_jindex;
        }
  
+       atomic_set(&sdp->sd_log_blks_needed, 0);
        if (sdp->sd_args.ar_spectator) {
                sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
                atomic_set(&sdp->sd_log_blks_free, sdp->sd_jdesc->jd_blocks);