Skip to content

Commit

Permalink
Merge tag 'gfs2-for-6.13' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/gfs2/linux-gfs2

Pull gfs2 updates from Andreas Gruenbacher:

 - Fix the code that cleans up left-over unlinked files.

   Various fixes and minor improvements in deleting files cached or held
   open remotely.

 - Simplify the use of dlm's DLM_LKF_QUECVT flag.

 - A few other minor cleanups.

* tag 'gfs2-for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (21 commits)
  gfs2: Prevent inode creation race
  gfs2: Only defer deletes when we have an iopen glock
  gfs2: Simplify DLM_LKF_QUECVT use
  gfs2: gfs2_evict_inode clarification
  gfs2: Make gfs2_inode_refresh static
  gfs2: Use get_random_u32 in gfs2_orlov_skip
  gfs2: Randomize GLF_VERIFY_DELETE work delay
  gfs2: Use mod_delayed_work in gfs2_queue_try_to_evict
  gfs2: Update to the evict / remote delete documentation
  gfs2: Call gfs2_queue_verify_delete from gfs2_evict_inode
  gfs2: Clean up delete work processing
  gfs2: Minor delete_work_func cleanup
  gfs2: Return enum evict_behavior from gfs2_upgrade_iopen_glock
  gfs2: Rename dinode_demise to evict_behavior
  gfs2: Rename GIF_{DEFERRED -> DEFER}_DELETE
  gfs2: Faster gfs2_upgrade_iopen_glock wakeups
  KMSAN: uninit-value in inode_go_dump (5)
  gfs2: Fix unlinked inode cleanup
  gfs2: Allow immediate GLF_VERIFY_DELETE work
  gfs2: Initialize gl_no_formal_ino earlier
  ...
  • Loading branch information
torvalds committed Nov 26, 2024
2 parents 7eef7e3 + ffd1cf0 commit ff2a7a0
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 114 deletions.
107 changes: 41 additions & 66 deletions fs/gfs2/glock.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/rhashtable.h>
#include <linux/pid_namespace.h>
#include <linux/file.h>
#include <linux/random.h>

#include "gfs2.h"
#include "incore.h"
Expand Down Expand Up @@ -562,11 +563,11 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
gl->gl_tchange = jiffies;
}

static void gfs2_set_demote(struct gfs2_glock *gl)
static void gfs2_set_demote(int nr, struct gfs2_glock *gl)
{
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

set_bit(GLF_DEMOTE, &gl->gl_flags);
set_bit(nr, &gl->gl_flags);
smp_mb();
wake_up(&sdp->sd_async_glock_wait);
}
Expand Down Expand Up @@ -958,37 +959,45 @@ static void gfs2_glock_poke(struct gfs2_glock *gl)
gfs2_holder_uninit(&gh);
}

static bool gfs2_try_evict(struct gfs2_glock *gl)
static void gfs2_try_evict(struct gfs2_glock *gl)
{
struct gfs2_inode *ip;
bool evicted = false;

/*
* If there is contention on the iopen glock and we have an inode, try
* to grab and release the inode so that it can be evicted. This will
* allow the remote node to go ahead and delete the inode without us
* having to do it, which will avoid rgrp glock thrashing.
* to grab and release the inode so that it can be evicted. The
* GIF_DEFER_DELETE flag indicates to gfs2_evict_inode() that the inode
* should not be deleted locally. This will allow the remote node to
* go ahead and delete the inode without us having to do it, which will
* avoid rgrp glock thrashing.
*
* The remote node is likely still holding the corresponding inode
* glock, so it will run before we get to verify that the delete has
* happened below.
* happened below. (Verification is triggered by the call to
* gfs2_queue_verify_delete() in gfs2_evict_inode().)
*/
spin_lock(&gl->gl_lockref.lock);
ip = gl->gl_object;
if (ip && !igrab(&ip->i_inode))
ip = NULL;
spin_unlock(&gl->gl_lockref.lock);
if (ip) {
gl->gl_no_formal_ino = ip->i_no_formal_ino;
set_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
wait_on_inode(&ip->i_inode);
if (is_bad_inode(&ip->i_inode)) {
iput(&ip->i_inode);
ip = NULL;
}
}
if (ip) {
set_bit(GIF_DEFER_DELETE, &ip->i_flags);
d_prune_aliases(&ip->i_inode);
iput(&ip->i_inode);

/* If the inode was evicted, gl->gl_object will now be NULL. */
spin_lock(&gl->gl_lockref.lock);
ip = gl->gl_object;
if (ip) {
clear_bit(GIF_DEFERRED_DELETE, &ip->i_flags);
clear_bit(GIF_DEFER_DELETE, &ip->i_flags);
if (!igrab(&ip->i_inode))
ip = NULL;
}
Expand All @@ -997,9 +1006,7 @@ static bool gfs2_try_evict(struct gfs2_glock *gl)
gfs2_glock_poke(ip->i_gl);
iput(&ip->i_inode);
}
evicted = !ip;
}
return evicted;
}

bool gfs2_queue_try_to_evict(struct gfs2_glock *gl)
Expand All @@ -1008,70 +1015,47 @@ bool gfs2_queue_try_to_evict(struct gfs2_glock *gl)

if (test_and_set_bit(GLF_TRY_TO_EVICT, &gl->gl_flags))
return false;
return queue_delayed_work(sdp->sd_delete_wq,
&gl->gl_delete, 0);
return !mod_delayed_work(sdp->sd_delete_wq, &gl->gl_delete, 0);
}

static bool gfs2_queue_verify_evict(struct gfs2_glock *gl)
bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later)
{
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
unsigned long delay;

if (test_and_set_bit(GLF_VERIFY_EVICT, &gl->gl_flags))
if (test_and_set_bit(GLF_VERIFY_DELETE, &gl->gl_flags))
return false;
return queue_delayed_work(sdp->sd_delete_wq,
&gl->gl_delete, 5 * HZ);
delay = later ? HZ + get_random_long() % (HZ * 9) : 0;
return queue_delayed_work(sdp->sd_delete_wq, &gl->gl_delete, delay);
}

static void delete_work_func(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct gfs2_glock *gl = container_of(dwork, struct gfs2_glock, gl_delete);
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct inode *inode;
u64 no_addr = gl->gl_name.ln_number;
bool verify_delete = test_and_clear_bit(GLF_VERIFY_DELETE, &gl->gl_flags);

if (test_and_clear_bit(GLF_TRY_TO_EVICT, &gl->gl_flags)) {
/*
* If we can evict the inode, give the remote node trying to
* delete the inode some time before verifying that the delete
* has happened. Otherwise, if we cause contention on the inode glock
* immediately, the remote node will think that we still have
* the inode in use, and so it will give up waiting.
*
* If we can't evict the inode, signal to the remote node that
* the inode is still in use. We'll later try to delete the
* inode locally in gfs2_evict_inode.
*
* FIXME: We only need to verify that the remote node has
* deleted the inode because nodes before this remote delete
* rework won't cooperate. At a later time, when we no longer
* care about compatibility with such nodes, we can skip this
* step entirely.
*/
if (gfs2_try_evict(gl)) {
if (test_bit(SDF_KILL, &sdp->sd_flags))
goto out;
if (gfs2_queue_verify_evict(gl))
return;
}
goto out;
}
if (test_and_clear_bit(GLF_TRY_TO_EVICT, &gl->gl_flags))
gfs2_try_evict(gl);

if (verify_delete) {
u64 no_addr = gl->gl_name.ln_number;
struct inode *inode;

if (test_and_clear_bit(GLF_VERIFY_EVICT, &gl->gl_flags)) {
inode = gfs2_lookup_by_inum(sdp, no_addr, gl->gl_no_formal_ino,
GFS2_BLKST_UNLINKED);
if (IS_ERR(inode)) {
if (PTR_ERR(inode) == -EAGAIN &&
!test_bit(SDF_KILL, &sdp->sd_flags) &&
gfs2_queue_verify_evict(gl))
gfs2_queue_verify_delete(gl, true))
return;
} else {
d_prune_aliases(inode);
iput(inode);
}
}

out:
gfs2_glock_put(gl);
}

Expand Down Expand Up @@ -1100,7 +1084,7 @@ static void glock_work_func(struct work_struct *work)

if (!delay) {
clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
gfs2_set_demote(gl);
gfs2_set_demote(GLF_DEMOTE, gl);
}
}
run_queue(gl, 0);
Expand Down Expand Up @@ -1442,10 +1426,7 @@ int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
static void request_demote(struct gfs2_glock *gl, unsigned int state,
unsigned long delay, bool remote)
{
if (delay)
set_bit(GLF_PENDING_DEMOTE, &gl->gl_flags);
else
gfs2_set_demote(gl);
gfs2_set_demote(delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE, gl);
if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
gl->gl_demote_state = state;
gl->gl_demote_time = jiffies;
Expand Down Expand Up @@ -1635,12 +1616,6 @@ int gfs2_glock_poll(struct gfs2_holder *gh)
return test_bit(HIF_WAIT, &gh->gh_iflags) ? 0 : 1;
}

static inline bool needs_demote(struct gfs2_glock *gl)
{
return (test_bit(GLF_DEMOTE, &gl->gl_flags) ||
test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags));
}

static void __gfs2_glock_dq(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
Expand All @@ -1649,8 +1624,8 @@ static void __gfs2_glock_dq(struct gfs2_holder *gh)

/*
* This holder should not be cached, so mark it for demote.
* Note: this should be done before the check for needs_demote
* below.
* Note: this should be done before the glock_needs_demote
* check below.
*/
if (gh->gh_flags & GL_NOCACHE)
request_demote(gl, LM_ST_UNLOCKED, 0, false);
Expand All @@ -1663,7 +1638,7 @@ static void __gfs2_glock_dq(struct gfs2_holder *gh)
* If there hasn't been a demote request we are done.
* (Let the remaining holders, if any, keep holding it.)
*/
if (!needs_demote(gl)) {
if (!glock_needs_demote(gl)) {
if (list_empty(&gl->gl_holders))
fast_path = 1;
}
Expand Down Expand Up @@ -2117,7 +2092,7 @@ static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
void gfs2_cancel_delete_work(struct gfs2_glock *gl)
{
clear_bit(GLF_TRY_TO_EVICT, &gl->gl_flags);
clear_bit(GLF_VERIFY_EVICT, &gl->gl_flags);
clear_bit(GLF_VERIFY_DELETE, &gl->gl_flags);
if (cancel_delayed_work(&gl->gl_delete))
gfs2_glock_put(gl);
}
Expand Down Expand Up @@ -2370,7 +2345,7 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
*p++ = 'N';
if (test_bit(GLF_TRY_TO_EVICT, gflags))
*p++ = 'e';
if (test_bit(GLF_VERIFY_EVICT, gflags))
if (test_bit(GLF_VERIFY_DELETE, gflags))
*p++ = 'E';
*p = 0;
return buf;
Expand Down
7 changes: 7 additions & 0 deletions fs/gfs2/glock.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state);
void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
bool gfs2_queue_try_to_evict(struct gfs2_glock *gl);
bool gfs2_queue_verify_delete(struct gfs2_glock *gl, bool later);
void gfs2_cancel_delete_work(struct gfs2_glock *gl);
void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
Expand Down Expand Up @@ -284,4 +285,10 @@ static inline bool gfs2_holder_queued(struct gfs2_holder *gh)
void gfs2_inode_remember_delete(struct gfs2_glock *gl, u64 generation);
bool gfs2_inode_already_deleted(struct gfs2_glock *gl, u64 generation);

static inline bool glock_needs_demote(struct gfs2_glock *gl)
{
return (test_bit(GLF_DEMOTE, &gl->gl_flags) ||
test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags));
}

#endif /* __GLOCK_DOT_H__ */
11 changes: 9 additions & 2 deletions fs/gfs2/glops.c
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
* Returns: errno
*/

int gfs2_inode_refresh(struct gfs2_inode *ip)
static int gfs2_inode_refresh(struct gfs2_inode *ip)
{
struct buffer_head *dibh;
int error;
Expand All @@ -494,11 +494,18 @@ int gfs2_inode_refresh(struct gfs2_inode *ip)
static int inode_go_instantiate(struct gfs2_glock *gl)
{
struct gfs2_inode *ip = gl->gl_object;
struct gfs2_glock *io_gl;
int error;

if (!ip) /* no inode to populate - read it in later */
return 0;

return gfs2_inode_refresh(ip);
error = gfs2_inode_refresh(ip);
if (error)
return error;
io_gl = ip->i_iopen_gh.gh_gl;
io_gl->gl_no_formal_ino = ip->i_no_formal_ino;
return 0;
}

static int inode_go_held(struct gfs2_holder *gh)
Expand Down
4 changes: 2 additions & 2 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ enum {
GLF_BLOCKING = 15,
GLF_UNLOCKED = 16, /* Wait for glock to be unlocked */
GLF_TRY_TO_EVICT = 17, /* iopen glocks only */
GLF_VERIFY_EVICT = 18, /* iopen glocks only */
GLF_VERIFY_DELETE = 18, /* iopen glocks only */
};

struct gfs2_glock {
Expand Down Expand Up @@ -376,7 +376,7 @@ enum {
GIF_SW_PAGED = 3,
GIF_FREE_VFS_INODE = 5,
GIF_GLOP_PENDING = 6,
GIF_DEFERRED_DELETE = 7,
GIF_DEFER_DELETE = 7,
};

struct gfs2_inode {
Expand Down
1 change: 1 addition & 0 deletions fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_free_inode;
gfs2_cancel_delete_work(io_gl);
io_gl->gl_no_formal_ino = ip->i_no_formal_ino;

retry:
error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr);
Expand Down
2 changes: 0 additions & 2 deletions fs/gfs2/inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
u64 no_formal_ino,
unsigned int blktype);

int gfs2_inode_refresh(struct gfs2_inode *ip);

struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
int is_root);
int gfs2_permission(struct mnt_idmap *idmap,
Expand Down
29 changes: 25 additions & 4 deletions fs/gfs2/lock_dlm.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,21 @@ static int make_mode(struct gfs2_sbd *sdp, const unsigned int lmstate)
return -1;
}

/* Taken from fs/dlm/lock.c. */

static bool middle_conversion(int cur, int req)
{
return (cur == DLM_LOCK_PR && req == DLM_LOCK_CW) ||
(cur == DLM_LOCK_CW && req == DLM_LOCK_PR);
}

static bool down_conversion(int cur, int req)
{
return !middle_conversion(cur, req) && req < cur;
}

static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,
const int req)
const int cur, const int req)
{
u32 lkf = 0;

Expand All @@ -251,7 +264,14 @@ static u32 make_flags(struct gfs2_glock *gl, const unsigned int gfs_flags,

if (!test_bit(GLF_INITIAL, &gl->gl_flags)) {
lkf |= DLM_LKF_CONVERT;
if (test_bit(GLF_BLOCKING, &gl->gl_flags))

/*
* The DLM_LKF_QUECVT flag needs to be set for "first come,
* first served" semantics, but it must only be set for
* "upward" lock conversions or else DLM will reject the
* request as invalid.
*/
if (!down_conversion(cur, req))
lkf |= DLM_LKF_QUECVT;
}

Expand All @@ -271,13 +291,14 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
unsigned int flags)
{
struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct;
int req;
int cur, req;
u32 lkf;
char strname[GDLM_STRNAME_BYTES] = "";
int error;

cur = make_mode(gl->gl_name.ln_sbd, gl->gl_state);
req = make_mode(gl->gl_name.ln_sbd, req_state);
lkf = make_flags(gl, flags, req);
lkf = make_flags(gl, flags, cur, req);
gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
if (test_bit(GLF_INITIAL, &gl->gl_flags)) {
Expand Down
Loading

0 comments on commit ff2a7a0

Please sign in to comment.