diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2022-08-05 18:37:03 +0200 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2022-08-05 18:37:03 +0200 |
commit | 446279168e030fd0ed68e2bba336bef8bb3da352 (patch) | |
tree | 0944d4dc64b07f74a6cf73d2ce803a789f8d786d /fs/gfs2 | |
parent | gfs2: Minor gfs2_glock_nq_m cleanup (diff) | |
parent | gfs2: List traversal in do_promote is safe (diff) | |
download | linux-446279168e030fd0ed68e2bba336bef8bb3da352.tar.xz linux-446279168e030fd0ed68e2bba336bef8bb3da352.zip |
Merge part of branch 'for-next.instantiate' into for-next
Diffstat (limited to 'fs/gfs2')
-rw-r--r-- | fs/gfs2/glock.c | 187 | ||||
-rw-r--r-- | fs/gfs2/glock.h | 2 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 31 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 6 | ||||
-rw-r--r-- | fs/gfs2/main.c | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 2 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 28 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 3 | ||||
-rw-r--r-- | fs/gfs2/rgrp.h | 2 | ||||
-rw-r--r-- | fs/gfs2/super.c | 2 |
10 files changed, 94 insertions, 170 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index e540d1290099..0b36a16659b6 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -405,10 +405,13 @@ static void do_error(struct gfs2_glock *gl, const int ret) /** * demote_incompat_holders - demote incompatible demoteable holders * @gl: the glock we want to promote - * @new_gh: the new holder to be promoted + * @current_gh: the newly promoted holder + * + * We're passing the newly promoted holder in @current_gh, but actually, any of + * the strong holders would do. */ static void demote_incompat_holders(struct gfs2_glock *gl, - struct gfs2_holder *new_gh) + struct gfs2_holder *current_gh) { struct gfs2_holder *gh, *tmp; @@ -424,8 +427,10 @@ static void demote_incompat_holders(struct gfs2_glock *gl, */ if (!test_bit(HIF_HOLDER, &gh->gh_iflags)) return; + if (gh == current_gh) + continue; if (test_bit(HIF_MAY_DEMOTE, &gh->gh_iflags) && - !may_grant(gl, new_gh, gh)) { + !may_grant(gl, current_gh, gh)) { /* * We should not recurse into do_promote because * __gfs2_glock_dq only calls handle_callback, @@ -478,8 +483,7 @@ find_first_strong_holder(struct gfs2_glock *gl) * gfs2_instantiate - Call the glops instantiate function * @gh: The glock holder * - * Returns: 0 if instantiate was successful, 2 if type specific operation is - * underway, or error. + * Returns: 0 if instantiate was successful, or error. */ int gfs2_instantiate(struct gfs2_holder *gh) { @@ -489,7 +493,7 @@ int gfs2_instantiate(struct gfs2_holder *gh) again: if (!test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags)) - return 0; + goto done; /* * Since we unlock the lockref lock, we set a flag to indicate @@ -508,37 +512,36 @@ again: goto again; } - ret = glops->go_instantiate(gh); + ret = glops->go_instantiate(gl); if (!ret) clear_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags); clear_and_wake_up_bit(GLF_INSTANTIATE_IN_PROG, &gl->gl_flags); - return ret; + if (ret) + return ret; + +done: + if (glops->go_held) + return glops->go_held(gh); + return 0; } /** * do_promote - promote as many requests as possible on the current queue * @gl: The glock * - * Returns: 1 if there is a blocked holder at the head of the list, or 2 - * if a type specific operation is underway. + * Returns: 1 if there is a blocked holder at the head of the list */ static int do_promote(struct gfs2_glock *gl) -__releases(&gl->gl_lockref.lock) -__acquires(&gl->gl_lockref.lock) { - struct gfs2_holder *gh, *tmp, *first_gh; + struct gfs2_holder *gh, *current_gh; bool incompat_holders_demoted = false; - bool lock_released; - int ret; -restart: - first_gh = find_first_strong_holder(gl); - list_for_each_entry_safe(gh, tmp, &gl->gl_holders, gh_list) { - lock_released = false; + current_gh = find_first_strong_holder(gl); + list_for_each_entry(gh, &gl->gl_holders, gh_list) { if (test_bit(HIF_HOLDER, &gh->gh_iflags)) continue; - if (!may_grant(gl, first_gh, gh)) { + if (!may_grant(gl, current_gh, gh)) { /* * If we get here, it means we may not grant this * holder for some reason. If this holder is at the @@ -550,37 +553,14 @@ restart: do_error(gl, 0); break; } - if (!incompat_holders_demoted) { - demote_incompat_holders(gl, first_gh); - incompat_holders_demoted = true; - first_gh = gh; - } - if (test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags) && - !(gh->gh_flags & GL_SKIP) && gl->gl_ops->go_instantiate) { - lock_released = true; - spin_unlock(&gl->gl_lockref.lock); - ret = gfs2_instantiate(gh); - spin_lock(&gl->gl_lockref.lock); - if (ret) { - if (ret == 1) - return 2; - gh->gh_error = ret; - list_del_init(&gh->gh_list); - trace_gfs2_glock_queue(gh, 0); - gfs2_holder_wake(gh); - goto restart; - } - } set_bit(HIF_HOLDER, &gh->gh_iflags); trace_gfs2_promote(gh); gfs2_holder_wake(gh); - /* - * If we released the gl_lockref.lock the holders list may have - * changed. For that reason, we start again at the start of - * the holders queue. - */ - if (lock_released) - goto restart; + if (!incompat_holders_demoted) { + current_gh = gh; + demote_incompat_holders(gl, current_gh); + incompat_holders_demoted = true; + } } return 0; } @@ -658,7 +638,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret) const struct gfs2_glock_operations *glops = gl->gl_ops; struct gfs2_holder *gh; unsigned state = ret & LM_OUT_ST_MASK; - int rv; spin_lock(&gl->gl_lockref.lock); trace_gfs2_glock_state_change(gl, state); @@ -716,6 +695,8 @@ retry: gfs2_demote_wake(gl); if (state != LM_ST_UNLOCKED) { if (glops->go_xmote_bh) { + int rv; + spin_unlock(&gl->gl_lockref.lock); rv = glops->go_xmote_bh(gl); spin_lock(&gl->gl_lockref.lock); @@ -724,13 +705,10 @@ retry: goto out; } } - rv = do_promote(gl); - if (rv == 2) - goto out_locked; + do_promote(gl); } out: clear_bit(GLF_LOCK, &gl->gl_flags); -out_locked: spin_unlock(&gl->gl_lockref.lock); } @@ -887,7 +865,6 @@ __releases(&gl->gl_lockref.lock) __acquires(&gl->gl_lockref.lock) { struct gfs2_holder *gh = NULL; - int ret; if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) return; @@ -906,18 +883,14 @@ __acquires(&gl->gl_lockref.lock) } else { if (test_bit(GLF_DEMOTE, &gl->gl_flags)) gfs2_demote_wake(gl); - ret = do_promote(gl); - if (ret == 0) + if (do_promote(gl) == 0) goto out_unlock; - if (ret == 2) - goto out; gh = find_first_waiter(gl); gl->gl_target = gh->gh_state; if (!(gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) do_error(gl, 0); /* Fail queued try locks */ } do_xmote(gl, gh, gl->gl_target); -out: return; out_sched: @@ -1315,6 +1288,25 @@ static void gfs2_glock_update_hold_time(struct gfs2_glock *gl, } /** + * gfs2_glock_holder_ready - holder is ready and its error code can be collected + * @gh: the glock holder + * + * Called when a glock holder no longer needs to be waited for because it is + * now either held (HIF_HOLDER set; gh_error == 0), or acquiring the lock has + * failed (gh_error != 0). + */ + +int gfs2_glock_holder_ready(struct gfs2_holder *gh) +{ + if (gh->gh_error || (gh->gh_flags & GL_SKIP)) + return gh->gh_error; + gh->gh_error = gfs2_instantiate(gh); + if (gh->gh_error) + gfs2_glock_dq(gh); + return gh->gh_error; +} + +/** * gfs2_glock_wait - wait on a glock acquisition * @gh: the glock holder * @@ -1328,7 +1320,7 @@ int gfs2_glock_wait(struct gfs2_holder *gh) might_sleep(); wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE); gfs2_glock_update_hold_time(gh->gh_gl, start_time); - return gh->gh_error; + return gfs2_glock_holder_ready(gh); } static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs) @@ -1356,7 +1348,6 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd; int i, ret = 0, timeout = 0; unsigned long start_time = jiffies; - bool keep_waiting; might_sleep(); /* @@ -1366,53 +1357,33 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs) for (i = 0; i < num_gh; i++) timeout += ghs[i].gh_gl->gl_hold_time << 1; -wait_for_dlm: if (!wait_event_timeout(sdp->sd_async_glock_wait, - !glocks_pending(num_gh, ghs), timeout)) + !glocks_pending(num_gh, ghs), timeout)) { ret = -ESTALE; /* request timed out. */ + goto out; + } - /* - * If dlm granted all our requests, we need to adjust the glock - * minimum hold time values according to how long we waited. - * - * If our request timed out, we need to repeatedly release any held - * glocks we acquired thus far to allow dlm to acquire the remaining - * glocks without deadlocking. We cannot currently cancel outstanding - * glock acquisitions. - * - * The HIF_WAIT bit tells us which requests still need a response from - * dlm. - * - * If dlm sent us any errors, we return the first error we find. - */ - keep_waiting = false; for (i = 0; i < num_gh; i++) { - /* Skip holders we have already dequeued below. */ - if (!gfs2_holder_queued(&ghs[i])) - continue; - /* Skip holders with a pending DLM response. */ - if (test_bit(HIF_WAIT, &ghs[i].gh_iflags)) { - keep_waiting = true; - continue; - } + struct gfs2_holder *gh = &ghs[i]; + int ret2; - if (test_bit(HIF_HOLDER, &ghs[i].gh_iflags)) { - if (ret == -ESTALE) - gfs2_glock_dq(&ghs[i]); - else - gfs2_glock_update_hold_time(ghs[i].gh_gl, - start_time); + if (test_bit(HIF_HOLDER, &gh->gh_iflags)) { + gfs2_glock_update_hold_time(gh->gh_gl, + start_time); } + ret2 = gfs2_glock_holder_ready(gh); if (!ret) - ret = ghs[i].gh_error; + ret = ret2; } - if (keep_waiting) - goto wait_for_dlm; +out: + if (ret) { + for (i = 0; i < num_gh; i++) { + struct gfs2_holder *gh = &ghs[i]; - /* - * At this point, we've either acquired all locks or released them all. - */ + gfs2_glock_dq(gh); + } + } return ret; } @@ -1491,10 +1462,10 @@ __acquires(&gl->gl_lockref.lock) if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) { if (test_bit(GLF_LOCK, &gl->gl_flags)) { - struct gfs2_holder *first_gh; + struct gfs2_holder *current_gh; - first_gh = find_first_strong_holder(gl); - try_futile = !may_grant(gl, first_gh, gh); + current_gh = find_first_strong_holder(gl); + try_futile = !may_grant(gl, current_gh, gh); } if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags)) goto fail; @@ -2242,20 +2213,6 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp) glock_hash_walk(dump_glock_func, sdp); } -void gfs2_glock_finish_truncate(struct gfs2_inode *ip) -{ - struct gfs2_glock *gl = ip->i_gl; - int ret; - - ret = gfs2_truncatei_resume(ip); - gfs2_glock_assert_withdraw(gl, ret == 0); - - spin_lock(&gl->gl_lockref.lock); - clear_bit(GLF_LOCK, &gl->gl_flags); - run_queue(gl, 1); - spin_unlock(&gl->gl_lockref.lock); -} - static const char *state2str(unsigned state) { switch(state) { diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index c0ae9100a0bc..5aed8b500cf5 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h @@ -213,6 +213,7 @@ extern void gfs2_holder_uninit(struct gfs2_holder *gh); extern int gfs2_glock_nq(struct gfs2_holder *gh); extern int gfs2_glock_poll(struct gfs2_holder *gh); extern int gfs2_instantiate(struct gfs2_holder *gh); +extern int gfs2_glock_holder_ready(struct gfs2_holder *gh); extern int gfs2_glock_wait(struct gfs2_holder *gh); extern int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs); extern void gfs2_glock_dq(struct gfs2_holder *gh); @@ -273,7 +274,6 @@ extern void gfs2_cancel_delete_work(struct gfs2_glock *gl); extern bool gfs2_delete_work_queued(const struct gfs2_glock *gl); extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp); extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp); -extern void gfs2_glock_finish_truncate(struct gfs2_inode *ip); extern void gfs2_glock_thaw(struct gfs2_sbd *sdp); extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl); extern void gfs2_glock_free(struct gfs2_glock *gl); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 392800f082a6..49210a2e7ce7 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -485,35 +485,33 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) * Returns: errno */ -static int inode_go_instantiate(struct gfs2_holder *gh) +static int inode_go_instantiate(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip = gl->gl_object; + + if (!ip) /* no inode to populate - read it in later */ + return 0; + + return gfs2_inode_refresh(ip); +} + +static int inode_go_held(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_inode *ip = gl->gl_object; int error = 0; if (!ip) /* no inode to populate - read it in later */ - goto out; - - error = gfs2_inode_refresh(ip); - if (error) - goto out; + return 0; if (gh->gh_state != LM_ST_DEFERRED) inode_dio_wait(&ip->i_inode); if ((ip->i_diskflags & GFS2_DIF_TRUNC_IN_PROG) && (gl->gl_state == LM_ST_EXCLUSIVE) && - (gh->gh_state == LM_ST_EXCLUSIVE)) { - spin_lock(&sdp->sd_trunc_lock); - if (list_empty(&ip->i_trunc_list)) - list_add(&ip->i_trunc_list, &sdp->sd_trunc_list); - spin_unlock(&sdp->sd_trunc_lock); - wake_up(&sdp->sd_quota_wait); - error = 1; - } + (gh->gh_state == LM_ST_EXCLUSIVE)) + error = gfs2_truncatei_resume(ip); -out: return error; } @@ -737,6 +735,7 @@ const struct gfs2_glock_operations gfs2_inode_glops = { .go_inval = inode_go_inval, .go_demote_ok = inode_go_demote_ok, .go_instantiate = inode_go_instantiate, + .go_held = inode_go_held, .go_dump = inode_go_dump, .go_type = LM_TYPE_INODE, .go_flags = GLOF_ASPACE | GLOF_LRU | GLOF_LVB, diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 8c00fb389ae5..d09d9892cd05 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -219,7 +219,8 @@ struct gfs2_glock_operations { int (*go_xmote_bh)(struct gfs2_glock *gl); void (*go_inval) (struct gfs2_glock *gl, int flags); int (*go_demote_ok) (const struct gfs2_glock *gl); - int (*go_instantiate) (struct gfs2_holder *gh); + 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, const char *fs_id_buf); void (*go_callback)(struct gfs2_glock *gl, bool remote); @@ -396,7 +397,6 @@ struct gfs2_inode { atomic_t i_sizehint; /* hint of the write size */ struct rw_semaphore i_rw_mutex; struct list_head i_ordered; - struct list_head i_trunc_list; __be64 *i_hash_cache; u32 i_entries; u32 i_diskflags; @@ -784,8 +784,6 @@ struct gfs2_sbd { struct mutex sd_quota_mutex; struct mutex sd_quota_sync_mutex; wait_queue_head_t sd_quota_wait; - struct list_head sd_trunc_list; - spinlock_t sd_trunc_lock; unsigned int sd_quota_slots; unsigned long *sd_quota_bitmap; diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index 244187e3e70f..d94791527dcb 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -38,7 +38,6 @@ static void gfs2_init_inode_once(void *foo) inode_init_once(&ip->i_inode); atomic_set(&ip->i_sizehint, 0); init_rwsem(&ip->i_rw_mutex); - INIT_LIST_HEAD(&ip->i_trunc_list); INIT_LIST_HEAD(&ip->i_ordered); ip->i_qadata = NULL; gfs2_holder_mark_uninitialized(&ip->i_rgd_gh); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index c9b423c874a3..549879929c84 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -106,8 +106,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) mutex_init(&sdp->sd_quota_mutex); mutex_init(&sdp->sd_quota_sync_mutex); init_waitqueue_head(&sdp->sd_quota_wait); - INIT_LIST_HEAD(&sdp->sd_trunc_list); - spin_lock_init(&sdp->sd_trunc_lock); spin_lock_init(&sdp->sd_bitmap_lock); INIT_LIST_HEAD(&sdp->sd_sc_inodes_list); diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 59d727a4ae2c..a6667e8d781f 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -1517,25 +1517,6 @@ static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, } } -static void quotad_check_trunc_list(struct gfs2_sbd *sdp) -{ - struct gfs2_inode *ip; - - while(1) { - ip = NULL; - spin_lock(&sdp->sd_trunc_lock); - if (!list_empty(&sdp->sd_trunc_list)) { - ip = list_first_entry(&sdp->sd_trunc_list, - struct gfs2_inode, i_trunc_list); - list_del_init(&ip->i_trunc_list); - } - spin_unlock(&sdp->sd_trunc_lock); - if (ip == NULL) - return; - gfs2_glock_finish_truncate(ip); - } -} - void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) { if (!sdp->sd_statfs_force_sync) { sdp->sd_statfs_force_sync = 1; @@ -1558,7 +1539,6 @@ int gfs2_quotad(void *data) unsigned long quotad_timeo = 0; unsigned long t = 0; DEFINE_WAIT(wait); - int empty; while (!kthread_should_stop()) { @@ -1579,19 +1559,13 @@ int gfs2_quotad(void *data) quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, "ad_timeo, &tune->gt_quota_quantum); - /* Check for & recover partially truncated inodes */ - quotad_check_trunc_list(sdp); - try_to_freeze(); bypass: t = min(quotad_timeo, statfs_timeo); prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_INTERRUPTIBLE); - spin_lock(&sdp->sd_trunc_lock); - empty = list_empty(&sdp->sd_trunc_list); - spin_unlock(&sdp->sd_trunc_lock); - if (empty && !sdp->sd_statfs_force_sync) + if (!sdp->sd_statfs_force_sync) t -= schedule_timeout(t); else t = 0; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index b9b8faefbe84..f602fb844951 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1196,9 +1196,8 @@ static void rgrp_set_bitmap_flags(struct gfs2_rgrpd *rgd) * Returns: errno */ -int gfs2_rgrp_go_instantiate(struct gfs2_holder *gh) +int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl) { - struct gfs2_glock *gl = gh->gh_gl; struct gfs2_rgrpd *rgd = gl->gl_object; struct gfs2_sbd *sdp = rgd->rd_sbd; unsigned int length = rgd->rd_length; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index fd6ee8bfe18d..00b30cf893af 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -31,7 +31,7 @@ extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); extern void gfs2_clear_rgrpd(struct gfs2_sbd *sdp); extern int gfs2_rindex_update(struct gfs2_sbd *sdp); extern void gfs2_free_clones(struct gfs2_rgrpd *rgd); -extern int gfs2_rgrp_go_instantiate(struct gfs2_holder *gh); +extern int gfs2_rgrp_go_instantiate(struct gfs2_glock *gl); extern void gfs2_rgrp_brelse(struct gfs2_rgrpd *rgd); extern struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index bdb773e5c88f..b5b0f285b27f 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1196,7 +1196,7 @@ static bool gfs2_upgrade_iopen_glock(struct inode *inode) gfs2_glock_dq(gh); return false; } - return true; + return gfs2_glock_holder_ready(gh) == 0; } /** |