Commit c7d7d2d3 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher
Browse files

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
parents 74b1b10e ebdc416c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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.
+25 −4
Original line number Diff line number Diff line
@@ -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);
}
+203 −10
Original line number Diff line number Diff line
@@ -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)))
		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);

+1 −0
Original line number Diff line number Diff line
@@ -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
  
/*
+3 −2
Original line number Diff line number Diff line
@@ -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;

Loading