forked from Minki/linux
gfs2: Merge branch 'for-next.nopid' into for-next
Resolves a conflict in gfs2_inode_lookup() between the following commits: gfs2: Use TRY lock in gfs2_inode_lookup for UNLINKED inodes gfs2: Mark the remaining process-independent glock holders as GL_NOPID Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
commit
c7d7d2d345
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
213
fs/gfs2/glock.c
213
fs/gfs2/glock.c
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user