2019-05-31 11:09:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2007-12-12 03:49:21 +03:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03:00
*/
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-03-28 23:14:04 +04:00
# include <linux/crc32.h>
2018-01-17 02:01:33 +03:00
# include <linux/crc32c.h>
2006-11-23 19:06:35 +03:00
# include <linux/delay.h>
2007-11-09 13:01:41 +03:00
# include <linux/kthread.h>
# include <linux/freezer.h>
2008-09-26 13:23:22 +04:00
# include <linux/bio.h>
2014-02-03 13:57:29 +04:00
# include <linux/blkdev.h>
2011-04-18 17:18:09 +04:00
# include <linux/writeback.h>
2012-02-14 23:49:57 +04:00
# include <linux/list_sort.h>
2006-01-16 19:50:04 +03:00
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "bmap.h"
# include "glock.h"
# include "log.h"
# include "lops.h"
# include "meta_io.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-03-28 23:14:04 +04:00
# include "dir.h"
2009-06-12 11:49:20 +04:00
# include "trace_gfs2.h"
2019-04-17 21:04:27 +03:00
# include "trans.h"
2006-01-16 19:50:04 +03:00
2019-11-14 17:48:26 +03:00
static void gfs2_log_shutdown ( struct gfs2_sbd * sdp ) ;
2006-01-16 19:50:04 +03:00
/**
* gfs2_struct2blk - compute stuff
* @ sdp : the filesystem
* @ nstruct : the number of structures
*
* Compute the number of log descriptor blocks needed to hold a certain number
* of structures of a certain size .
*
* Returns : the number of blocks needed ( minimum is always 1 )
*/
2019-12-13 17:10:51 +03:00
unsigned int gfs2_struct2blk ( struct gfs2_sbd * sdp , unsigned int nstruct )
2006-01-16 19:50:04 +03:00
{
unsigned int blks ;
unsigned int first , second ;
2020-12-06 15:30:14 +03:00
/* The initial struct gfs2_log_descriptor block */
2006-01-16 19:50:04 +03:00
blks = 1 ;
2019-12-13 17:10:51 +03:00
first = sdp - > sd_ldptrs ;
2006-01-16 19:50:04 +03:00
if ( nstruct > first ) {
2020-12-06 15:30:14 +03:00
/* Subsequent struct gfs2_meta_header blocks */
2019-12-13 17:10:51 +03:00
second = sdp - > sd_inptrs ;
2006-02-28 01:23:27 +03:00
blks + = DIV_ROUND_UP ( nstruct - first , second ) ;
2006-01-16 19:50:04 +03:00
}
return blks ;
}
2007-08-27 12:45:26 +04:00
/**
* gfs2_remove_from_ail - Remove an entry from the ail lists , updating counters
* @ bd : The gfs2_bufdata to remove
*
2011-03-14 15:40:29 +03:00
* The ail lock _must_ be held when calling this function
2007-08-27 12:45:26 +04:00
*
*/
gfs2: Wipe jdata and ail1 in gfs2_journal_wipe, formerly gfs2_meta_wipe
Before this patch, when blocks were freed, it called gfs2_meta_wipe to
take the metadata out of the pending journal blocks. It did this mostly
by calling another function called gfs2_remove_from_journal. This is
shortsighted because it does not do anything with jdata blocks which
may also be in the journal.
This patch expands the function so that it wipes out jdata blocks from
the journal as well, and it wipes it from the ail1 list if it hasn't
been written back yet. Since it now processes jdata blocks as well,
the function has been renamed from gfs2_meta_wipe to gfs2_journal_wipe.
New function gfs2_ail1_wipe wants a static view of the ail list, so it
locks the sd_ail_lock when removing items. To accomplish this, function
gfs2_remove_from_journal no longer locks the sd_ail_lock, and it's now
the caller's responsibility to do so.
I was going to make sd_ail_lock locking conditional, but the practice is
generally frowned upon. For details, see: https://lwn.net/Articles/109066/
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-07-22 18:27:50 +03:00
void gfs2_remove_from_ail ( struct gfs2_bufdata * bd )
2007-08-27 12:45:26 +04:00
{
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
bd - > bd_tr = NULL ;
2007-09-03 14:01:33 +04:00
list_del_init ( & bd - > bd_ail_st_list ) ;
list_del_init ( & bd - > bd_ail_gl_list ) ;
2007-08-27 12:45:26 +04:00
atomic_dec ( & bd - > bd_gl - > gl_ail_count ) ;
brelse ( bd - > bd_bh ) ;
}
2006-10-03 19:10:41 +04:00
/**
2021-03-30 19:44:29 +03:00
* gfs2_ail1_start_one - Start I / O on a transaction
* @ sdp : The superblock
2011-04-18 17:18:09 +04:00
* @ wbc : The writeback control structure
2021-03-30 19:44:29 +03:00
* @ tr : The transaction to start I / O on
* @ plug : The block plug currently active
2006-10-03 19:10:41 +04:00
*/
2011-04-26 13:23:56 +04:00
static int gfs2_ail1_start_one ( struct gfs2_sbd * sdp ,
struct writeback_control * wbc ,
2021-02-18 17:07:21 +03:00
struct gfs2_trans * tr , struct blk_plug * plug )
2011-03-11 14:52:25 +03:00
__releases ( & sdp - > sd_ail_lock )
__acquires ( & sdp - > sd_ail_lock )
2006-10-03 19:10:41 +04:00
{
2011-03-30 19:25:51 +04:00
struct gfs2_glock * gl = NULL ;
2011-04-18 17:18:09 +04:00
struct address_space * mapping ;
2006-10-03 19:10:41 +04:00
struct gfs2_bufdata * bd , * s ;
struct buffer_head * bh ;
2019-11-13 22:53:42 +03:00
int ret = 0 ;
2006-10-03 19:10:41 +04:00
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_for_each_entry_safe_reverse ( bd , s , & tr - > tr_ail1_list , bd_ail_st_list ) {
2011-04-18 17:18:09 +04:00
bh = bd - > bd_bh ;
2006-10-03 19:10:41 +04:00
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
gfs2_assert ( sdp , bd - > bd_tr = = tr ) ;
2006-10-03 19:10:41 +04:00
2011-04-18 17:18:09 +04:00
if ( ! buffer_busy ( bh ) ) {
2019-11-13 20:47:09 +03:00
if ( buffer_uptodate ( bh ) ) {
list_move ( & bd - > bd_ail_st_list ,
& tr - > tr_ail2_list ) ;
continue ;
}
2019-04-10 20:46:35 +03:00
if ( ! cmpxchg ( & sdp - > sd_log_error , 0 , - EIO ) ) {
2011-04-18 17:18:09 +04:00
gfs2_io_error_bh ( sdp , bh ) ;
2019-02-12 23:43:55 +03:00
gfs2_withdraw_delayed ( sdp ) ;
2018-06-07 13:56:46 +03:00
}
2011-04-18 17:18:09 +04:00
}
2019-11-13 20:47:09 +03:00
if ( gfs2_withdrawn ( sdp ) ) {
gfs2_remove_from_ail ( bd ) ;
continue ;
}
2011-04-18 17:18:09 +04:00
if ( ! buffer_dirty ( bh ) )
continue ;
if ( gl = = bd - > bd_gl )
continue ;
gl = bd - > bd_gl ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_move ( & bd - > bd_ail_st_list , & tr - > tr_ail1_list ) ;
2011-04-18 17:18:09 +04:00
mapping = bh - > b_page - > mapping ;
2011-04-26 13:23:56 +04:00
if ( ! mapping )
continue ;
2011-04-18 17:18:09 +04:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
2022-07-22 20:59:15 +03:00
ret = filemap_fdatawrite_wbc ( mapping , wbc ) ;
2021-02-18 17:07:21 +03:00
if ( need_resched ( ) ) {
blk_finish_plug ( plug ) ;
cond_resched ( ) ;
blk_start_plug ( plug ) ;
}
2011-04-18 17:18:09 +04:00
spin_lock ( & sdp - > sd_ail_lock ) ;
gfs2: Fix case in which ail writes are done to jdata holes
Patch b2a846dbef4e ("gfs2: Ignore journal log writes for jdata holes")
tried (unsuccessfully) to fix a case in which writes were done to jdata
blocks, the blocks are sent to the ail list, then a punch_hole or truncate
operation caused the blocks to be freed. In other words, the ail items
are for jdata holes. Before b2a846dbef4e, the jdata hole caused function
gfs2_block_map to return -EIO, which was eventually interpreted as an
IO error to the journal, and then withdraw.
This patch changes function gfs2_get_block_noalloc, which is only used
for jdata writes, so it returns -ENODATA rather than -EIO, and when
-ENODATA is returned to gfs2_ail1_start_one, the error is ignored.
We can safely ignore it because gfs2_ail1_start_one is only called
when the jdata pages have already been written and truncated, so the
ail1 content no longer applies.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-11-12 19:02:48 +03:00
if ( ret = = - ENODATA ) /* if a jdata write into a new hole */
ret = 0 ; /* ignore it */
2019-11-13 22:53:42 +03:00
if ( ret | | wbc - > nr_to_write < = 0 )
2011-04-18 17:18:09 +04:00
break ;
2019-11-13 22:53:42 +03:00
return - EBUSY ;
2011-04-18 17:18:09 +04:00
}
2011-04-26 13:23:56 +04:00
2019-11-13 22:53:42 +03:00
return ret ;
2011-04-18 17:18:09 +04:00
}
2006-10-03 19:10:41 +04:00
2020-03-26 20:19:54 +03:00
static void dump_ail_list ( struct gfs2_sbd * sdp )
{
struct gfs2_trans * tr ;
struct gfs2_bufdata * bd ;
struct buffer_head * bh ;
list_for_each_entry_reverse ( tr , & sdp - > sd_ail1_list , tr_list ) {
list_for_each_entry_reverse ( bd , & tr - > tr_ail1_list ,
bd_ail_st_list ) {
bh = bd - > bd_bh ;
fs_err ( sdp , " bd %p: blk:0x%llx bh=%p " , bd ,
( unsigned long long ) bd - > bd_blkno , bh ) ;
if ( ! bh ) {
fs_err ( sdp , " \n " ) ;
continue ;
}
fs_err ( sdp , " 0x%llx up2:%d dirt:%d lkd:%d req:%d "
" map:%d new:%d ar:%d aw:%d delay:%d "
" io err:%d unwritten:%d dfr:%d pin:%d esc:%d \n " ,
( unsigned long long ) bh - > b_blocknr ,
buffer_uptodate ( bh ) , buffer_dirty ( bh ) ,
buffer_locked ( bh ) , buffer_req ( bh ) ,
buffer_mapped ( bh ) , buffer_new ( bh ) ,
buffer_async_read ( bh ) , buffer_async_write ( bh ) ,
buffer_delay ( bh ) , buffer_write_io_error ( bh ) ,
buffer_unwritten ( bh ) ,
buffer_defer_completion ( bh ) ,
buffer_pinned ( bh ) , buffer_escaped ( bh ) ) ;
}
}
}
2006-10-03 19:10:41 +04:00
2011-04-18 17:18:09 +04:00
/**
* gfs2_ail1_flush - start writeback of some ail1 entries
* @ sdp : The super block
* @ wbc : The writeback control structure
*
* Writes back some ail1 entries , according to the limits in the
* writeback control structure
*/
2006-10-03 19:10:41 +04:00
2011-04-18 17:18:09 +04:00
void gfs2_ail1_flush ( struct gfs2_sbd * sdp , struct writeback_control * wbc )
{
struct list_head * head = & sdp - > sd_ail1_list ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
struct gfs2_trans * tr ;
2014-02-03 13:57:29 +04:00
struct blk_plug plug ;
2020-03-27 23:23:14 +03:00
int ret ;
2020-03-26 20:19:54 +03:00
unsigned long flush_start = jiffies ;
2006-10-03 19:10:41 +04:00
2011-04-18 17:18:38 +04:00
trace_gfs2_ail_flush ( sdp , wbc , 1 ) ;
2014-02-03 13:57:29 +04:00
blk_start_plug ( & plug ) ;
2011-04-18 17:18:09 +04:00
spin_lock ( & sdp - > sd_ail_lock ) ;
2011-04-26 13:23:56 +04:00
restart :
2020-03-27 23:23:14 +03:00
ret = 0 ;
2020-03-26 20:19:54 +03:00
if ( time_after ( jiffies , flush_start + ( HZ * 600 ) ) ) {
2020-05-22 22:03:21 +03:00
fs_err ( sdp , " Error: In %s for ten minutes! t=%d \n " ,
__func__ , current - > journal_info ? 1 : 0 ) ;
2020-03-26 20:19:54 +03:00
dump_ail_list ( sdp ) ;
goto out ;
}
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_for_each_entry_reverse ( tr , head , tr_list ) {
2011-04-18 17:18:09 +04:00
if ( wbc - > nr_to_write < = 0 )
2006-10-03 19:10:41 +04:00
break ;
2021-02-18 17:07:21 +03:00
ret = gfs2_ail1_start_one ( sdp , wbc , tr , & plug ) ;
2019-11-13 22:53:42 +03:00
if ( ret ) {
if ( ret = = - EBUSY )
goto restart ;
break ;
}
2011-04-18 17:18:09 +04:00
}
2020-03-26 20:19:54 +03:00
out :
2011-04-18 17:18:09 +04:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
2014-02-03 13:57:29 +04:00
blk_finish_plug ( & plug ) ;
2020-03-06 19:15:03 +03:00
if ( ret ) {
2022-07-22 20:59:15 +03:00
gfs2_lm ( sdp , " gfs2_ail1_start_one returned: %d \n " , ret ) ;
2020-01-23 20:41:00 +03:00
gfs2_withdraw ( sdp ) ;
2020-03-06 19:15:03 +03:00
}
2011-04-18 17:18:38 +04:00
trace_gfs2_ail_flush ( sdp , wbc , 0 ) ;
2011-04-18 17:18:09 +04:00
}
/**
* gfs2_ail1_start - start writeback of all ail1 entries
* @ sdp : The superblock
*/
static void gfs2_ail1_start ( struct gfs2_sbd * sdp )
{
struct writeback_control wbc = {
. sync_mode = WB_SYNC_NONE ,
. nr_to_write = LONG_MAX ,
. range_start = 0 ,
. range_end = LLONG_MAX ,
} ;
return gfs2_ail1_flush ( sdp , & wbc ) ;
2006-10-03 19:10:41 +04:00
}
2020-12-19 09:15:17 +03:00
static void gfs2_log_update_flush_tail ( struct gfs2_sbd * sdp )
{
unsigned int new_flush_tail = sdp - > sd_log_head ;
struct gfs2_trans * tr ;
if ( ! list_empty ( & sdp - > sd_ail1_list ) ) {
tr = list_last_entry ( & sdp - > sd_ail1_list ,
struct gfs2_trans , tr_list ) ;
new_flush_tail = tr - > tr_first ;
}
sdp - > sd_log_flush_tail = new_flush_tail ;
}
static void gfs2_log_update_head ( struct gfs2_sbd * sdp )
{
unsigned int new_head = sdp - > sd_log_flush_head ;
if ( sdp - > sd_log_flush_tail = = sdp - > sd_log_head )
sdp - > sd_log_flush_tail = new_head ;
sdp - > sd_log_head = new_head ;
}
2021-03-30 19:44:29 +03:00
/*
2020-12-19 12:54:51 +03:00
* gfs2_ail_empty_tr - empty one of the ail lists of a transaction
*/
static void gfs2_ail_empty_tr ( struct gfs2_sbd * sdp , struct gfs2_trans * tr ,
struct list_head * head )
{
struct gfs2_bufdata * bd ;
while ( ! list_empty ( head ) ) {
bd = list_first_entry ( head , struct gfs2_bufdata ,
bd_ail_st_list ) ;
gfs2_assert ( sdp , bd - > bd_tr = = tr ) ;
gfs2_remove_from_ail ( bd ) ;
}
}
2006-10-03 19:10:41 +04:00
/**
* gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced
* @ sdp : the filesystem
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
* @ tr : the transaction
* @ max_revokes : If nonzero , issue revokes for the bd items for written buffers
2006-10-03 19:10:41 +04:00
*
2020-08-18 16:05:14 +03:00
* returns : the transaction ' s count of remaining active items
2006-10-03 19:10:41 +04:00
*/
2020-08-18 16:05:14 +03:00
static int gfs2_ail1_empty_one ( struct gfs2_sbd * sdp , struct gfs2_trans * tr ,
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
int * max_revokes )
2006-10-03 19:10:41 +04:00
{
struct gfs2_bufdata * bd , * s ;
struct buffer_head * bh ;
2020-08-18 16:05:14 +03:00
int active_count = 0 ;
2006-10-03 19:10:41 +04:00
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_for_each_entry_safe_reverse ( bd , s , & tr - > tr_ail1_list ,
2006-10-03 19:10:41 +04:00
bd_ail_st_list ) {
bh = bd - > bd_bh ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
gfs2_assert ( sdp , bd - > bd_tr = = tr ) ;
2019-04-10 20:46:35 +03:00
/*
* If another process flagged an io error , e . g . writing to the
* journal , error all other bhs and move them off the ail1 to
* prevent a tight loop when unmount tries to flush ail1 ,
* regardless of whether they ' re still busy . If no outside
* errors were found and the buffer is busy , move to the next .
* If the ail buffer is not busy and caught an error , flag it
* for others .
*/
2020-08-18 16:05:14 +03:00
if ( ! sdp - > sd_log_error & & buffer_busy ( bh ) ) {
active_count + + ;
2011-04-18 17:18:09 +04:00
continue ;
2020-08-18 16:05:14 +03:00
}
2018-10-04 18:21:07 +03:00
if ( ! buffer_uptodate ( bh ) & &
2019-04-10 20:46:35 +03:00
! cmpxchg ( & sdp - > sd_log_error , 0 , - EIO ) ) {
2006-10-03 19:10:41 +04:00
gfs2_io_error_bh ( sdp , bh ) ;
2019-02-12 23:43:55 +03:00
gfs2_withdraw_delayed ( sdp ) ;
2018-06-07 13:56:46 +03:00
}
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
/*
* If we have space for revokes and the bd is no longer on any
* buf list , we can just add a revoke for it immediately and
* avoid having to put it on the ail2 list , where it would need
* to be revoked later .
*/
if ( * max_revokes & & list_empty ( & bd - > bd_list ) ) {
gfs2_add_revoke ( sdp , bd ) ;
( * max_revokes ) - - ;
continue ;
}
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_move ( & bd - > bd_ail_st_list , & tr - > tr_ail2_list ) ;
2006-10-03 19:10:41 +04:00
}
2020-08-18 16:05:14 +03:00
return active_count ;
2006-10-03 19:10:41 +04:00
}
2011-04-18 17:18:09 +04:00
/**
* gfs2_ail1_empty - Try to empty the ail1 lists
* @ sdp : The superblock
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
* @ max_revokes : If non - zero , add revokes where appropriate
2011-04-18 17:18:09 +04:00
*
* Tries to empty the ail1 lists , starting with the oldest first
*/
2006-01-16 19:50:04 +03:00
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
static int gfs2_ail1_empty ( struct gfs2_sbd * sdp , int max_revokes )
2006-01-16 19:50:04 +03:00
{
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
struct gfs2_trans * tr , * s ;
2013-06-14 20:38:29 +04:00
int oldest_tr = 1 ;
2006-01-16 19:50:04 +03:00
int ret ;
2011-03-11 14:52:25 +03:00
spin_lock ( & sdp - > sd_ail_lock ) ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_for_each_entry_safe_reverse ( tr , s , & sdp - > sd_ail1_list , tr_list ) {
2020-08-18 16:05:14 +03:00
if ( ! gfs2_ail1_empty_one ( sdp , tr , & max_revokes ) & & oldest_tr )
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_move ( & tr - > tr_list , & sdp - > sd_ail2_list ) ;
2011-04-18 17:18:09 +04:00
else
2013-06-14 20:38:29 +04:00
oldest_tr = 0 ;
2006-01-16 19:50:04 +03:00
}
2020-12-19 09:15:17 +03:00
gfs2_log_update_flush_tail ( sdp ) ;
2006-01-16 19:50:04 +03:00
ret = list_empty ( & sdp - > sd_ail1_list ) ;
2011-03-11 14:52:25 +03:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
2006-01-16 19:50:04 +03:00
2019-02-12 23:43:55 +03:00
if ( test_bit ( SDF_WITHDRAWING , & sdp - > sd_flags ) ) {
2020-01-23 20:41:00 +03:00
gfs2_lm ( sdp , " fatal: I/O error(s) \n " ) ;
gfs2_withdraw ( sdp ) ;
}
2018-06-07 13:56:46 +03:00
2006-01-16 19:50:04 +03:00
return ret ;
}
2011-05-21 22:21:07 +04:00
static void gfs2_ail1_wait ( struct gfs2_sbd * sdp )
{
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
struct gfs2_trans * tr ;
2011-05-21 22:21:07 +04:00
struct gfs2_bufdata * bd ;
struct buffer_head * bh ;
spin_lock ( & sdp - > sd_ail_lock ) ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
list_for_each_entry_reverse ( tr , & sdp - > sd_ail1_list , tr_list ) {
list_for_each_entry ( bd , & tr - > tr_ail1_list , bd_ail_st_list ) {
2011-05-21 22:21:07 +04:00
bh = bd - > bd_bh ;
if ( ! buffer_locked ( bh ) )
continue ;
get_bh ( bh ) ;
spin_unlock ( & sdp - > sd_ail_lock ) ;
wait_on_buffer ( bh ) ;
brelse ( bh ) ;
return ;
}
}
spin_unlock ( & sdp - > sd_ail_lock ) ;
}
2006-10-03 19:10:41 +04:00
2020-12-11 16:45:23 +03:00
static void __ail2_empty ( struct gfs2_sbd * sdp , struct gfs2_trans * tr )
2006-10-03 19:10:41 +04:00
{
2020-12-11 16:45:23 +03:00
gfs2_ail_empty_tr ( sdp , tr , & tr - > tr_ail2_list ) ;
list_del ( & tr - > tr_list ) ;
gfs2_assert_warn ( sdp , list_empty ( & tr - > tr_ail1_list ) ) ;
gfs2_assert_warn ( sdp , list_empty ( & tr - > tr_ail2_list ) ) ;
gfs2_trans_free ( sdp , tr ) ;
2006-10-03 19:10:41 +04:00
}
2006-01-16 19:50:04 +03:00
static void ail2_empty ( struct gfs2_sbd * sdp , unsigned int new_tail )
{
2020-12-11 16:45:23 +03:00
struct list_head * ail2_list = & sdp - > sd_ail2_list ;
2006-01-16 19:50:04 +03:00
unsigned int old_tail = sdp - > sd_log_tail ;
2020-12-11 16:45:23 +03:00
struct gfs2_trans * tr , * safe ;
2006-01-16 19:50:04 +03:00
2011-03-11 14:52:25 +03:00
spin_lock ( & sdp - > sd_ail_lock ) ;
2020-12-11 16:45:23 +03:00
if ( old_tail < = new_tail ) {
list_for_each_entry_safe ( tr , safe , ail2_list , tr_list ) {
if ( old_tail < = tr - > tr_first & & tr - > tr_first < new_tail )
__ail2_empty ( sdp , tr ) ;
}
} else {
list_for_each_entry_safe ( tr , safe , ail2_list , tr_list ) {
if ( old_tail < = tr - > tr_first | | tr - > tr_first < new_tail )
__ail2_empty ( sdp , tr ) ;
}
2006-01-16 19:50:04 +03:00
}
2011-03-11 14:52:25 +03:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
2006-01-16 19:50:04 +03:00
}
2020-12-13 11:21:34 +03:00
/**
* gfs2_log_is_empty - Check if the log is empty
* @ sdp : The GFS2 superblock
*/
2006-01-16 19:50:04 +03:00
2020-12-13 11:21:34 +03:00
bool gfs2_log_is_empty ( struct gfs2_sbd * sdp ) {
return atomic_read ( & sdp - > sd_log_blks_free ) = = sdp - > sd_jdesc - > jd_blocks ;
}
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
static bool __gfs2_log_try_reserve_revokes ( struct gfs2_sbd * sdp , unsigned int revokes )
{
unsigned int available ;
available = atomic_read ( & sdp - > sd_log_revokes_available ) ;
while ( available > = revokes ) {
if ( atomic_try_cmpxchg ( & sdp - > sd_log_revokes_available ,
& available , available - revokes ) )
return true ;
2006-01-16 19:50:04 +03:00
}
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
return false ;
}
2006-01-16 19:50:04 +03:00
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
/**
* gfs2_log_release_revokes - Release a given number of revokes
* @ sdp : The GFS2 superblock
* @ revokes : The number of revokes to release
*
* sdp - > sd_log_flush_lock must be held .
*/
void gfs2_log_release_revokes ( struct gfs2_sbd * sdp , unsigned int revokes )
{
if ( revokes )
atomic_add ( revokes , & sdp - > sd_log_revokes_available ) ;
2006-01-16 19:50:04 +03:00
}
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
/**
* gfs2_log_release - Release a given number of log blocks
* @ sdp : The GFS2 superblock
* @ blks : The number of blocks
*
*/
void gfs2_log_release ( struct gfs2_sbd * sdp , unsigned int blks )
{
atomic_add ( blks , & sdp - > sd_log_blks_free ) ;
trace_gfs2_log_blocks ( sdp , blks ) ;
gfs2_assert_withdraw ( sdp , atomic_read ( & sdp - > sd_log_blks_free ) < =
sdp - > sd_jdesc - > jd_blocks ) ;
2020-12-13 13:37:17 +03:00
if ( atomic_read ( & sdp - > sd_log_blks_needed ) )
wake_up ( & sdp - > sd_log_waitq ) ;
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
}
2006-01-16 19:50:04 +03:00
/**
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
* __gfs2_log_try_reserve - Try to make a log reservation
* @ sdp : The GFS2 superblock
* @ blks : The number of blocks to reserve
* @ taboo_blks : The number of blocks to leave free
*
* Try to do the same as __gfs2_log_reserve ( ) , but fail if no more log
* space is immediately available .
*/
static bool __gfs2_log_try_reserve ( struct gfs2_sbd * sdp , unsigned int blks ,
unsigned int taboo_blks )
{
unsigned wanted = blks + taboo_blks ;
unsigned int free_blocks ;
free_blocks = atomic_read ( & sdp - > sd_log_blks_free ) ;
while ( free_blocks > = wanted ) {
if ( atomic_try_cmpxchg ( & sdp - > sd_log_blks_free , & free_blocks ,
free_blocks - blks ) ) {
trace_gfs2_log_blocks ( sdp , - blks ) ;
return true ;
}
}
return false ;
}
/**
* __gfs2_log_reserve - Make a log reservation
2006-01-16 19:50:04 +03:00
* @ sdp : The GFS2 superblock
* @ blks : The number of blocks to reserve
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
* @ taboo_blks : The number of blocks to leave free
2006-01-16 19:50:04 +03:00
*
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
* @ taboo_blks is set to 0 for logd , and to GFS2_LOG_FLUSH_MIN_BLOCKS
* for all other processes . This ensures that when the log is almost full ,
* logd will still be able to call gfs2_log_flush one more time without
* blocking , which will advance the tail and make some more log space
* available .
2006-11-23 18:51:34 +03:00
*
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
* We no longer flush the log here , instead we wake up logd to do that
* for us . To avoid the thundering herd and to ensure that we deal fairly
* with queued waiters , we use an exclusive wait . This means that when we
* get woken with enough journal space to get our reservation , we need to
* wake the next waiter on the list .
2006-01-16 19:50:04 +03:00
*/
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
static void __gfs2_log_reserve ( struct gfs2_sbd * sdp , unsigned int blks ,
unsigned int taboo_blks )
2006-01-16 19:50:04 +03:00
{
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
unsigned wanted = blks + taboo_blks ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
unsigned int free_blocks ;
2006-01-16 19:50:04 +03:00
2017-01-06 00:01:45 +03:00
atomic_add ( blks , & sdp - > sd_log_blks_needed ) ;
2020-12-13 13:37:17 +03:00
for ( ; ; ) {
if ( current ! = sdp - > sd_logd_process )
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
wake_up ( & sdp - > sd_logd_waitq ) ;
2020-12-13 13:37:17 +03:00
io_wait_event ( sdp - > sd_log_waitq ,
( free_blocks = atomic_read ( & sdp - > sd_log_blks_free ) ,
free_blocks > = wanted ) ) ;
do {
if ( atomic_try_cmpxchg ( & sdp - > sd_log_blks_free ,
& free_blocks ,
free_blocks - blks ) )
goto reserved ;
} while ( free_blocks > = wanted ) ;
2014-11-14 05:42:04 +03:00
}
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
2020-12-13 13:37:17 +03:00
reserved :
trace_gfs2_log_blocks ( sdp , - blks ) ;
if ( atomic_sub_return ( blks , & sdp - > sd_log_blks_needed ) )
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
wake_up ( & sdp - > sd_log_waitq ) ;
2006-01-16 19:50:04 +03:00
}
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
/**
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
* gfs2_log_try_reserve - Try to make a log reservation
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
* @ sdp : The GFS2 superblock
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
* @ tr : The transaction
* @ extra_revokes : The number of additional revokes reserved ( output )
*
* This is similar to gfs2_log_reserve , but sdp - > sd_log_flush_lock must be
* held for correct revoke accounting .
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
*/
2006-03-29 18:12:12 +04:00
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
bool gfs2_log_try_reserve ( struct gfs2_sbd * sdp , struct gfs2_trans * tr ,
unsigned int * extra_revokes )
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
{
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
unsigned int blks = tr - > tr_reserved ;
unsigned int revokes = tr - > tr_revokes ;
unsigned int revoke_blks = 0 ;
* extra_revokes = 0 ;
if ( revokes & & ! __gfs2_log_try_reserve_revokes ( sdp , revokes ) ) {
revoke_blks = DIV_ROUND_UP ( revokes , sdp - > sd_inptrs ) ;
* extra_revokes = revoke_blks * sdp - > sd_inptrs - revokes ;
blks + = revoke_blks ;
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
}
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
if ( ! blks )
return true ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
if ( __gfs2_log_try_reserve ( sdp , blks , GFS2_LOG_FLUSH_MIN_BLOCKS ) )
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
return true ;
if ( ! revoke_blks )
gfs2_log_release_revokes ( sdp , revokes ) ;
return false ;
}
/**
* gfs2_log_reserve - Make a log reservation
* @ sdp : The GFS2 superblock
* @ tr : The transaction
* @ extra_revokes : The number of additional revokes reserved ( output )
*
* sdp - > sd_log_flush_lock must not be held .
*/
void gfs2_log_reserve ( struct gfs2_sbd * sdp , struct gfs2_trans * tr ,
unsigned int * extra_revokes )
{
unsigned int blks = tr - > tr_reserved ;
unsigned int revokes = tr - > tr_revokes ;
2021-06-30 20:49:59 +03:00
unsigned int revoke_blks ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
* extra_revokes = 0 ;
if ( revokes ) {
revoke_blks = DIV_ROUND_UP ( revokes , sdp - > sd_inptrs ) ;
* extra_revokes = revoke_blks * sdp - > sd_inptrs - revokes ;
blks + = revoke_blks ;
}
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
__gfs2_log_reserve ( sdp , blks , GFS2_LOG_FLUSH_MIN_BLOCKS ) ;
2006-01-16 19:50:04 +03:00
}
/**
* log_distance - Compute distance between two journal blocks
* @ sdp : The GFS2 superblock
* @ newer : The most recent journal block of the pair
* @ older : The older journal block of the pair
*
* Compute the distance ( in the journal direction ) between two
* blocks in the journal
*
* Returns : the distance in blocks
*/
2006-09-13 19:13:27 +04:00
static inline unsigned int log_distance ( struct gfs2_sbd * sdp , unsigned int newer ,
2006-01-16 19:50:04 +03:00
unsigned int older )
{
int dist ;
dist = newer - older ;
if ( dist < 0 )
dist + = sdp - > sd_jdesc - > jd_blocks ;
return dist ;
}
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
/**
2020-12-06 15:30:14 +03:00
* calc_reserved - Calculate the number of blocks to keep reserved
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
* @ sdp : The GFS2 superblock
*
* This is complex . We need to reserve room for all our currently used
2020-12-06 15:30:14 +03:00
* metadata blocks ( e . g . normal file I / O rewriting file time stamps ) and
* all our journaled data blocks for journaled files ( e . g . files in the
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
* meta_fs like rindex , or files for which chattr + j was done . )
2020-12-06 15:30:14 +03:00
* If we don ' t reserve enough space , corruption will follow .
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
*
2020-12-06 15:30:14 +03:00
* We can have metadata blocks and jdata blocks in the same journal . Each
* type gets its own log descriptor , for which we need to reserve a block .
* In fact , each type has the potential for needing more than one log descriptor
* in cases where we have more blocks than will fit in a log descriptor .
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
* Metadata journal entries take up half the space of journaled buffer entries .
*
* Also , we need to reserve blocks for revoke journal entries and one for an
* overall header for the lot .
*
* Returns : the number of blocks reserved
*/
static unsigned int calc_reserved ( struct gfs2_sbd * sdp )
{
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
unsigned int reserved = GFS2_LOG_FLUSH_MIN_BLOCKS ;
2021-01-29 21:56:37 +03:00
unsigned int blocks ;
2014-02-22 01:55:33 +04:00
struct gfs2_trans * tr = sdp - > sd_log_tr ;
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
2014-02-22 01:55:33 +04:00
if ( tr ) {
2021-01-29 21:56:37 +03:00
blocks = tr - > tr_num_buf_new - tr - > tr_num_buf_rm ;
reserved + = blocks + DIV_ROUND_UP ( blocks , buf_limit ( sdp ) ) ;
blocks = tr - > tr_num_databuf_new - tr - > tr_num_databuf_rm ;
reserved + = blocks + DIV_ROUND_UP ( blocks , databuf_limit ( sdp ) ) ;
2014-02-22 01:55:33 +04:00
}
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
return reserved ;
}
2020-12-19 09:15:17 +03:00
static void log_pull_tail ( struct gfs2_sbd * sdp )
2006-01-16 19:50:04 +03:00
{
2020-12-19 09:15:17 +03:00
unsigned int new_tail = sdp - > sd_log_flush_tail ;
unsigned int dist ;
2006-01-16 19:50:04 +03:00
2020-12-19 09:15:17 +03:00
if ( new_tail = = sdp - > sd_log_tail )
return ;
dist = log_distance ( sdp , new_tail , sdp - > sd_log_tail ) ;
2006-01-16 19:50:04 +03:00
ail2_empty ( sdp , new_tail ) ;
2020-12-13 01:30:22 +03:00
gfs2_log_release ( sdp , dist ) ;
2006-01-16 19:50:04 +03:00
sdp - > sd_log_tail = new_tail ;
}
2019-11-13 22:47:02 +03:00
void log_flush_wait ( struct gfs2_sbd * sdp )
2006-01-16 19:50:04 +03:00
{
2007-09-17 13:59:52 +04:00
DEFINE_WAIT ( wait ) ;
if ( atomic_read ( & sdp - > sd_log_in_flight ) ) {
do {
prepare_to_wait ( & sdp - > sd_log_flush_wait , & wait ,
TASK_UNINTERRUPTIBLE ) ;
if ( atomic_read ( & sdp - > sd_log_in_flight ) )
io_schedule ( ) ;
} while ( atomic_read ( & sdp - > sd_log_in_flight ) ) ;
finish_wait ( & sdp - > sd_log_flush_wait , & wait ) ;
2006-01-16 19:50:04 +03:00
}
}
2021-04-08 21:28:34 +03:00
static int ip_cmp ( void * priv , const struct list_head * a , const struct list_head * b )
2012-02-14 23:49:57 +04:00
{
2013-01-28 13:30:07 +04:00
struct gfs2_inode * ipa , * ipb ;
2012-02-14 23:49:57 +04:00
2013-01-28 13:30:07 +04:00
ipa = list_entry ( a , struct gfs2_inode , i_ordered ) ;
ipb = list_entry ( b , struct gfs2_inode , i_ordered ) ;
2012-02-14 23:49:57 +04:00
2013-01-28 13:30:07 +04:00
if ( ipa - > i_no_addr < ipb - > i_no_addr )
2012-02-14 23:49:57 +04:00
return - 1 ;
2013-01-28 13:30:07 +04:00
if ( ipa - > i_no_addr > ipb - > i_no_addr )
2012-02-14 23:49:57 +04:00
return 1 ;
return 0 ;
}
2020-06-17 15:47:34 +03:00
static void __ordered_del_inode ( struct gfs2_inode * ip )
{
if ( ! list_empty ( & ip - > i_ordered ) )
list_del_init ( & ip - > i_ordered ) ;
}
2007-09-02 13:48:13 +04:00
static void gfs2_ordered_write ( struct gfs2_sbd * sdp )
{
2013-01-28 13:30:07 +04:00
struct gfs2_inode * ip ;
2007-09-02 13:48:13 +04:00
LIST_HEAD ( written ) ;
2013-01-28 13:30:07 +04:00
spin_lock ( & sdp - > sd_ordered_lock ) ;
2019-04-05 14:16:14 +03:00
list_sort ( NULL , & sdp - > sd_log_ordered , & ip_cmp ) ;
while ( ! list_empty ( & sdp - > sd_log_ordered ) ) {
2020-02-03 21:22:45 +03:00
ip = list_first_entry ( & sdp - > sd_log_ordered , struct gfs2_inode , i_ordered ) ;
2017-12-22 16:55:31 +03:00
if ( ip - > i_inode . i_mapping - > nrpages = = 0 ) {
2020-06-17 15:47:34 +03:00
__ordered_del_inode ( ip ) ;
2007-09-02 13:48:13 +04:00
continue ;
2017-12-22 16:55:31 +03:00
}
list_move ( & ip - > i_ordered , & written ) ;
2013-01-28 13:30:07 +04:00
spin_unlock ( & sdp - > sd_ordered_lock ) ;
filemap_fdatawrite ( ip - > i_inode . i_mapping ) ;
spin_lock ( & sdp - > sd_ordered_lock ) ;
2007-09-02 13:48:13 +04:00
}
2019-04-05 14:16:14 +03:00
list_splice ( & written , & sdp - > sd_log_ordered ) ;
2013-01-28 13:30:07 +04:00
spin_unlock ( & sdp - > sd_ordered_lock ) ;
2007-09-02 13:48:13 +04:00
}
static void gfs2_ordered_wait ( struct gfs2_sbd * sdp )
{
2013-01-28 13:30:07 +04:00
struct gfs2_inode * ip ;
2007-09-02 13:48:13 +04:00
2013-01-28 13:30:07 +04:00
spin_lock ( & sdp - > sd_ordered_lock ) ;
2019-04-05 14:16:14 +03:00
while ( ! list_empty ( & sdp - > sd_log_ordered ) ) {
2020-02-03 21:22:45 +03:00
ip = list_first_entry ( & sdp - > sd_log_ordered , struct gfs2_inode , i_ordered ) ;
2020-06-17 15:47:34 +03:00
__ordered_del_inode ( ip ) ;
2013-01-28 13:30:07 +04:00
if ( ip - > i_inode . i_mapping - > nrpages = = 0 )
2007-09-02 13:48:13 +04:00
continue ;
2013-01-28 13:30:07 +04:00
spin_unlock ( & sdp - > sd_ordered_lock ) ;
filemap_fdatawait ( ip - > i_inode . i_mapping ) ;
spin_lock ( & sdp - > sd_ordered_lock ) ;
2007-09-02 13:48:13 +04:00
}
2013-01-28 13:30:07 +04:00
spin_unlock ( & sdp - > sd_ordered_lock ) ;
}
void gfs2_ordered_del_inode ( struct gfs2_inode * ip )
{
struct gfs2_sbd * sdp = GFS2_SB ( & ip - > i_inode ) ;
spin_lock ( & sdp - > sd_ordered_lock ) ;
2020-06-17 15:47:34 +03:00
__ordered_del_inode ( ip ) ;
2013-01-28 13:30:07 +04:00
spin_unlock ( & sdp - > sd_ordered_lock ) ;
2007-09-02 13:48:13 +04:00
}
2013-06-14 20:38:29 +04:00
void gfs2_add_revoke ( struct gfs2_sbd * sdp , struct gfs2_bufdata * bd )
{
struct buffer_head * bh = bd - > bd_bh ;
struct gfs2_glock * gl = bd - > bd_gl ;
2020-05-05 19:56:46 +03:00
sdp - > sd_log_num_revoke + + ;
if ( atomic_inc_return ( & gl - > gl_revokes ) = = 1 )
gfs2_glock_hold ( gl ) ;
2013-06-14 20:38:29 +04:00
bh - > b_private = NULL ;
bd - > bd_blkno = bh - > b_blocknr ;
2013-12-10 21:06:35 +04:00
gfs2_remove_from_ail ( bd ) ; /* drops ref on bh */
bd - > bd_bh = NULL ;
2013-06-14 20:38:29 +04:00
set_bit ( GLF_LFLUSH , & gl - > gl_flags ) ;
2019-04-05 14:16:14 +03:00
list_add ( & bd - > bd_list , & sdp - > sd_log_revokes ) ;
2013-06-14 20:38:29 +04:00
}
2019-11-14 17:49:11 +03:00
void gfs2_glock_remove_revoke ( struct gfs2_glock * gl )
{
if ( atomic_dec_return ( & gl - > gl_revokes ) = = 0 ) {
clear_bit ( GLF_LFLUSH , & gl - > gl_flags ) ;
gfs2_glock_queue_put ( gl ) ;
}
}
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
/**
2020-12-19 05:11:51 +03:00
* gfs2_flush_revokes - Add as many revokes to the system transaction as we can
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
* @ sdp : The GFS2 superblock
*
* Our usual strategy is to defer writing revokes as much as we can in the hope
* that we ' ll eventually overwrite the journal , which will make those revokes
* go away . This changes when we flush the log : at that point , there will
* likely be some left - over space in the last revoke block of that transaction .
* We can fill that space with additional revokes for blocks that have already
* been written back . This will basically come at no cost now , and will save
* us from having to keep track of those blocks on the AIL2 list later .
*/
2020-12-19 05:11:51 +03:00
void gfs2_flush_revokes ( struct gfs2_sbd * sdp )
2013-06-14 20:38:29 +04:00
{
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
/* number of revokes we still have room for */
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
unsigned int max_revokes = atomic_read ( & sdp - > sd_log_revokes_available ) ;
2013-06-14 20:38:29 +04:00
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
gfs2_log_lock ( sdp ) ;
gfs2_ail1_empty ( sdp , max_revokes ) ;
2013-06-14 20:38:29 +04:00
gfs2_log_unlock ( sdp ) ;
}
2012-03-09 14:45:56 +04:00
/**
2019-03-25 18:34:19 +03:00
* gfs2_write_log_header - Write a journal log header buffer at lblock
2012-03-09 14:45:56 +04:00
* @ sdp : The GFS2 superblock
2018-01-17 02:01:33 +03:00
* @ jd : journal descriptor of the journal to which we are writing
2017-12-18 21:48:29 +03:00
* @ seq : sequence number
* @ tail : tail of the log
2019-03-25 18:34:19 +03:00
* @ lblock : value for lh_blkno ( block number relative to start of journal )
2018-01-17 02:01:33 +03:00
* @ flags : log header flags GFS2_LOG_HEAD_ *
2017-12-18 21:48:29 +03:00
* @ op_flags : flags to pass to the bio
2012-03-09 14:45:56 +04:00
*
* Returns : the initialized log buffer descriptor
*/
2018-01-17 02:01:33 +03:00
void gfs2_write_log_header ( struct gfs2_sbd * sdp , struct gfs2_jdesc * jd ,
2019-03-25 18:34:19 +03:00
u64 seq , u32 tail , u32 lblock , u32 flags ,
2022-07-14 21:07:19 +03:00
blk_opf_t op_flags )
2012-03-09 14:45:56 +04:00
{
struct gfs2_log_header * lh ;
2018-01-17 02:01:33 +03:00
u32 hash , crc ;
2019-11-20 16:53:14 +03:00
struct page * page ;
2018-01-17 02:01:33 +03:00
struct gfs2_statfs_change_host * l_sc = & sdp - > sd_statfs_local ;
struct timespec64 tv ;
struct super_block * sb = sdp - > sd_vfs ;
2019-03-25 18:34:19 +03:00
u64 dblock ;
2017-12-18 21:48:29 +03:00
2019-11-20 16:53:14 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-12-11 03:36:25 +03:00
return ;
2019-11-20 16:53:14 +03:00
page = mempool_alloc ( gfs2_page_pool , GFP_NOIO ) ;
2012-04-16 12:28:31 +04:00
lh = page_address ( page ) ;
clear_page ( lh ) ;
2012-03-09 14:45:56 +04:00
lh - > lh_header . mh_magic = cpu_to_be32 ( GFS2_MAGIC ) ;
lh - > lh_header . mh_type = cpu_to_be32 ( GFS2_METATYPE_LH ) ;
lh - > lh_header . __pad0 = cpu_to_be64 ( 0 ) ;
lh - > lh_header . mh_format = cpu_to_be32 ( GFS2_FORMAT_LH ) ;
lh - > lh_header . mh_jid = cpu_to_be32 ( sdp - > sd_jdesc - > jd_jid ) ;
2017-12-18 21:48:29 +03:00
lh - > lh_sequence = cpu_to_be64 ( seq ) ;
2012-03-09 14:45:56 +04:00
lh - > lh_flags = cpu_to_be32 ( flags ) ;
lh - > lh_tail = cpu_to_be32 ( tail ) ;
2019-03-25 18:34:19 +03:00
lh - > lh_blkno = cpu_to_be32 ( lblock ) ;
2018-01-17 02:01:33 +03:00
hash = ~ crc32 ( ~ 0 , lh , LH_V1_SIZE ) ;
2012-03-09 14:45:56 +04:00
lh - > lh_hash = cpu_to_be32 ( hash ) ;
2018-06-20 23:15:24 +03:00
ktime_get_coarse_real_ts64 ( & tv ) ;
2018-01-17 02:01:33 +03:00
lh - > lh_nsec = cpu_to_be32 ( tv . tv_nsec ) ;
lh - > lh_sec = cpu_to_be64 ( tv . tv_sec ) ;
2019-03-25 18:34:19 +03:00
if ( ! list_empty ( & jd - > extent_list ) )
2019-08-28 23:21:34 +03:00
dblock = gfs2_log_bmap ( jd , lblock ) ;
2019-03-25 18:34:19 +03:00
else {
2021-03-28 00:05:14 +03:00
unsigned int extlen ;
int ret ;
extlen = 1 ;
ret = gfs2_get_extent ( jd - > jd_inode , lblock , & dblock , & extlen ) ;
2019-03-25 18:34:19 +03:00
if ( gfs2_assert_withdraw ( sdp , ret = = 0 ) )
return ;
}
lh - > lh_addr = cpu_to_be64 ( dblock ) ;
2018-01-17 02:01:33 +03:00
lh - > lh_jinode = cpu_to_be64 ( GFS2_I ( jd - > jd_inode ) - > i_no_addr ) ;
/* We may only write local statfs, quota, etc., when writing to our
own journal . The values are left 0 when recovering a journal
different from our own . */
if ( ! ( flags & GFS2_LOG_HEAD_RECOVERY ) ) {
lh - > lh_statfs_addr =
cpu_to_be64 ( GFS2_I ( sdp - > sd_sc_inode ) - > i_no_addr ) ;
lh - > lh_quota_addr =
cpu_to_be64 ( GFS2_I ( sdp - > sd_qc_inode ) - > i_no_addr ) ;
spin_lock ( & sdp - > sd_statfs_spin ) ;
lh - > lh_local_total = cpu_to_be64 ( l_sc - > sc_total ) ;
lh - > lh_local_free = cpu_to_be64 ( l_sc - > sc_free ) ;
lh - > lh_local_dinodes = cpu_to_be64 ( l_sc - > sc_dinodes ) ;
spin_unlock ( & sdp - > sd_statfs_spin ) ;
}
BUILD_BUG_ON ( offsetof ( struct gfs2_log_header , lh_crc ) ! = LH_V1_SIZE ) ;
crc = crc32c ( ~ 0 , ( void * ) lh + LH_V1_SIZE + 4 ,
sb - > s_blocksize - LH_V1_SIZE - 4 ) ;
lh - > lh_crc = cpu_to_be32 ( crc ) ;
2021-01-21 18:10:26 +03:00
gfs2_log_write ( sdp , jd , page , sb - > s_blocksize , 0 , dblock ) ;
gfs2_log_submit_bio ( & jd - > jd_log_bio , REQ_OP_WRITE | op_flags ) ;
2017-12-18 21:48:29 +03:00
}
/**
* log_write_header - Get and initialize a journal header buffer
* @ sdp : The GFS2 superblock
2018-01-17 02:01:33 +03:00
* @ flags : The log header flags , including log header origin
2017-12-18 21:48:29 +03:00
*
* Returns : the initialized log buffer descriptor
*/
static void log_write_header ( struct gfs2_sbd * sdp , u32 flags )
{
2022-07-14 21:07:19 +03:00
blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC ;
2017-12-18 21:48:29 +03:00
enum gfs2_freeze_state state = atomic_read ( & sdp - > sd_freeze_state ) ;
gfs2_assert_withdraw ( sdp , ( state ! = SFS_FROZEN ) ) ;
2012-03-09 14:45:56 +04:00
if ( test_bit ( SDF_NOBARRIERS , & sdp - > sd_flags ) ) {
gfs2_ordered_wait ( sdp ) ;
log_flush_wait ( sdp ) ;
2016-11-01 16:40:10 +03:00
op_flags = REQ_SYNC | REQ_META | REQ_PRIO ;
2012-03-09 14:45:56 +04:00
}
2020-12-19 09:15:17 +03:00
sdp - > sd_log_idle = ( sdp - > sd_log_flush_tail = = sdp - > sd_log_flush_head ) ;
gfs2_write_log_header ( sdp , sdp - > sd_jdesc , sdp - > sd_log_sequence + + ,
sdp - > sd_log_flush_tail , sdp - > sd_log_flush_head ,
flags , op_flags ) ;
2019-08-28 23:21:34 +03:00
gfs2_log_incr_head ( sdp ) ;
2020-12-11 03:36:25 +03:00
log_flush_wait ( sdp ) ;
2020-12-19 09:15:17 +03:00
log_pull_tail ( sdp ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
gfs2_log_update_head ( sdp ) ;
2012-03-09 14:45:56 +04:00
}
2019-11-13 22:58:30 +03:00
/**
2021-05-19 21:54:02 +03:00
* gfs2_ail_drain - drain the ail lists after a withdraw
2019-11-13 22:58:30 +03:00
* @ sdp : Pointer to GFS2 superblock
*/
2021-05-19 21:54:02 +03:00
void gfs2_ail_drain ( struct gfs2_sbd * sdp )
2019-11-13 22:58:30 +03:00
{
struct gfs2_trans * tr ;
spin_lock ( & sdp - > sd_ail_lock ) ;
/*
* For transactions on the sd_ail1_list we need to drain both the
* ail1 and ail2 lists . That ' s because function gfs2_ail1_start_one
* ( temporarily ) moves items from its tr_ail1 list to tr_ail2 list
* before revokes are sent for that block . Items on the sd_ail2_list
* should have already gotten beyond that point , so no need .
*/
while ( ! list_empty ( & sdp - > sd_ail1_list ) ) {
tr = list_first_entry ( & sdp - > sd_ail1_list , struct gfs2_trans ,
tr_list ) ;
gfs2_ail_empty_tr ( sdp , tr , & tr - > tr_ail1_list ) ;
gfs2_ail_empty_tr ( sdp , tr , & tr - > tr_ail2_list ) ;
list_del ( & tr - > tr_list ) ;
2019-04-17 21:04:27 +03:00
gfs2_trans_free ( sdp , tr ) ;
2019-11-13 22:58:30 +03:00
}
while ( ! list_empty ( & sdp - > sd_ail2_list ) ) {
tr = list_first_entry ( & sdp - > sd_ail2_list , struct gfs2_trans ,
tr_list ) ;
gfs2_ail_empty_tr ( sdp , tr , & tr - > tr_ail2_list ) ;
list_del ( & tr - > tr_list ) ;
2019-04-17 21:04:27 +03:00
gfs2_trans_free ( sdp , tr ) ;
2019-11-13 22:58:30 +03:00
}
2021-05-19 21:54:02 +03:00
gfs2_drain_revokes ( sdp ) ;
2019-11-13 22:58:30 +03:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
}
2020-05-22 22:03:21 +03:00
/**
* empty_ail1_list - try to start IO and empty the ail1 list
* @ sdp : Pointer to GFS2 superblock
*/
static void empty_ail1_list ( struct gfs2_sbd * sdp )
{
unsigned long start = jiffies ;
for ( ; ; ) {
if ( time_after ( jiffies , start + ( HZ * 600 ) ) ) {
fs_err ( sdp , " Error: In %s for 10 minutes! t=%d \n " ,
__func__ , current - > journal_info ? 1 : 0 ) ;
dump_ail_list ( sdp ) ;
return ;
}
gfs2_ail1_start ( sdp ) ;
gfs2_ail1_wait ( sdp ) ;
if ( gfs2_ail1_empty ( sdp , 0 ) )
return ;
}
}
2020-08-21 16:50:34 +03:00
/**
2020-08-31 16:12:15 +03:00
* trans_drain - drain the buf and databuf queue for a failed transaction
2020-08-21 16:50:34 +03:00
* @ tr : the transaction to drain
*
* When this is called , we ' re taking an error exit for a log write that failed
* but since we bypassed the after_commit functions , we need to remove the
* items from the buf and databuf queue .
*/
static void trans_drain ( struct gfs2_trans * tr )
{
struct gfs2_bufdata * bd ;
struct list_head * head ;
if ( ! tr )
return ;
head = & tr - > tr_buf ;
while ( ! list_empty ( head ) ) {
bd = list_first_entry ( head , struct gfs2_bufdata , bd_list ) ;
list_del_init ( & bd - > bd_list ) ;
2021-02-25 19:11:09 +03:00
if ( ! list_empty ( & bd - > bd_ail_st_list ) )
gfs2_remove_from_ail ( bd ) ;
2020-08-21 16:50:34 +03:00
kmem_cache_free ( gfs2_bufdata_cachep , bd ) ;
}
head = & tr - > tr_databuf ;
while ( ! list_empty ( head ) ) {
bd = list_first_entry ( head , struct gfs2_bufdata , bd_list ) ;
list_del_init ( & bd - > bd_list ) ;
2021-02-25 19:11:09 +03:00
if ( ! list_empty ( & bd - > bd_ail_st_list ) )
gfs2_remove_from_ail ( bd ) ;
2020-08-21 16:50:34 +03:00
kmem_cache_free ( gfs2_bufdata_cachep , bd ) ;
}
}
2006-01-16 19:50:04 +03:00
/**
2006-04-07 19:17:32 +04:00
* gfs2_log_flush - flush incore transaction ( s )
2021-03-30 19:44:29 +03:00
* @ sdp : The filesystem
2006-01-16 19:50:04 +03:00
* @ gl : The glock structure to flush . If NULL , flush the whole incore log
2018-01-08 18:34:17 +03:00
* @ flags : The log header flags : GFS2_LOG_HEAD_FLUSH_ * and debug flags
2006-01-16 19:50:04 +03:00
*
*/
2018-01-17 02:01:33 +03:00
void gfs2_log_flush ( struct gfs2_sbd * sdp , struct gfs2_glock * gl , u32 flags )
2006-01-16 19:50:04 +03:00
{
2019-11-13 22:58:30 +03:00
struct gfs2_trans * tr = NULL ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
unsigned int reserved_blocks = 0 , used_blocks = 0 ;
2014-11-14 05:42:04 +03:00
enum gfs2_freeze_state state = atomic_read ( & sdp - > sd_freeze_state ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
unsigned int first_log_head ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
unsigned int reserved_revokes = 0 ;
2006-01-16 19:50:04 +03:00
2006-03-29 18:12:12 +04:00
down_write ( & sdp - > sd_log_flush_lock ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
trace_gfs2_log_flush ( sdp , 1 , flags ) ;
2006-02-21 15:51:39 +03:00
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
repeat :
2019-11-13 22:58:30 +03:00
/*
* Do this check while holding the log_flush_lock to prevent new
* buffers from being added to the ail via gfs2_pin ( )
*/
2021-03-12 16:47:47 +03:00
if ( gfs2_withdrawn ( sdp ) | | ! test_bit ( SDF_JOURNAL_LIVE , & sdp - > sd_flags ) )
2019-11-13 22:58:30 +03:00
goto out ;
2007-11-08 17:25:12 +03:00
/* Log might have been flushed while we waited for the flush lock */
2020-08-29 00:44:36 +03:00
if ( gl & & ! test_bit ( GLF_LFLUSH , & gl - > gl_flags ) )
goto out ;
2006-02-21 15:51:39 +03:00
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
first_log_head = sdp - > sd_log_head ;
sdp - > sd_log_flush_head = first_log_head ;
2015-12-09 16:46:33 +03:00
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
tr = sdp - > sd_log_tr ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
if ( tr | | sdp - > sd_log_num_revoke ) {
if ( reserved_blocks )
gfs2_log_release ( sdp , reserved_blocks ) ;
reserved_blocks = sdp - > sd_log_blks_reserved ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
reserved_revokes = sdp - > sd_log_num_revoke ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
if ( tr ) {
sdp - > sd_log_tr = NULL ;
tr - > tr_first = first_log_head ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
if ( unlikely ( state = = SFS_FROZEN ) ) {
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
if ( gfs2_assert_withdraw_delayed ( sdp ,
! tr - > tr_num_buf_new & & ! tr - > tr_num_databuf_new ) )
goto out_withdraw ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
}
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
}
} else if ( ! reserved_blocks ) {
unsigned int taboo_blocks = GFS2_LOG_FLUSH_MIN_BLOCKS ;
reserved_blocks = GFS2_LOG_FLUSH_MIN_BLOCKS ;
if ( current = = sdp - > sd_logd_process )
taboo_blocks = 0 ;
if ( ! __gfs2_log_try_reserve ( sdp , reserved_blocks , taboo_blocks ) ) {
up_write ( & sdp - > sd_log_flush_lock ) ;
__gfs2_log_reserve ( sdp , reserved_blocks , taboo_blocks ) ;
down_write ( & sdp - > sd_log_flush_lock ) ;
goto repeat ;
}
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
BUG_ON ( sdp - > sd_log_num_revoke ) ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
}
2006-01-16 19:50:04 +03:00
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
if ( flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN )
clear_bit ( SDF_JOURNAL_LIVE , & sdp - > sd_flags ) ;
2014-11-14 05:42:04 +03:00
if ( unlikely ( state = = SFS_FROZEN ) )
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
if ( gfs2_assert_withdraw_delayed ( sdp , ! reserved_revokes ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
2006-01-16 19:50:04 +03:00
2007-09-02 13:48:13 +04:00
gfs2_ordered_write ( sdp ) ;
2019-11-13 22:58:30 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
2014-02-21 19:22:35 +04:00
lops_before_commit ( sdp , tr ) ;
2019-11-13 22:58:30 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
2021-01-21 18:10:26 +03:00
gfs2_log_submit_bio ( & sdp - > sd_jdesc - > jd_log_bio , REQ_OP_WRITE ) ;
2019-11-13 22:58:30 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
2007-09-02 13:48:13 +04:00
2012-03-09 14:45:56 +04:00
if ( sdp - > sd_log_head ! = sdp - > sd_log_flush_head ) {
2018-01-17 02:01:33 +03:00
log_write_header ( sdp , flags ) ;
2020-12-19 09:15:17 +03:00
} else if ( sdp - > sd_log_tail ! = sdp - > sd_log_flush_tail & & ! sdp - > sd_log_idle ) {
2018-01-17 02:01:33 +03:00
log_write_header ( sdp , flags ) ;
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
}
2019-11-13 22:58:30 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
lops_after_commit ( sdp , tr ) ;
2006-04-07 19:17:32 +04:00
2006-10-11 21:34:59 +04:00
gfs2_log_lock ( sdp ) ;
2006-09-13 19:13:27 +04:00
sdp - > sd_log_blks_reserved = 0 ;
2006-01-16 19:50:04 +03:00
2011-03-11 14:52:25 +03:00
spin_lock ( & sdp - > sd_ail_lock ) ;
GFS2: replace gfs2_ail structure with gfs2_trans
In order to allow transactions and log flushes to happen at the same
time, gfs2 needs to move the transaction accounting and active items
list code into the gfs2_trans structure. As a first step toward this,
this patch removes the gfs2_ail structure, and handles the active items
list in the gfs_trans structure. This keeps gfs2 from allocating an ail
structure on log flushes, and gives us a struture that can later be used
to store the transaction accounting outside of the gfs2 superblock
structure.
With this patch, at the end of a transaction, gfs2 will add the
gfs2_trans structure to the superblock if there is not one already.
This structure now has the active items fields that were previously in
gfs2_ail. This is not necessary in the case where the transaction was
simply used to add revokes, since these are never written outside of the
journal, and thus, don't need an active items list.
Also, in order to make sure that the transaction structure is not
removed while it's still in use by gfs2_trans_end, unlocking the
sd_log_flush_lock has to happen slightly later in ending the
transaction.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2013-04-06 05:31:46 +04:00
if ( tr & & ! list_empty ( & tr - > tr_ail1_list ) ) {
list_add ( & tr - > tr_list , & sdp - > sd_ail1_list ) ;
tr = NULL ;
2006-01-16 19:50:04 +03:00
}
2011-03-11 14:52:25 +03:00
spin_unlock ( & sdp - > sd_ail_lock ) ;
2006-01-16 19:50:04 +03:00
gfs2_log_unlock ( sdp ) ;
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
2018-01-17 02:01:33 +03:00
if ( ! ( flags & GFS2_LOG_HEAD_FLUSH_NORMAL ) ) {
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
if ( ! sdp - > sd_log_idle ) {
2020-05-22 22:03:21 +03:00
empty_ail1_list ( sdp ) ;
2019-11-13 20:47:09 +03:00
if ( gfs2_withdrawn ( sdp ) )
2020-08-29 00:44:36 +03:00
goto out_withdraw ;
2018-01-17 02:01:33 +03:00
log_write_header ( sdp , flags ) ;
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
}
2018-01-17 02:01:33 +03:00
if ( flags & ( GFS2_LOG_HEAD_FLUSH_SHUTDOWN |
GFS2_LOG_HEAD_FLUSH_FREEZE ) )
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
gfs2_log_shutdown ( sdp ) ;
2018-01-17 02:01:33 +03:00
if ( flags & GFS2_LOG_HEAD_FLUSH_FREEZE )
2014-11-14 05:42:04 +03:00
atomic_set ( & sdp - > sd_freeze_state , SFS_FROZEN ) ;
GFS2: remove transaction glock
GFS2 has a transaction glock, which must be grabbed for every
transaction, whose purpose is to deal with freezing the filesystem.
Aside from this involving a large amount of locking, it is very easy to
make the current fsfreeze code hang on unfreezing.
This patch rewrites how gfs2 handles freezing the filesystem. The
transaction glock is removed. In it's place is a freeze glock, which is
cached (but not held) in a shared state by every node in the cluster
when the filesystem is mounted. This lock only needs to be grabbed on
freezing, and actions which need to be safe from freezing, like
recovery.
When a node wants to freeze the filesystem, it grabs this glock
exclusively. When the freeze glock state changes on the nodes (either
from shared to unlocked, or shared to exclusive), the filesystem does a
special log flush. gfs2_log_flush() does all the work for flushing out
the and shutting down the incore log, and then it tries to grab the
freeze glock in a shared state again. Since the filesystem is stuck in
gfs2_log_flush, no new transaction can start, and nothing can be written
to disk. Unfreezing the filesytem simply involes dropping the freeze
glock, allowing gfs2_log_flush() to grab and then release the shared
lock, so it is cached for next time.
However, in order for the unfreezing ioctl to occur, gfs2 needs to get a
shared lock on the filesystem root directory inode to check permissions.
If that glock has already been grabbed exclusively, fsfreeze will be
unable to get the shared lock and unfreeze the filesystem.
In order to allow the unfreeze, this patch makes gfs2 grab a shared lock
on the filesystem root directory during the freeze, and hold it until it
unfreezes the filesystem. The functions which need to grab a shared
lock in order to allow the unfreeze ioctl to be issued now use the lock
grabbed by the freeze code instead.
The freeze and unfreeze code take care to make sure that this shared
lock will not be dropped while another process is using it.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2014-05-02 07:26:55 +04:00
}
2020-08-29 00:44:36 +03:00
out_end :
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
used_blocks = log_distance ( sdp , sdp - > sd_log_flush_head , first_log_head ) ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
reserved_revokes + = atomic_read ( & sdp - > sd_log_revokes_available ) ;
atomic_set ( & sdp - > sd_log_revokes_available , sdp - > sd_ldptrs ) ;
gfs2_assert_withdraw ( sdp , reserved_revokes % sdp - > sd_inptrs = = sdp - > sd_ldptrs ) ;
if ( reserved_revokes > sdp - > sd_ldptrs )
reserved_blocks + = ( reserved_revokes - sdp - > sd_ldptrs ) / sdp - > sd_inptrs ;
2020-08-29 00:44:36 +03:00
out :
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
if ( used_blocks ! = reserved_blocks ) {
gfs2_assert_withdraw_delayed ( sdp , used_blocks < reserved_blocks ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
gfs2_log_release ( sdp , reserved_blocks - used_blocks ) ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
}
2006-03-29 18:12:12 +04:00
up_write ( & sdp - > sd_log_flush_lock ) ;
2019-04-17 21:04:27 +03:00
gfs2_trans_free ( sdp , tr ) ;
2020-08-29 00:44:36 +03:00
if ( gfs2_withdrawing ( sdp ) )
gfs2_withdraw ( sdp ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
trace_gfs2_log_flush ( sdp , 0 , flags ) ;
2020-08-29 00:44:36 +03:00
return ;
out_withdraw :
trans_drain ( tr ) ;
/**
* If the tr_list is empty , we ' re withdrawing during a log
* flush that targets a transaction , but the transaction was
* never queued onto any of the ail lists . Here we add it to
* ail1 just so that ail_drain ( ) will find and free it .
*/
spin_lock ( & sdp - > sd_ail_lock ) ;
if ( tr & & list_empty ( & tr - > tr_list ) )
list_add ( & tr - > tr_list , & sdp - > sd_ail1_list ) ;
spin_unlock ( & sdp - > sd_ail_lock ) ;
tr = NULL ;
goto out_end ;
2006-01-16 19:50:04 +03:00
}
2014-02-21 19:22:35 +04:00
/**
* gfs2_merge_trans - Merge a new transaction into a cached transaction
2021-03-30 19:44:29 +03:00
* @ sdp : the filesystem
2014-02-21 19:22:35 +04:00
* @ new : New transaction to be merged
*/
gfs2: fix use-after-free on transaction ail lists
Before this patch, transactions could be merged into the system
transaction by function gfs2_merge_trans(), but the transaction ail
lists were never merged. Because the ail flushing mechanism can run
separately, bd elements can be attached to the transaction's buffer
list during the transaction (trans_add_meta, etc) but quickly moved
to its ail lists. Later, in function gfs2_trans_end, the transaction
can be freed (by gfs2_trans_end) while it still has bd elements
queued to its ail lists, which can cause it to either lose track of
the bd elements altogether (memory leak) or worse, reference the bd
elements after the parent transaction has been freed.
Although I've not seen any serious consequences, the problem becomes
apparent with the previous patch's addition of:
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
to function gfs2_trans_free().
This patch adds logic into gfs2_merge_trans() to move the merged
transaction's ail lists to the sdp transaction. This prevents the
use-after-free. To do this properly, we need to hold the ail lock,
so we pass sdp into the function instead of the transaction itself.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-06-04 22:28:58 +03:00
static void gfs2_merge_trans ( struct gfs2_sbd * sdp , struct gfs2_trans * new )
2014-02-21 19:22:35 +04:00
{
gfs2: fix use-after-free on transaction ail lists
Before this patch, transactions could be merged into the system
transaction by function gfs2_merge_trans(), but the transaction ail
lists were never merged. Because the ail flushing mechanism can run
separately, bd elements can be attached to the transaction's buffer
list during the transaction (trans_add_meta, etc) but quickly moved
to its ail lists. Later, in function gfs2_trans_end, the transaction
can be freed (by gfs2_trans_end) while it still has bd elements
queued to its ail lists, which can cause it to either lose track of
the bd elements altogether (memory leak) or worse, reference the bd
elements after the parent transaction has been freed.
Although I've not seen any serious consequences, the problem becomes
apparent with the previous patch's addition of:
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
to function gfs2_trans_free().
This patch adds logic into gfs2_merge_trans() to move the merged
transaction's ail lists to the sdp transaction. This prevents the
use-after-free. To do this properly, we need to hold the ail lock,
so we pass sdp into the function instead of the transaction itself.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-06-04 22:28:58 +03:00
struct gfs2_trans * old = sdp - > sd_log_tr ;
2017-01-25 20:50:47 +03:00
WARN_ON_ONCE ( ! test_bit ( TR_ATTACHED , & old - > tr_flags ) ) ;
2014-02-21 19:22:35 +04:00
old - > tr_num_buf_new + = new - > tr_num_buf_new ;
old - > tr_num_databuf_new + = new - > tr_num_databuf_new ;
old - > tr_num_buf_rm + = new - > tr_num_buf_rm ;
old - > tr_num_databuf_rm + = new - > tr_num_databuf_rm ;
gfs2: Per-revoke accounting in transactions
In the log, revokes are stored as a revoke descriptor (struct
gfs2_log_descriptor), followed by zero or more additional revoke blocks
(struct gfs2_meta_header). On filesystems with a blocksize of 4k, the
revoke descriptor contains up to 503 revokes, and the metadata blocks
contain up to 509 revokes each. We've so far been reserving space for
revokes in transactions in block granularity, so a lot more space than
necessary was being allocated and then released again.
This patch switches to assigning revokes to transactions individually
instead. Initially, space for the revoke descriptor is reserved and
handed out to transactions. When more revokes than that are reserved,
additional revoke blocks are added. When the log is flushed, the space
for the additional revoke blocks is released, but we keep the space for
the revoke descriptor block allocated.
Transactions may still reserve more revokes than they will actually need
in the end, but now we won't overshoot the target as much, and by only
returning the space for excess revokes at log flush time, we further
reduce the amount of contention between processes.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-17 18:14:30 +03:00
old - > tr_revokes + = new - > tr_revokes ;
2014-02-21 19:22:35 +04:00
old - > tr_num_revoke + = new - > tr_num_revoke ;
list_splice_tail_init ( & new - > tr_databuf , & old - > tr_databuf ) ;
list_splice_tail_init ( & new - > tr_buf , & old - > tr_buf ) ;
gfs2: fix use-after-free on transaction ail lists
Before this patch, transactions could be merged into the system
transaction by function gfs2_merge_trans(), but the transaction ail
lists were never merged. Because the ail flushing mechanism can run
separately, bd elements can be attached to the transaction's buffer
list during the transaction (trans_add_meta, etc) but quickly moved
to its ail lists. Later, in function gfs2_trans_end, the transaction
can be freed (by gfs2_trans_end) while it still has bd elements
queued to its ail lists, which can cause it to either lose track of
the bd elements altogether (memory leak) or worse, reference the bd
elements after the parent transaction has been freed.
Although I've not seen any serious consequences, the problem becomes
apparent with the previous patch's addition of:
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
to function gfs2_trans_free().
This patch adds logic into gfs2_merge_trans() to move the merged
transaction's ail lists to the sdp transaction. This prevents the
use-after-free. To do this properly, we need to hold the ail lock,
so we pass sdp into the function instead of the transaction itself.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-06-04 22:28:58 +03:00
spin_lock ( & sdp - > sd_ail_lock ) ;
list_splice_tail_init ( & new - > tr_ail1_list , & old - > tr_ail1_list ) ;
list_splice_tail_init ( & new - > tr_ail2_list , & old - > tr_ail2_list ) ;
spin_unlock ( & sdp - > sd_ail_lock ) ;
2014-02-21 19:22:35 +04:00
}
2006-01-16 19:50:04 +03:00
static void log_refund ( struct gfs2_sbd * sdp , struct gfs2_trans * tr )
{
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
unsigned int reserved ;
2008-01-10 17:49:43 +03:00
unsigned int unused ;
2014-02-22 01:55:33 +04:00
unsigned int maxres ;
2006-01-16 19:50:04 +03:00
gfs2_log_lock ( sdp ) ;
2014-02-22 01:55:33 +04:00
if ( sdp - > sd_log_tr ) {
gfs2: fix use-after-free on transaction ail lists
Before this patch, transactions could be merged into the system
transaction by function gfs2_merge_trans(), but the transaction ail
lists were never merged. Because the ail flushing mechanism can run
separately, bd elements can be attached to the transaction's buffer
list during the transaction (trans_add_meta, etc) but quickly moved
to its ail lists. Later, in function gfs2_trans_end, the transaction
can be freed (by gfs2_trans_end) while it still has bd elements
queued to its ail lists, which can cause it to either lose track of
the bd elements altogether (memory leak) or worse, reference the bd
elements after the parent transaction has been freed.
Although I've not seen any serious consequences, the problem becomes
apparent with the previous patch's addition of:
gfs2_assert_warn(sdp, list_empty(&tr->tr_ail1_list));
to function gfs2_trans_free().
This patch adds logic into gfs2_merge_trans() to move the merged
transaction's ail lists to the sdp transaction. This prevents the
use-after-free. To do this properly, we need to hold the ail lock,
so we pass sdp into the function instead of the transaction itself.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-06-04 22:28:58 +03:00
gfs2_merge_trans ( sdp , tr ) ;
2014-02-22 01:55:33 +04:00
} else if ( tr - > tr_num_buf_new | | tr - > tr_num_databuf_new ) {
2021-01-29 18:45:33 +03:00
gfs2_assert_withdraw ( sdp , ! test_bit ( TR_ONSTACK , & tr - > tr_flags ) ) ;
2014-02-22 01:55:33 +04:00
sdp - > sd_log_tr = tr ;
2017-01-25 20:50:47 +03:00
set_bit ( TR_ATTACHED , & tr - > tr_flags ) ;
2014-02-22 01:55:33 +04:00
}
[GFS2] assertion failure after writing to journaled file, umount
This patch passes all my nasty tests that were causing the code to
fail under one circumstance or another. Here is a complete summary
of all changes from today's git tree, in order of appearance:
1. There are now separate variables for metadata buffer accounting.
2. Variable sd_log_num_hdrs is no longer needed, since the header
accounting is taken care of by the reserve/refund sequence.
3. Fixed a tiny grammatical problem in a comment.
4. Added a new function "calc_reserved" to calculate the reserved
log space. This isn't entirely necessary, but it has two benefits:
First, it simplifies the gfs2_log_refund function greatly.
Second, it allows for easier debugging because I could sprinkle the
code with calls to this function to make sure the accounting is
proper (by adding asserts and printks) at strategic point of the code.
5. In log_pull_tail there apparently was a kludge to fix up the
accounting based on a "pull" parameter. The buffer accounting is
now done properly, so the kludge was removed.
6. File sync operations were making a call to gfs2_log_flush that
writes another journal header. Since that header was unplanned
for (reserved) by the reserve/refund sequence, the free space had
to be decremented so that when log_pull_tail gets called, the free
space is be adjusted properly. (Did I hear you call that a kludge?
well, maybe, but a lot more justifiable than the one I removed).
7. In the gfs2_log_shutdown code, it optionally syncs the log by
specifying the PULL parameter to log_write_header. I'm not sure
this is necessary anymore. It just seems to me there could be
cases where shutdown is called while there are outstanding log
buffers.
8. In the (data)buf_lo_before_commit functions, I changed some offset
values from being calculated on the fly to being constants. That
simplified some code and we might as well let the compiler do the
calculation once rather than redoing those cycles at run time.
9. This version has my rewritten databuf_lo_add function.
This version is much more like its predecessor, buf_lo_add, which
makes it easier to understand. Again, this might not be necessary,
but it seems as if this one works as well as the previous one,
maybe even better, so I decided to leave it in.
10. In databuf_lo_before_commit, a previous data corruption problem
was caused by going off the end of the buffer. The proper solution
is to have the proper limit in place, rather than stopping earlier.
(Thus my previous attempt to fix it is wrong).
If you don't wrap the buffer, you're stopping too early and that
causes more log buffer accounting problems.
11. In lops.h there are two new (previously mentioned) constants for
figuring out the data offset for the journal buffers.
12. There are also two new functions, buf_limit and databuf_limit to
calculate how many entries will fit in the buffer.
13. In function gfs2_meta_wipe, it needs to distinguish between pinned
metadata buffers and journaled data buffers for proper journal buffer
accounting. It can't use the JDATA gfs2_inode flag because it's
sometimes passed the "real" inode and sometimes the "metadata
inode" and the inode flags will be random bits in a metadata
gfs2_inode. It needs to base its decision on which was passed in.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2007-06-18 23:50:20 +04:00
reserved = calc_reserved ( sdp ) ;
2014-02-22 01:55:33 +04:00
maxres = sdp - > sd_log_blks_reserved + tr - > tr_reserved ;
gfs2_assert_withdraw ( sdp , maxres > = reserved ) ;
unused = maxres - reserved ;
2020-12-13 13:37:17 +03:00
if ( unused )
gfs2_log_release ( sdp , unused ) ;
2006-01-16 19:50:04 +03:00
sdp - > sd_log_blks_reserved = reserved ;
gfs2_log_unlock ( sdp ) ;
}
/**
* gfs2_log_commit - Commit a transaction to the log
* @ sdp : the filesystem
* @ tr : the transaction
*
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
* We wake up gfs2_logd if the number of pinned blocks exceed thresh1
* or the total number of used blocks ( pinned blocks plus AIL blocks )
* is greater than thresh2 .
*
2020-07-22 18:19:52 +03:00
* At mount time thresh1 is 2 / 5 ths of journal size , thresh2 is 4 / 5 ths of
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
* journal size .
*
2006-01-16 19:50:04 +03:00
* Returns : errno
*/
void gfs2_log_commit ( struct gfs2_sbd * sdp , struct gfs2_trans * tr )
{
log_refund ( sdp , tr ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
if ( atomic_read ( & sdp - > sd_log_pinned ) > atomic_read ( & sdp - > sd_log_thresh1 ) | |
( ( sdp - > sd_jdesc - > jd_blocks - atomic_read ( & sdp - > sd_log_blks_free ) ) >
atomic_read ( & sdp - > sd_log_thresh2 ) ) )
wake_up ( & sdp - > sd_logd_waitq ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_log_shutdown - write a shutdown header into a journal
* @ sdp : the filesystem
*
*/
2019-11-14 17:48:26 +03:00
static void gfs2_log_shutdown ( struct gfs2_sbd * sdp )
2006-01-16 19:50:04 +03:00
{
gfs2_assert_withdraw ( sdp , ! sdp - > sd_log_blks_reserved ) ;
gfs2_assert_withdraw ( sdp , ! sdp - > sd_log_num_revoke ) ;
gfs2_assert_withdraw ( sdp , list_empty ( & sdp - > sd_ail1_list ) ) ;
2018-01-08 18:34:17 +03:00
log_write_header ( sdp , GFS2_LOG_HEAD_UNMOUNT | GFS2_LFC_SHUTDOWN ) ;
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
log_pull_tail ( sdp ) ;
2006-01-16 19:50:04 +03:00
2006-04-21 23:10:46 +04:00
gfs2_assert_warn ( sdp , sdp - > sd_log_head = = sdp - > sd_log_tail ) ;
gfs2_assert_warn ( sdp , list_empty ( & sdp - > sd_ail2_list ) ) ;
2006-11-23 19:06:35 +03:00
}
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
static inline int gfs2_jrnl_flush_reqd ( struct gfs2_sbd * sdp )
{
2017-01-06 00:01:45 +03:00
return ( atomic_read ( & sdp - > sd_log_pinned ) +
atomic_read ( & sdp - > sd_log_blks_needed ) > =
atomic_read ( & sdp - > sd_log_thresh1 ) ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
}
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 ) ;
2017-08-04 20:15:32 +03:00
if ( test_and_clear_bit ( SDF_FORCE_AIL_FLUSH , & sdp - > sd_flags ) )
return 1 ;
2017-01-06 00:01:45 +03:00
return used_blocks + atomic_read ( & sdp - > sd_log_blks_needed ) > =
atomic_read ( & sdp - > sd_log_thresh2 ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
}
2007-11-09 13:01:41 +03:00
/**
* gfs2_logd - Update log tail as Active Items get flushed to in - place blocks
2021-03-30 19:44:29 +03:00
* @ data : Pointer to GFS2 superblock
2007-11-09 13:01:41 +03:00
*
* Also , periodically check to make sure that we ' re using the most recent
* journal index .
*/
int gfs2_logd ( void * data )
{
struct gfs2_sbd * sdp = data ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
unsigned long t = 1 ;
DEFINE_WAIT ( wait ) ;
2007-11-09 13:01:41 +03:00
while ( ! kthread_should_stop ( ) ) {
2020-04-24 20:17:33 +03:00
if ( gfs2_withdrawn ( sdp ) ) {
msleep_interruptible ( HZ ) ;
continue ;
}
GFS2: Withdraw for IO errors writing to the journal or statfs
Before this patch, if GFS2 encountered IO errors while writing to
the journal, it would not report the problem, so they would go
unnoticed, sometimes for many hours. Sometimes this would only be
noticed later, when recovery tried to do journal replay and failed
due to invalid metadata at the blocks that resulted in IO errors.
This patch makes GFS2's log daemon check for IO errors. If it
encounters one, it withdraws from the file system and reports
why in dmesg. A similar action is taken when IO errors occur when
writing to the system statfs file.
These errors are also reported back to any callers of fsync, since
that requires the journal to be flushed. Therefore, any IO errors
that would previously go unnoticed are now noticed and the file
system is withdrawn as early as possible, thus preventing further
file system damage.
Also note that this reintroduces superblock variable sd_log_error,
which Christoph removed with commit f729b66fca.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2017-08-16 19:30:06 +03:00
/* Check for errors writing to the journal */
if ( sdp - > sd_log_error ) {
2020-01-23 20:41:00 +03:00
gfs2_lm ( sdp ,
" GFS2: fsid=%s: error %d: "
" withdrawing the file system to "
" prevent further damage. \n " ,
sdp - > sd_fsname , sdp - > sd_log_error ) ;
gfs2_withdraw ( sdp ) ;
2020-04-24 20:17:33 +03:00
continue ;
GFS2: Withdraw for IO errors writing to the journal or statfs
Before this patch, if GFS2 encountered IO errors while writing to
the journal, it would not report the problem, so they would go
unnoticed, sometimes for many hours. Sometimes this would only be
noticed later, when recovery tried to do journal replay and failed
due to invalid metadata at the blocks that resulted in IO errors.
This patch makes GFS2's log daemon check for IO errors. If it
encounters one, it withdraws from the file system and reports
why in dmesg. A similar action is taken when IO errors occur when
writing to the system statfs file.
These errors are also reported back to any callers of fsync, since
that requires the journal to be flushed. Therefore, any IO errors
that would previously go unnoticed are now noticed and the file
system is withdrawn as early as possible, thus preventing further
file system damage.
Also note that this reintroduces superblock variable sd_log_error,
which Christoph removed with commit f729b66fca.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
2017-08-16 19:30:06 +03:00
}
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
if ( gfs2_jrnl_flush_reqd ( sdp ) | | t = = 0 ) {
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
gfs2_ail1_empty ( sdp , 0 ) ;
2018-01-08 18:34:17 +03:00
gfs2_log_flush ( sdp , NULL , GFS2_LOG_HEAD_FLUSH_NORMAL |
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
GFS2_LFC_LOGD_JFLUSH_REQD ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
}
2007-11-09 13:01:41 +03:00
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
if ( gfs2_ail_flush_reqd ( sdp ) ) {
gfs2_ail1_start ( sdp ) ;
2011-05-21 22:21:07 +04:00
gfs2_ail1_wait ( sdp ) ;
gfs2: Issue revokes more intelligently
Before this patch, function gfs2_write_revokes would call
gfs2_ail1_empty, then traverse the sd_ail1_list looking for
transactions that had bds which were no longer queued to a glock.
And if it found some, it would try to issue revokes for them, up to
a predetermined maximum. There were two problems with how it did
this. First was the fact that gfs2_ail1_empty moves transactions
which have nothing remaining on the ail1 list from the sd_ail1_list
to the sd_ail2_list, thus making its traversal of sd_ail1_list
miss them completely, and therefore, never issue revokes for them.
Second was the fact that there were three traversals (or partial
traversals) of the sd_ail1_list, each of which took and then
released the sd_ail_lock lock: First inside gfs2_ail1_empty,
second to determine if there are any revokes to be issued, and
third to actually issue them. All this taking and releasing of the
sd_ail_lock meant other processes could modify the lists and the
conditions in which we're working.
This patch simplies the whole process by adding a new parameter
to function gfs2_ail1_empty, max_revokes. For normal calls, this
is passed in as 0, meaning we don't want to issue any revokes.
For function gfs2_write_revokes, we pass in the maximum number
of revokes we can, thus allowing gfs2_ail1_empty to add the
revokes where needed. This simplies the code, allows for a single
holding of the sd_ail_lock, and allows gfs2_ail1_empty to add
revokes for all the necessary bd items without missing any.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Reviewed-by: Andreas Gruenbacher <agruenba@redhat.com>
2019-02-22 00:28:07 +03:00
gfs2_ail1_empty ( sdp , 0 ) ;
2018-01-08 18:34:17 +03:00
gfs2_log_flush ( sdp , NULL , GFS2_LOG_HEAD_FLUSH_NORMAL |
gfs2: Rework the log space allocation logic
The current log space allocation logic is hard to understand or extend.
The principle it that when the log is flushed, we may or may not have a
transaction active that has space allocated in the log. To deal with
that, we set aside a magical number of blocks to be used in case we
don't have an active transaction. It isn't clear that the pool will
always be big enough. In addition, we can't return unused log space at
the end of a transaction, so the number of blocks allocated must exactly
match the number of blocks used.
Simplify this as follows:
* When transactions are allocated or merged, always reserve enough
blocks to flush the transaction (err on the safe side).
* In gfs2_log_flush, return any allocated blocks that haven't been used.
* Maintain a pool of spare blocks big enough to do one log flush, as
before.
* In gfs2_log_flush, when we have no active transaction, allocate a
suitable number of blocks. For that, use the spare pool when
called from logd, and leave the pool alone otherwise. This means
that when the log is almost full, logd will still be able to do one
more log flush, which will result in more log space becoming
available.
This will make the log space allocator code easier to work with in
the future.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2020-12-10 14:49:56 +03:00
GFS2_LFC_LOGD_AIL_FLUSH_REQD ) ;
2007-11-09 13:01:41 +03:00
}
t = gfs2_tune_get ( sdp , gt_logd_secs ) * HZ ;
2011-11-22 00:32:22 +04:00
try_to_freeze ( ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
do {
prepare_to_wait ( & sdp - > sd_logd_waitq , & wait ,
2010-09-09 17:45:00 +04:00
TASK_INTERRUPTIBLE ) ;
GFS2: Various gfs2_logd improvements
This patch contains various tweaks to how log flushes and active item writeback
work. gfs2_logd is now managed by a waitqueue, and gfs2_log_reseve now waits
for gfs2_logd to do the log flushing. Multiple functions were rewritten to
remove the need to call gfs2_log_lock(). Instead of using one test to see if
gfs2_logd had work to do, there are now seperate tests to check if there
are two many buffers in the incore log or if there are two many items on the
active items list.
This patch is a port of a patch Steve Whitehouse wrote about a year ago, with
some minor changes. Since gfs2_ail1_start always submits all the active items,
it no longer needs to keep track of the first ai submitted, so this has been
removed. In gfs2_log_reserve(), the order of the calls to
prepare_to_wait_exclusive() and wake_up() when firing off the logd thread has
been switched. If it called wake_up first there was a small window for a race,
where logd could run and return before gfs2_log_reserve was ready to get woken
up. If gfs2_logd ran, but did not free up enough blocks, gfs2_log_reserve()
would be left waiting for gfs2_logd to eventualy run because it timed out.
Finally, gt_logd_secs, which controls how long to wait before gfs2_logd times
out, and flushes the log, can now be set on mount with ar_commit.
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2010-05-04 23:29:16 +04:00
if ( ! gfs2_ail_flush_reqd ( sdp ) & &
! gfs2_jrnl_flush_reqd ( sdp ) & &
! kthread_should_stop ( ) )
t = schedule_timeout ( t ) ;
} while ( t & & ! gfs2_ail_flush_reqd ( sdp ) & &
! gfs2_jrnl_flush_reqd ( sdp ) & &
! kthread_should_stop ( ) ) ;
finish_wait ( & sdp - > sd_logd_waitq , & wait ) ;
2007-11-09 13:01:41 +03:00
}
return 0 ;
}