gfs2 debugfs improvements

- Improve the way how the state of glocks is reported in debugfs
   for glocks which are not held by processes, but rather by other
   resouces like cached inodes or flocks.
 -----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmNDPTcUHGFncnVlbmJh
 QHJlZGhhdC5jb20ACgkQ1b+f6wMTZToc9w//aoJUYZjHit6fQeD9RKksJrw82TrP
 VQKaPSA0pcGMXOxsoTAY9W4a5kEEjBoYpeIfGqGBtZl4Jq0IeNcOG1HM+sxI2YmR
 8SwL/p3hKOq/56beq/jBo8gWVDpf59B8iDfFyBCXtVk2riOw+H+5W5hx3EIfGTj+
 6qyppxc/GLXdl3ImmAIE28euzXoz0BE8UYs2GoaRLkCur8OqrproYOJBLkXqybTU
 SPtGtclQOFyrLq/4AYWHs7+ijQcs6QZNEJo5v79Wo7ewB0V0JVtZWqy/MMt4TUct
 189pL3El+Zxo9TmW8S2bAX2m19cdpEwijmBCbpdHcIQVI14jXKErpixbSCwU/aui
 uUfu7S57FrknUBHmPMfTQlT57Xqd1jddv2IL+3dLocJx/6/a5g17NNTDzooYf1WT
 hCXkuEj/LrIpva7lGymZzEgPVtW3YIOrVrRmGuvhSRjjCh9zIE5bOFWt7eMkiX0K
 UQBfaS5dNa5tAZcrHe81NVf/ZACmLFeCMCd1yC1c8EGYT4VVCJoDgx41hrEJoCgf
 EZQi1IiVXamPa/rjLlDjvRFnBdeGblWaeEK10j8ybtkjqfBJrI5Md60ynYSXlI3O
 h3Ux826PXEUR1PlHOpCli4CKnCF02942E1tvMem+QSzwDG6ojuVYhvUtPCThxlIy
 oeIm1/X+Z+TZ7po=
 =FORZ
 -----END PGP SIGNATURE-----

Merge tag 'gfs2-nopid-for-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 debugfs updates from Andreas Gruenbacher:

 - Improve the way how the state of glocks is reported in debugfs for
   glocks which are not held by processes, but rather by other resouces
   like cached inodes or flocks.

* tag 'gfs2-nopid-for-v6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Mark the remaining process-independent glock holders as GL_NOPID
  gfs2: Mark flock glock holders as GL_NOPID
  gfs2: Add GL_NOPID flag for process-independent glock holders
  gfs2: Add flocks to glockfd debugfs file
  gfs2: Add glockfd debugfs file
This commit is contained in:
Linus Torvalds 2022-10-10 20:13:22 -07:00
commit 288fc86067
9 changed files with 248 additions and 25 deletions

View File

@ -980,6 +980,7 @@ struct file *task_lookup_next_fd_rcu(struct task_struct *task, unsigned int *ret
*ret_fd = fd;
return file;
}
EXPORT_SYMBOL(task_lookup_next_fd_rcu);
/*
* Lightweight file lookup - no refcnt increment if fd table isn't shared.

View File

@ -1443,6 +1443,22 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
return dlm_posix_lock(ls->ls_dlm, ip->i_no_addr, file, cmd, fl);
}
static void __flock_holder_uninit(struct file *file, struct gfs2_holder *fl_gh)
{
struct gfs2_glock *gl = fl_gh->gh_gl;
/*
* Make sure gfs2_glock_put() won't sleep under the file->f_lock
* spinlock.
*/
gfs2_glock_hold(gl);
spin_lock(&file->f_lock);
gfs2_holder_uninit(fl_gh);
spin_unlock(&file->f_lock);
gfs2_glock_put(gl);
}
static int do_flock(struct file *file, int cmd, struct file_lock *fl)
{
struct gfs2_file *fp = file->private_data;
@ -1455,7 +1471,9 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
int sleeptime;
state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY_1CB) | GL_EXACT;
flags = GL_EXACT | GL_NOPID;
if (!IS_SETLKW(cmd))
flags |= LM_FLAG_TRY_1CB;
mutex_lock(&fp->f_fl_mutex);
@ -1474,18 +1492,21 @@ static int do_flock(struct file *file, int cmd, struct file_lock *fl)
&gfs2_flock_glops, CREATE, &gl);
if (error)
goto out;
spin_lock(&file->f_lock);
gfs2_holder_init(gl, state, flags, fl_gh);
spin_unlock(&file->f_lock);
gfs2_glock_put(gl);
}
for (sleeptime = 1; sleeptime <= 4; sleeptime <<= 1) {
error = gfs2_glock_nq(fl_gh);
if (error != GLR_TRYFAILED)
break;
fl_gh->gh_flags = LM_FLAG_TRY | GL_EXACT;
fl_gh->gh_flags &= ~LM_FLAG_TRY_1CB;
fl_gh->gh_flags |= LM_FLAG_TRY;
msleep(sleeptime);
}
if (error) {
gfs2_holder_uninit(fl_gh);
__flock_holder_uninit(file, fl_gh);
if (error == GLR_TRYFAILED)
error = -EAGAIN;
} else {
@ -1507,7 +1528,7 @@ static void do_unflock(struct file *file, struct file_lock *fl)
locks_lock_file_wait(file, fl);
if (gfs2_holder_initialized(fl_gh)) {
gfs2_glock_dq(fl_gh);
gfs2_holder_uninit(fl_gh);
__flock_holder_uninit(file, fl_gh);
}
mutex_unlock(&fp->f_fl_mutex);
}

View File

@ -33,6 +33,9 @@
#include <linux/list_sort.h>
#include <linux/lockref.h>
#include <linux/rhashtable.h>
#include <linux/pid_namespace.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include "gfs2.h"
#include "incore.h"
@ -1456,6 +1459,15 @@ void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
va_end(args);
}
static inline bool pid_is_meaningful(const struct gfs2_holder *gh)
{
if (!(gh->gh_flags & GL_NOPID))
return true;
if (gh->gh_state == LM_ST_UNLOCKED)
return true;
return false;
}
/**
* add_to_queue - Add a holder to the wait queue (but look for recursion)
* @gh: the holder structure to add
@ -1492,10 +1504,17 @@ __acquires(&gl->gl_lockref.lock)
}
list_for_each_entry(gh2, &gl->gl_holders, gh_list) {
if (unlikely(gh2->gh_owner_pid == gh->gh_owner_pid &&
(gh->gh_gl->gl_ops->go_type != LM_TYPE_FLOCK) &&
!test_bit(HIF_MAY_DEMOTE, &gh2->gh_iflags)))
goto trap_recursive;
if (likely(gh2->gh_owner_pid != gh->gh_owner_pid))
continue;
if (gh->gh_gl->gl_ops->go_type == LM_TYPE_FLOCK)
continue;
if (test_bit(HIF_MAY_DEMOTE, &gh2->gh_iflags))
continue;
if (!pid_is_meaningful(gh2))
continue;
goto trap_recursive;
}
list_for_each_entry(gh2, &gl->gl_holders, gh_list) {
if (try_futile &&
!(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) {
fail:
@ -2306,19 +2325,24 @@ static const char *hflags2str(char *buf, u16 flags, unsigned long iflags)
static void dump_holder(struct seq_file *seq, const struct gfs2_holder *gh,
const char *fs_id_buf)
{
struct task_struct *gh_owner = NULL;
const char *comm = "(none)";
pid_t owner_pid = 0;
char flags_buf[32];
rcu_read_lock();
if (gh->gh_owner_pid)
if (pid_is_meaningful(gh)) {
struct task_struct *gh_owner;
comm = "(ended)";
owner_pid = pid_nr(gh->gh_owner_pid);
gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID);
if (gh_owner)
comm = gh_owner->comm;
}
gfs2_print_dbg(seq, "%s H: s:%s f:%s e:%d p:%ld [%s] %pS\n",
fs_id_buf, state2str(gh->gh_state),
hflags2str(flags_buf, gh->gh_flags, gh->gh_iflags),
gh->gh_error,
gh->gh_owner_pid ? (long)pid_nr(gh->gh_owner_pid) : -1,
gh_owner ? gh_owner->comm : "(ended)",
(void *)gh->gh_ip);
gh->gh_error, (long)owner_pid, comm, (void *)gh->gh_ip);
rcu_read_unlock();
}
@ -2733,6 +2757,172 @@ static const struct file_operations gfs2_glstats_fops = {
.release = gfs2_glocks_release,
};
struct gfs2_glockfd_iter {
struct super_block *sb;
unsigned int tgid;
struct task_struct *task;
unsigned int fd;
struct file *file;
};
static struct task_struct *gfs2_glockfd_next_task(struct gfs2_glockfd_iter *i)
{
struct pid_namespace *ns = task_active_pid_ns(current);
struct pid *pid;
if (i->task)
put_task_struct(i->task);
rcu_read_lock();
retry:
i->task = NULL;
pid = find_ge_pid(i->tgid, ns);
if (pid) {
i->tgid = pid_nr_ns(pid, ns);
i->task = pid_task(pid, PIDTYPE_TGID);
if (!i->task) {
i->tgid++;
goto retry;
}
get_task_struct(i->task);
}
rcu_read_unlock();
return i->task;
}
static struct file *gfs2_glockfd_next_file(struct gfs2_glockfd_iter *i)
{
if (i->file) {
fput(i->file);
i->file = NULL;
}
rcu_read_lock();
for(;; i->fd++) {
struct inode *inode;
i->file = task_lookup_next_fd_rcu(i->task, &i->fd);
if (!i->file) {
i->fd = 0;
break;
}
inode = file_inode(i->file);
if (inode->i_sb != i->sb)
continue;
if (get_file_rcu(i->file))
break;
}
rcu_read_unlock();
return i->file;
}
static void *gfs2_glockfd_seq_start(struct seq_file *seq, loff_t *pos)
{
struct gfs2_glockfd_iter *i = seq->private;
if (*pos)
return NULL;
while (gfs2_glockfd_next_task(i)) {
if (gfs2_glockfd_next_file(i))
return i;
i->tgid++;
}
return NULL;
}
static void *gfs2_glockfd_seq_next(struct seq_file *seq, void *iter_ptr,
loff_t *pos)
{
struct gfs2_glockfd_iter *i = seq->private;
(*pos)++;
i->fd++;
do {
if (gfs2_glockfd_next_file(i))
return i;
i->tgid++;
} while (gfs2_glockfd_next_task(i));
return NULL;
}
static void gfs2_glockfd_seq_stop(struct seq_file *seq, void *iter_ptr)
{
struct gfs2_glockfd_iter *i = seq->private;
if (i->file)
fput(i->file);
if (i->task)
put_task_struct(i->task);
}
static void gfs2_glockfd_seq_show_flock(struct seq_file *seq,
struct gfs2_glockfd_iter *i)
{
struct gfs2_file *fp = i->file->private_data;
struct gfs2_holder *fl_gh = &fp->f_fl_gh;
struct lm_lockname gl_name = { .ln_type = LM_TYPE_RESERVED };
if (!READ_ONCE(fl_gh->gh_gl))
return;
spin_lock(&i->file->f_lock);
if (gfs2_holder_initialized(fl_gh))
gl_name = fl_gh->gh_gl->gl_name;
spin_unlock(&i->file->f_lock);
if (gl_name.ln_type != LM_TYPE_RESERVED) {
seq_printf(seq, "%d %u %u/%llx\n",
i->tgid, i->fd, gl_name.ln_type,
(unsigned long long)gl_name.ln_number);
}
}
static int gfs2_glockfd_seq_show(struct seq_file *seq, void *iter_ptr)
{
struct gfs2_glockfd_iter *i = seq->private;
struct inode *inode = file_inode(i->file);
struct gfs2_glock *gl;
inode_lock_shared(inode);
gl = GFS2_I(inode)->i_iopen_gh.gh_gl;
if (gl) {
seq_printf(seq, "%d %u %u/%llx\n",
i->tgid, i->fd, gl->gl_name.ln_type,
(unsigned long long)gl->gl_name.ln_number);
}
gfs2_glockfd_seq_show_flock(seq, i);
inode_unlock_shared(inode);
return 0;
}
static const struct seq_operations gfs2_glockfd_seq_ops = {
.start = gfs2_glockfd_seq_start,
.next = gfs2_glockfd_seq_next,
.stop = gfs2_glockfd_seq_stop,
.show = gfs2_glockfd_seq_show,
};
static int gfs2_glockfd_open(struct inode *inode, struct file *file)
{
struct gfs2_glockfd_iter *i;
struct gfs2_sbd *sdp = inode->i_private;
i = __seq_open_private(file, &gfs2_glockfd_seq_ops,
sizeof(struct gfs2_glockfd_iter));
if (!i)
return -ENOMEM;
i->sb = sdp->sd_vfs;
return 0;
}
static const struct file_operations gfs2_glockfd_fops = {
.owner = THIS_MODULE,
.open = gfs2_glockfd_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
DEFINE_SEQ_ATTRIBUTE(gfs2_sbstats);
void gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
@ -2742,6 +2932,9 @@ void gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
debugfs_create_file("glocks", S_IFREG | S_IRUGO, sdp->debugfs_dir, sdp,
&gfs2_glocks_fops);
debugfs_create_file("glockfd", S_IFREG | S_IRUGO, sdp->debugfs_dir, sdp,
&gfs2_glockfd_fops);
debugfs_create_file("glstats", S_IFREG | S_IRUGO, sdp->debugfs_dir, sdp,
&gfs2_glstats_fops);

View File

@ -91,6 +91,7 @@ enum {
#define GL_ASYNC 0x0040
#define GL_EXACT 0x0080
#define GL_SKIP 0x0100
#define GL_NOPID 0x0200
#define GL_NOCACHE 0x0400
/*

View File

@ -147,7 +147,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
else
gfs2_cancel_delete_work(io_gl);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED,
GL_EXACT | extra_flags,
GL_EXACT | GL_NOPID | extra_flags,
&ip->i_iopen_gh);
gfs2_glock_put(io_gl);
if (unlikely(error))
@ -726,7 +726,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
error = insert_inode_locked4(inode, ip->i_no_addr, iget_test, &ip->i_no_addr);
BUG_ON(error);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT | GL_NOPID,
&ip->i_iopen_gh);
if (error)
goto fail_gunlock2;

View File

@ -406,7 +406,8 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
error = gfs2_glock_nq_num(sdp,
GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
LM_ST_EXCLUSIVE,
LM_FLAG_NOEXP | GL_NOCACHE | GL_NOPID,
mount_gh);
if (error) {
fs_err(sdp, "can't acquire mount glock: %d\n", error);
@ -416,7 +417,7 @@ static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
error = gfs2_glock_nq_num(sdp,
GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
LM_ST_SHARED,
LM_FLAG_NOEXP | GL_EXACT,
LM_FLAG_NOEXP | GL_EXACT | GL_NOPID,
&sdp->sd_live_gh);
if (error) {
fs_err(sdp, "can't acquire live glock: %d\n", error);
@ -692,7 +693,7 @@ static int init_statfs(struct gfs2_sbd *sdp)
iput(pn);
pn = NULL;
ip = GFS2_I(sdp->sd_sc_inode);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NOPID,
&sdp->sd_sc_gh);
if (error) {
fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
@ -781,7 +782,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
&gfs2_journal_glops,
LM_ST_EXCLUSIVE,
LM_FLAG_NOEXP | GL_NOCACHE,
LM_FLAG_NOEXP | GL_NOCACHE | GL_NOPID,
&sdp->sd_journal_gh);
if (error) {
fs_err(sdp, "can't acquire journal glock: %d\n", error);
@ -791,7 +792,8 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
ip = GFS2_I(sdp->sd_jdesc->jd_inode);
sdp->sd_jinode_gl = ip->i_gl;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE,
LM_FLAG_NOEXP | GL_EXACT |
GL_NOCACHE | GL_NOPID,
&sdp->sd_jinode_gh);
if (error) {
fs_err(sdp, "can't acquire journal inode glock: %d\n",
@ -962,7 +964,7 @@ static int init_per_node(struct gfs2_sbd *sdp, int undo)
pn = NULL;
ip = GFS2_I(sdp->sd_qc_inode);
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0,
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_NOPID,
&sdp->sd_qc_gh);
if (error) {
fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);

View File

@ -346,7 +346,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp)
}
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
LM_FLAG_NOEXP, &sdp->sd_freeze_gh);
LM_FLAG_NOEXP | GL_NOPID,
&sdp->sd_freeze_gh);
if (error)
goto out;

View File

@ -232,7 +232,8 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
*/
fs_warn(sdp, "Requesting recovery of jid %d.\n",
sdp->sd_lockstruct.ls_jid);
gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | LM_FLAG_NOEXP,
gfs2_holder_reinit(LM_ST_EXCLUSIVE,
LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | GL_NOPID,
&sdp->sd_live_gh);
msleep(GL_GLOCK_MAX_HOLD);
/*
@ -257,7 +258,8 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp)
fs_warn(sdp, "Unable to recover our journal jid %d.\n",
sdp->sd_lockstruct.ls_jid);
gfs2_glock_dq_wait(&sdp->sd_live_gh);
gfs2_holder_reinit(LM_ST_SHARED, LM_FLAG_NOEXP | GL_EXACT,
gfs2_holder_reinit(LM_ST_SHARED,
LM_FLAG_NOEXP | GL_EXACT | GL_NOPID,
&sdp->sd_live_gh);
gfs2_glock_nq(&sdp->sd_live_gh);
}

View File

@ -519,6 +519,7 @@ struct pid *find_ge_pid(int nr, struct pid_namespace *ns)
{
return idr_get_next(&ns->idr, &nr);
}
EXPORT_SYMBOL_GPL(find_ge_pid);
struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags)
{