Various gfs2 fixes
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmC0vkAUHGFncnVlbmJh QHJlZGhhdC5jb20ACgkQ1b+f6wMTZTqCGQ/+JiCdfHQao3/W9KsIeA5YO5fbsQXi tElY61L4eM7F+gEe1mbMzr8sefbejv73aAMGWJJD06gLPz/wIPeW/fYnC4/gcQEn +jLjVb7taGaxOn0fioCqjU+esGW4wstYrAXLp6XZmLnMETmr7PCbOhohRG7sK1TX m8si6riMOiNw20MOHhUK9DFZ3rF4Q5Rp/vYaTDwoGpcORIv5bpPoQKYT1FMCTD9h 5qI6ldOO2E4d9qXQXiCv2RqXElYqQxwxqvGP0Hj+HQLZQBCmJJYZNDqRwDunJTaN K9++1/XbTCFKEQz0UWz1x1k5fCDIewbzxX348aQjiLMkkpXr885AGhasAX8gRS3p D7Y4q6VCY3J5JzlCDfNWrTBd0abLJAjeJ70R71/kN/hgIY2PbU/CaPcyhUrp7rwH B6spZDXb2fBNdfYA5wmuUdSA9BRmw/MDpiGd9aQc5nv25YvZ5Apl9X4QSH2250vo MKTrlt90EyTmOgF6vRf28apVr41JO3PIXgMu+svZq769Ox2jSZJQT0UI4vzVThoP RGBsTDPtDL67OvNoC6H7Poc7ad+BRqtFxkwNCz7kkcwQlYkmVPUf49UC/pBnBV3M HtlkJdlhD7VEWqUPl3T02rTdLRXLuPIGw9Kk6gKiDCikONoD+icJ3fV7rWShMjhD O/KT/r3XM1V1sP8= =vV+Y -----END PGP SIGNATURE----- Merge tag 'gfs2-v5.13-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2 Pull gfs2 fixes from Andreas Gruenbacher: "Various gfs2 fixes" * tag 'gfs2-v5.13-rc2-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: Fix use-after-free in gfs2_glock_shrink_scan gfs2: Fix mmap locking for write faults gfs2: Clean up revokes on normal withdraws gfs2: fix a deadlock on withdraw-during-mount gfs2: fix scheduling while atomic bug in glocks gfs2: Fix I_NEW check in gfs2_dinode_in gfs2: Prevent direct-I/O write fallback errors from getting lost
This commit is contained in:
Коммит
c2131f7e73
|
@ -540,9 +540,11 @@ static vm_fault_t gfs2_fault(struct vm_fault *vmf)
|
|||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
struct gfs2_holder gh;
|
||||
vm_fault_t ret;
|
||||
u16 state;
|
||||
int err;
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||
state = (vmf->flags & FAULT_FLAG_WRITE) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
|
||||
gfs2_holder_init(ip->i_gl, state, 0, &gh);
|
||||
err = gfs2_glock_nq(&gh);
|
||||
if (err) {
|
||||
ret = block_page_mkwrite_return(err);
|
||||
|
@ -911,8 +913,11 @@ static ssize_t gfs2_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
current->backing_dev_info = inode_to_bdi(inode);
|
||||
buffered = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops);
|
||||
current->backing_dev_info = NULL;
|
||||
if (unlikely(buffered <= 0))
|
||||
if (unlikely(buffered <= 0)) {
|
||||
if (!ret)
|
||||
ret = buffered;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to ensure that the page cache pages are written to
|
||||
|
|
|
@ -582,6 +582,16 @@ out_locked:
|
|||
spin_unlock(&gl->gl_lockref.lock);
|
||||
}
|
||||
|
||||
static bool is_system_glock(struct gfs2_glock *gl)
|
||||
{
|
||||
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
|
||||
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
|
||||
|
||||
if (gl == m_ip->i_gl)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_xmote - Calls the DLM to change the state of a lock
|
||||
* @gl: The lock state
|
||||
|
@ -671,17 +681,25 @@ skip_inval:
|
|||
* to see sd_log_error and withdraw, and in the meantime, requeue the
|
||||
* work for later.
|
||||
*
|
||||
* We make a special exception for some system glocks, such as the
|
||||
* system statfs inode glock, which needs to be granted before the
|
||||
* gfs2_quotad daemon can exit, and that exit needs to finish before
|
||||
* we can unmount the withdrawn file system.
|
||||
*
|
||||
* However, if we're just unlocking the lock (say, for unmount, when
|
||||
* gfs2_gl_hash_clear calls clear_glock) and recovery is complete
|
||||
* then it's okay to tell dlm to unlock it.
|
||||
*/
|
||||
if (unlikely(sdp->sd_log_error && !gfs2_withdrawn(sdp)))
|
||||
gfs2_withdraw_delayed(sdp);
|
||||
if (glock_blocked_by_withdraw(gl)) {
|
||||
if (target != LM_ST_UNLOCKED ||
|
||||
test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags)) {
|
||||
if (glock_blocked_by_withdraw(gl) &&
|
||||
(target != LM_ST_UNLOCKED ||
|
||||
test_bit(SDF_WITHDRAW_RECOVERY, &sdp->sd_flags))) {
|
||||
if (!is_system_glock(gl)) {
|
||||
gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
|
||||
goto out;
|
||||
} else {
|
||||
clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1466,9 +1484,11 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
|
|||
glock_blocked_by_withdraw(gl) &&
|
||||
gh->gh_gl != sdp->sd_jinode_gl) {
|
||||
sdp->sd_glock_dqs_held++;
|
||||
spin_unlock(&gl->gl_lockref.lock);
|
||||
might_sleep();
|
||||
wait_on_bit(&sdp->sd_flags, SDF_WITHDRAW_RECOVERY,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
spin_lock(&gl->gl_lockref.lock);
|
||||
}
|
||||
if (gh->gh_flags & GL_NOCACHE)
|
||||
handle_callback(gl, LM_ST_UNLOCKED, 0, false);
|
||||
|
@ -1775,6 +1795,7 @@ __acquires(&lru_lock)
|
|||
while(!list_empty(list)) {
|
||||
gl = list_first_entry(list, struct gfs2_glock, gl_lru);
|
||||
list_del_init(&gl->gl_lru);
|
||||
clear_bit(GLF_LRU, &gl->gl_flags);
|
||||
if (!spin_trylock(&gl->gl_lockref.lock)) {
|
||||
add_back_to_lru:
|
||||
list_add(&gl->gl_lru, &lru_list);
|
||||
|
@ -1820,7 +1841,6 @@ static long gfs2_scan_glock_lru(int nr)
|
|||
if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
|
||||
list_move(&gl->gl_lru, &dispose);
|
||||
atomic_dec(&lru_count);
|
||||
clear_bit(GLF_LRU, &gl->gl_flags);
|
||||
freed++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -396,7 +396,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
|
|||
struct timespec64 atime;
|
||||
u16 height, depth;
|
||||
umode_t mode = be32_to_cpu(str->di_mode);
|
||||
bool is_new = ip->i_inode.i_flags & I_NEW;
|
||||
bool is_new = ip->i_inode.i_state & I_NEW;
|
||||
|
||||
if (unlikely(ip->i_no_addr != be64_to_cpu(str->di_num.no_addr)))
|
||||
goto corrupt;
|
||||
|
|
|
@ -926,10 +926,10 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
|
|||
}
|
||||
|
||||
/**
|
||||
* ail_drain - drain the ail lists after a withdraw
|
||||
* gfs2_ail_drain - drain the ail lists after a withdraw
|
||||
* @sdp: Pointer to GFS2 superblock
|
||||
*/
|
||||
static void ail_drain(struct gfs2_sbd *sdp)
|
||||
void gfs2_ail_drain(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct gfs2_trans *tr;
|
||||
|
||||
|
@ -956,6 +956,7 @@ static void ail_drain(struct gfs2_sbd *sdp)
|
|||
list_del(&tr->tr_list);
|
||||
gfs2_trans_free(sdp, tr);
|
||||
}
|
||||
gfs2_drain_revokes(sdp);
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
}
|
||||
|
||||
|
@ -1162,7 +1163,6 @@ out_withdraw:
|
|||
if (tr && list_empty(&tr->tr_list))
|
||||
list_add(&tr->tr_list, &sdp->sd_ail1_list);
|
||||
spin_unlock(&sdp->sd_ail_lock);
|
||||
ail_drain(sdp); /* frees all transactions */
|
||||
tr = NULL;
|
||||
goto out_end;
|
||||
}
|
||||
|
|
|
@ -93,5 +93,6 @@ extern int gfs2_logd(void *data);
|
|||
extern void gfs2_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
|
||||
extern void gfs2_glock_remove_revoke(struct gfs2_glock *gl);
|
||||
extern void gfs2_flush_revokes(struct gfs2_sbd *sdp);
|
||||
extern void gfs2_ail_drain(struct gfs2_sbd *sdp);
|
||||
|
||||
#endif /* __LOG_DOT_H__ */
|
||||
|
|
|
@ -885,7 +885,7 @@ static void revoke_lo_before_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
|||
gfs2_log_write_page(sdp, page);
|
||||
}
|
||||
|
||||
static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
void gfs2_drain_revokes(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct list_head *head = &sdp->sd_log_revokes;
|
||||
struct gfs2_bufdata *bd;
|
||||
|
@ -900,6 +900,11 @@ static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
|||
}
|
||||
}
|
||||
|
||||
static void revoke_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
|
||||
{
|
||||
gfs2_drain_revokes(sdp);
|
||||
}
|
||||
|
||||
static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
|
||||
struct gfs2_log_header_host *head, int pass)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ extern void gfs2_log_submit_bio(struct bio **biop, int opf);
|
|||
extern void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
|
||||
extern int gfs2_find_jhead(struct gfs2_jdesc *jd,
|
||||
struct gfs2_log_header_host *head, bool keep_cache);
|
||||
extern void gfs2_drain_revokes(struct gfs2_sbd *sdp);
|
||||
static inline unsigned int buf_limit(struct gfs2_sbd *sdp)
|
||||
{
|
||||
return sdp->sd_ldptrs;
|
||||
|
|
|
@ -131,6 +131,7 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
|
|||
if (test_bit(SDF_NORECOVERY, &sdp->sd_flags) || !sdp->sd_jdesc)
|
||||
return;
|
||||
|
||||
gfs2_ail_drain(sdp); /* frees all transactions */
|
||||
inode = sdp->sd_jdesc->jd_inode;
|
||||
ip = GFS2_I(inode);
|
||||
i_gl = ip->i_gl;
|
||||
|
|
Загрузка…
Ссылка в новой задаче