Skip to content

Commit

Permalink
Merge tag 'gfs2-v6.4-rc5-fixes' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/gfs2/linux-gfs2

Pull gfs2 updates from Andreas Gruenbacher:

 - Move the freeze/thaw logic from glock callback context to process /
   worker thread context to prevent deadlocks

 - Fix a quota reference couting bug in do_qc()

 - Carry on deallocating inodes even when gfs2_rindex_update() fails

 - Retry filesystem-internal reads when they are interruped by a signal

 - Eliminate kmap_atomic() in favor of kmap_local_page() /
   memcpy_{from,to}_page()

 - Get rid of noop_direct_IO

 - And a few more minor fixes and cleanups

* tag 'gfs2-v6.4-rc5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (23 commits)
  gfs2: Add quota_change type
  gfs2: Use memcpy_{from,to}_page where appropriate
  gfs2: Convert remaining kmap_atomic calls to kmap_local_page
  gfs2: Replace deprecated kmap_atomic with kmap_local_page
  gfs: Get rid of unnucessary locking in inode_go_dump
  gfs2: gfs2_freeze_lock_shared cleanup
  gfs2: Replace sd_freeze_state with SDF_FROZEN flag
  gfs2: Rework freeze / thaw logic
  gfs2: Rename SDF_{FS_FROZEN => FREEZE_INITIATOR}
  gfs2: Reconfiguring frozen filesystem already rejected
  gfs2: Rename gfs2_freeze_lock{ => _shared }
  gfs2: Rename the {freeze,thaw}_super callbacks
  gfs2: Rename remaining "transaction" glock references
  gfs2: retry interrupted internal reads
  gfs2: Fix possible data races in gfs2_show_options()
  gfs2: Fix duplicate should_fault_in_pages() call
  gfs2: set FMODE_CAN_ODIRECT instead of a dummy direct_IO method
  gfs2: Don't remember delete unless it's successful
  gfs2: Update rl_unlinked before releasing rgrp lock
  gfs2: Fix gfs2_qa_get imbalance in gfs2_quota_hold
  ...
  • Loading branch information
Linus Torvalds committed Jul 4, 2023
2 parents ccf46d8 + 432928c commit 94c7695
Show file tree
Hide file tree
Showing 19 changed files with 277 additions and 237 deletions.
19 changes: 9 additions & 10 deletions fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,10 +432,10 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
if (error)
return error;

kaddr = kmap_atomic(page);
kaddr = kmap_local_page(page);
memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
kunmap_atomic(kaddr);
kunmap_local(kaddr);
flush_dcache_page(page);
brelse(dibh);
SetPageUptodate(page);
Expand Down Expand Up @@ -489,18 +489,18 @@ int gfs2_internal_read(struct gfs2_inode *ip, char *buf, loff_t *pos,
unsigned copied = 0;
unsigned amt;
struct page *page;
void *p;

do {
page = read_cache_page(mapping, index, gfs2_read_folio, NULL);
if (IS_ERR(page)) {
if (PTR_ERR(page) == -EINTR)
continue;
return PTR_ERR(page);
}
amt = size - copied;
if (offset + size > PAGE_SIZE)
amt = PAGE_SIZE - offset;
page = read_cache_page(mapping, index, gfs2_read_folio, NULL);
if (IS_ERR(page))
return PTR_ERR(page);
p = kmap_atomic(page);
memcpy(buf + copied, p + offset, amt);
kunmap_atomic(p);
memcpy_from_page(buf + copied, page, offset, amt);
put_page(page);
copied += amt;
index++;
Expand Down Expand Up @@ -751,7 +751,6 @@ static const struct address_space_operations gfs2_aops = {
.release_folio = iomap_release_folio,
.invalidate_folio = iomap_invalidate_folio,
.bmap = gfs2_bmap,
.direct_IO = noop_direct_IO,
.migrate_folio = filemap_migrate_folio,
.is_partially_uptodate = iomap_is_partially_uptodate,
.error_remove_page = generic_error_remove_page,
Expand Down
4 changes: 2 additions & 2 deletions fs/gfs2/bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1729,8 +1729,8 @@ static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length)

if (offset >= maxsize) {
/*
* The starting point lies beyond the allocated meta-data;
* there are no blocks do deallocate.
* The starting point lies beyond the allocated metadata;
* there are no blocks to deallocate.
*/
return 0;
}
Expand Down
5 changes: 4 additions & 1 deletion fs/gfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,9 @@ int gfs2_open_common(struct inode *inode, struct file *file)
ret = generic_file_open(inode, file);
if (ret)
return ret;

if (!gfs2_is_jdata(GFS2_I(inode)))
file->f_mode |= FMODE_CAN_ODIRECT;
}

fp = kzalloc(sizeof(struct gfs2_file), GFP_NOFS);
Expand Down Expand Up @@ -1030,8 +1033,8 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
}

gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, gh);
retry:
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
retry:
window_size -= fault_in_iov_iter_readable(from, window_size);
if (!window_size) {
ret = -EFAULT;
Expand Down
4 changes: 2 additions & 2 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu)
*
* We need to allow some glocks to be enqueued, dequeued, promoted, and demoted
* when we're withdrawn. For example, to maintain metadata integrity, we should
* disallow the use of inode and rgrp glocks when withdrawn. Other glocks, like
* iopen or the transaction glocks may be safely used because none of their
* disallow the use of inode and rgrp glocks when withdrawn. Other glocks like
* the iopen or freeze glock may be safely used because none of their
* metadata goes through the journal. So in general, we should disallow all
* glocks that are journaled, and allow all the others. One exception is:
* we need to allow our active journal to be promoted and demoted so others
Expand Down
69 changes: 25 additions & 44 deletions fs/gfs2/glops.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static void rgrp_go_inval(struct gfs2_glock *gl, int flags)
truncate_inode_pages_range(mapping, start, end);
}

static void gfs2_rgrp_go_dump(struct seq_file *seq, struct gfs2_glock *gl,
static void gfs2_rgrp_go_dump(struct seq_file *seq, const struct gfs2_glock *gl,
const char *fs_id_buf)
{
struct gfs2_rgrpd *rgd = gl->gl_object;
Expand Down Expand Up @@ -536,72 +536,53 @@ static int inode_go_held(struct gfs2_holder *gh)
*
*/

static void inode_go_dump(struct seq_file *seq, struct gfs2_glock *gl,
static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl,
const char *fs_id_buf)
{
struct gfs2_inode *ip = gl->gl_object;
struct inode *inode;
unsigned long nrpages;
const struct inode *inode = &ip->i_inode;

if (ip == NULL)
return;

inode = &ip->i_inode;
xa_lock_irq(&inode->i_data.i_pages);
nrpages = inode->i_data.nrpages;
xa_unlock_irq(&inode->i_data.i_pages);

gfs2_print_dbg(seq, "%s I: n:%llu/%llu t:%u f:0x%02lx d:0x%08x s:%llu "
"p:%lu\n", fs_id_buf,
(unsigned long long)ip->i_no_formal_ino,
(unsigned long long)ip->i_no_addr,
IF2DT(ip->i_inode.i_mode), ip->i_flags,
IF2DT(inode->i_mode), ip->i_flags,
(unsigned int)ip->i_diskflags,
(unsigned long long)i_size_read(inode), nrpages);
(unsigned long long)i_size_read(inode),
inode->i_data.nrpages);
}

/**
* freeze_go_sync - promote/demote the freeze glock
* freeze_go_callback - A cluster node is requesting a freeze
* @gl: the glock
* @remote: true if this came from a different cluster node
*/

static int freeze_go_sync(struct gfs2_glock *gl)
static void freeze_go_callback(struct gfs2_glock *gl, bool remote)
{
int error = 0;
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct super_block *sb = sdp->sd_vfs;

if (!remote ||
gl->gl_state != LM_ST_SHARED ||
gl->gl_demote_state != LM_ST_UNLOCKED)
return;

/*
* We need to check gl_state == LM_ST_SHARED here and not gl_req ==
* LM_ST_EXCLUSIVE. That's because when any node does a freeze,
* all the nodes should have the freeze glock in SH mode and they all
* call do_xmote: One for EX and the others for UN. They ALL must
* freeze locally, and they ALL must queue freeze work. The freeze_work
* calls freeze_func, which tries to reacquire the freeze glock in SH,
* effectively waiting for the thaw on the node who holds it in EX.
* Once thawed, the work func acquires the freeze glock in
* SH and everybody goes back to thawed.
* Try to get an active super block reference to prevent racing with
* unmount (see trylock_super()). But note that unmount isn't the only
* place where a write lock on s_umount is taken, and we can fail here
* because of things like remount as well.
*/
if (gl->gl_state == LM_ST_SHARED && !gfs2_withdrawn(sdp) &&
!test_bit(SDF_NORECOVERY, &sdp->sd_flags)) {
atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE);
error = freeze_super(sdp->sd_vfs);
if (error) {
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
error);
if (gfs2_withdrawn(sdp)) {
atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
return 0;
}
gfs2_assert_withdraw(sdp, 0);
}
queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work);
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
GFS2_LFC_FREEZE_GO_SYNC);
else /* read-only mounts */
atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
if (down_read_trylock(&sb->s_umount)) {
atomic_inc(&sb->s_active);
up_read(&sb->s_umount);
if (!queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work))
deactivate_super(sb);
}
return 0;
}

/**
Expand Down Expand Up @@ -761,9 +742,9 @@ const struct gfs2_glock_operations gfs2_rgrp_glops = {
};

const struct gfs2_glock_operations gfs2_freeze_glops = {
.go_sync = freeze_go_sync,
.go_xmote_bh = freeze_go_xmote_bh,
.go_demote_ok = freeze_go_demote_ok,
.go_callback = freeze_go_callback,
.go_type = LM_TYPE_NONDISK,
.go_flags = GLOF_NONDISK,
};
Expand Down
12 changes: 3 additions & 9 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ struct gfs2_glock_operations {
int (*go_demote_ok) (const struct gfs2_glock *gl);
int (*go_instantiate) (struct gfs2_glock *gl);
int (*go_held)(struct gfs2_holder *gh);
void (*go_dump)(struct seq_file *seq, struct gfs2_glock *gl,
void (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl,
const char *fs_id_buf);
void (*go_callback)(struct gfs2_glock *gl, bool remote);
void (*go_free)(struct gfs2_glock *gl);
Expand Down Expand Up @@ -600,20 +600,15 @@ enum {
SDF_RORECOVERY = 7, /* read only recovery */
SDF_SKIP_DLM_UNLOCK = 8,
SDF_FORCE_AIL_FLUSH = 9,
SDF_FS_FROZEN = 10,
SDF_FREEZE_INITIATOR = 10,
SDF_WITHDRAWING = 11, /* Will withdraw eventually */
SDF_WITHDRAW_IN_PROG = 12, /* Withdraw is in progress */
SDF_REMOTE_WITHDRAW = 13, /* Performing remote recovery */
SDF_WITHDRAW_RECOVERY = 14, /* Wait for journal recovery when we are
withdrawing */
SDF_DEACTIVATING = 15,
SDF_EVICTING = 16,
};

enum gfs2_freeze_state {
SFS_UNFROZEN = 0,
SFS_STARTING_FREEZE = 1,
SFS_FROZEN = 2,
SDF_FROZEN = 17,
};

#define GFS2_FSNAME_LEN 256
Expand Down Expand Up @@ -841,7 +836,6 @@ struct gfs2_sbd {

/* For quiescing the filesystem */
struct gfs2_holder sd_freeze_gh;
atomic_t sd_freeze_state;
struct mutex sd_freeze_mutex;

char sd_fsname[GFS2_FSNAME_LEN + 3 * sizeof(int) + 2];
Expand Down
23 changes: 10 additions & 13 deletions fs/gfs2/lock_dlm.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,28 +296,22 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
struct lm_lockstruct *ls = &sdp->sd_lockstruct;
int error;

if (gl->gl_lksb.sb_lkid == 0) {
gfs2_glock_free(gl);
return;
}
if (gl->gl_lksb.sb_lkid == 0)
goto out_free;

clear_bit(GLF_BLOCKING, &gl->gl_flags);
gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
gfs2_update_request_times(gl);

/* don't want to call dlm if we've unmounted the lock protocol */
if (test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) {
gfs2_glock_free(gl);
return;
}
if (test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
goto out_free;
/* don't want to skip dlm_unlock writing the lvb when lock has one */

if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) &&
!gl->gl_lksb.sb_lvbptr) {
gfs2_glock_free(gl);
return;
}
!gl->gl_lksb.sb_lvbptr)
goto out_free;

again:
error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
Expand All @@ -331,8 +325,11 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
gl->gl_name.ln_type,
(unsigned long long)gl->gl_name.ln_number, error);
return;
}
return;

out_free:
gfs2_glock_free(gl);
}

static void gdlm_cancel(struct gfs2_glock *gl)
Expand Down
11 changes: 4 additions & 7 deletions fs/gfs2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,9 +914,8 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
{
blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC;
enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);

gfs2_assert_withdraw(sdp, (state != SFS_FROZEN));
gfs2_assert_withdraw(sdp, !test_bit(SDF_FROZEN, &sdp->sd_flags));

if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
gfs2_ordered_wait(sdp);
Expand Down Expand Up @@ -1036,7 +1035,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
{
struct gfs2_trans *tr = NULL;
unsigned int reserved_blocks = 0, used_blocks = 0;
enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
bool frozen = test_bit(SDF_FROZEN, &sdp->sd_flags);
unsigned int first_log_head;
unsigned int reserved_revokes = 0;

Expand Down Expand Up @@ -1067,7 +1066,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (tr) {
sdp->sd_log_tr = NULL;
tr->tr_first = first_log_head;
if (unlikely (state == SFS_FROZEN)) {
if (unlikely(frozen)) {
if (gfs2_assert_withdraw_delayed(sdp,
!tr->tr_num_buf_new && !tr->tr_num_databuf_new))
goto out_withdraw;
Expand All @@ -1092,7 +1091,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (flags & GFS2_LOG_HEAD_FLUSH_SHUTDOWN)
clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);

if (unlikely(state == SFS_FROZEN))
if (unlikely(frozen))
if (gfs2_assert_withdraw_delayed(sdp, !reserved_revokes))
goto out_withdraw;

Expand Down Expand Up @@ -1136,8 +1135,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl, u32 flags)
if (flags & (GFS2_LOG_HEAD_FLUSH_SHUTDOWN |
GFS2_LOG_HEAD_FLUSH_FREEZE))
gfs2_log_shutdown(sdp);
if (flags & GFS2_LOG_HEAD_FLUSH_FREEZE)
atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
}

out_end:
Expand Down
21 changes: 10 additions & 11 deletions fs/gfs2/lops.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,11 @@ static bool gfs2_jhead_pg_srch(struct gfs2_jdesc *jd,
{
struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
struct gfs2_log_header_host lh;
void *kaddr = kmap_atomic(page);
void *kaddr;
unsigned int offset;
bool ret = false;

kaddr = kmap_local_page(page);
for (offset = 0; offset < PAGE_SIZE; offset += sdp->sd_sb.sb_bsize) {
if (!__get_log_header(sdp, kaddr + offset, 0, &lh)) {
if (lh.lh_sequence >= head->lh_sequence)
Expand All @@ -441,7 +442,7 @@ static bool gfs2_jhead_pg_srch(struct gfs2_jdesc *jd,
}
}
}
kunmap_atomic(kaddr);
kunmap_local(kaddr);
return ret;
}

Expand Down Expand Up @@ -626,11 +627,11 @@ static void gfs2_check_magic(struct buffer_head *bh)
__be32 *ptr;

clear_buffer_escaped(bh);
kaddr = kmap_atomic(bh->b_page);
kaddr = kmap_local_page(bh->b_page);
ptr = kaddr + bh_offset(bh);
if (*ptr == cpu_to_be32(GFS2_MAGIC))
set_buffer_escaped(bh);
kunmap_atomic(kaddr);
kunmap_local(kaddr);
}

static int blocknr_cmp(void *priv, const struct list_head *a,
Expand Down Expand Up @@ -696,14 +697,12 @@ static void gfs2_before_commit(struct gfs2_sbd *sdp, unsigned int limit,
lock_buffer(bd2->bd_bh);

if (buffer_escaped(bd2->bd_bh)) {
void *kaddr;
void *p;

page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
ptr = page_address(page);
kaddr = kmap_atomic(bd2->bd_bh->b_page);
memcpy(ptr, kaddr + bh_offset(bd2->bd_bh),
bd2->bd_bh->b_size);
kunmap_atomic(kaddr);
*(__be32 *)ptr = 0;
p = page_address(page);
memcpy_from_page(p, page, bh_offset(bd2->bd_bh), bd2->bd_bh->b_size);
*(__be32 *)p = 0;
clear_buffer_escaped(bd2->bd_bh);
unlock_buffer(bd2->bd_bh);
brelse(bd2->bd_bh);
Expand Down
Loading

0 comments on commit 94c7695

Please sign in to comment.