Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad12ab25 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 changes from Steven Whitehouse.

* git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw:
  GFS2: Change truncate page allocation to be GFP_NOFS
  GFS2: call gfs2_write_alloc_required for each chunk
  GFS2: Clean up log flush header writing
  GFS2: Remove a __GFP_NOFAIL allocation
  GFS2: Flush pending glock work when evicting an inode
  GFS2: make sure rgrps are up to date in func gfs2_blk2rgrpd
  GFS2: Eliminate sd_rindex_mutex
  GFS2: Unlock rindex mutex on glock error
  GFS2: Make bd_cmp() static
  GFS2: Sort the ordered write list
  GFS2: FITRIM ioctl support
  GFS2: Move two functions from log.c to lops.c
  GFS2: glock statistics gathering
parents 30d73f37 220cca2a
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
	int release = 0;

	if (!page || page->index) {
		page = grab_cache_page(inode->i_mapping, 0);
		page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
		if (!page)
			return -ENOMEM;
		release = 1;
@@ -930,7 +930,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
	struct page *page;
	int err;

	page = grab_cache_page(mapping, index);
	page = find_or_create_page(mapping, index, GFP_NOFS);
	if (!page)
		return 0;

+10 −5
Original line number Diff line number Diff line
@@ -313,6 +313,8 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
		return gfs2_get_flags(filp, (u32 __user *)arg);
	case FS_IOC_SETFLAGS:
		return gfs2_set_flags(filp, (u32 __user *)arg);
	case FITRIM:
		return gfs2_fitrim(filp, (void __user *)arg);
	}
	return -ENOTTY;
}
@@ -674,6 +676,7 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
	struct gfs2_inode *ip = GFS2_I(inode);
	struct buffer_head *dibh;
	int error;
	loff_t size = len;
	unsigned int nr_blks;
	sector_t lblock = offset >> inode->i_blkbits;

@@ -707,8 +710,8 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
			goto out;
		}
	}
	if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
		i_size_write(inode, offset + len);
	if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
		i_size_write(inode, offset + size);

	mark_inode_dirty(inode);

@@ -777,12 +780,14 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
	if (unlikely(error))
		goto out_uninit;

	if (!gfs2_write_alloc_required(ip, offset, len))
		goto out_unlock;

	while (len > 0) {
		if (len < bytes)
			bytes = len;
		if (!gfs2_write_alloc_required(ip, offset, bytes)) {
			len -= bytes;
			offset += bytes;
			continue;
		}
		qa = gfs2_qadata_get(ip);
		if (!qa) {
			error = -ENOMEM;
+202 −8
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/rcupdate.h>
#include <linux/rculist_bl.h>
#include <linux/bit_spinlock.h>
#include <linux/percpu.h>

#include "gfs2.h"
#include "incore.h"
@@ -543,6 +544,11 @@ __acquires(&gl->gl_spin)
		do_error(gl, 0); /* Fail queued try locks */
	}
	gl->gl_req = target;
	set_bit(GLF_BLOCKING, &gl->gl_flags);
	if ((gl->gl_req == LM_ST_UNLOCKED) ||
	    (gl->gl_state == LM_ST_EXCLUSIVE) ||
	    (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
		clear_bit(GLF_BLOCKING, &gl->gl_flags);
	spin_unlock(&gl->gl_spin);
	if (glops->go_xmote_th)
		glops->go_xmote_th(gl);
@@ -744,6 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
		return -ENOMEM;

	atomic_inc(&sdp->sd_glock_disposal);
	gl->gl_sbd = sdp;
	gl->gl_flags = 0;
	gl->gl_name = name;
	atomic_set(&gl->gl_ref, 1);
@@ -752,12 +759,17 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
	gl->gl_demote_state = LM_ST_EXCLUSIVE;
	gl->gl_hash = hash;
	gl->gl_ops = glops;
	snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number);
	gl->gl_dstamp = ktime_set(0, 0);
	preempt_disable();
	/* We use the global stats to estimate the initial per-glock stats */
	gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type];
	preempt_enable();
	gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0;
	gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0;
	memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
	gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
	gl->gl_tchange = jiffies;
	gl->gl_object = NULL;
	gl->gl_sbd = sdp;
	gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
	INIT_WORK(&gl->gl_delete, delete_work_func);
@@ -999,6 +1011,8 @@ __acquires(&gl->gl_spin)
	}
	set_bit(GLF_QUEUED, &gl->gl_flags);
	trace_gfs2_glock_queue(gh, 1);
	gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT);
	gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT);
	if (likely(insert_pt == NULL)) {
		list_add_tail(&gh->gh_list, &gl->gl_holders);
		if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
@@ -1658,6 +1672,8 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl)
		*p++ = 'L';
	if (gl->gl_object)
		*p++ = 'o';
	if (test_bit(GLF_BLOCKING, gflags))
		*p++ = 'b';
	*p = 0;
	return buf;
}
@@ -1714,8 +1730,78 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
	return error;
}

static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr)
{
	struct gfs2_glock *gl = iter_ptr;

	seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n",
		   gl->gl_name.ln_type,
		   (unsigned long long)gl->gl_name.ln_number,
		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTT],
		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR],
		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB],
		   (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB],
		   (long long)gl->gl_stats.stats[GFS2_LKS_SIRT],
		   (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR],
		   (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT],
		   (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]);
	return 0;
}

static const char *gfs2_gltype[] = {
	"type",
	"reserved",
	"nondisk",
	"inode",
	"rgrp",
	"meta",
	"iopen",
	"flock",
	"plock",
	"quota",
	"journal",
};

static const char *gfs2_stype[] = {
	[GFS2_LKS_SRTT]		= "srtt",
	[GFS2_LKS_SRTTVAR]	= "srttvar",
	[GFS2_LKS_SRTTB]	= "srttb",
	[GFS2_LKS_SRTTVARB]	= "srttvarb",
	[GFS2_LKS_SIRT]		= "sirt",
	[GFS2_LKS_SIRTVAR]	= "sirtvar",
	[GFS2_LKS_DCOUNT]	= "dlm",
	[GFS2_LKS_QCOUNT]	= "queue",
};

#define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype))

static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr)
{
	struct gfs2_glock_iter *gi = seq->private;
	struct gfs2_sbd *sdp = gi->sdp;
	unsigned index = gi->hash >> 3;
	unsigned subindex = gi->hash & 0x07;
	s64 value;
	int i;

	if (index == 0 && subindex != 0)
		return 0;

	seq_printf(seq, "%-10s %8s:", gfs2_gltype[index],
		   (index == 0) ? "cpu": gfs2_stype[subindex]);

	for_each_possible_cpu(i) {
                const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i);
		if (index == 0) {
			value = i;
		} else {
			value = lkstats->lkstats[index - 1].stats[subindex];
		}
		seq_printf(seq, " %15lld", (long long)value);
	}
	seq_putc(seq, '\n');
	return 0;
}

int __init gfs2_glock_init(void)
{
@@ -1828,6 +1914,35 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr)
	return dump_glock(seq, iter_ptr);
}

static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos)
{
	struct gfs2_glock_iter *gi = seq->private;

	gi->hash = *pos;
	if (*pos >= GFS2_NR_SBSTATS)
		return NULL;
	preempt_disable();
	return SEQ_START_TOKEN;
}

static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr,
				   loff_t *pos)
{
	struct gfs2_glock_iter *gi = seq->private;
	(*pos)++;
	gi->hash++;
	if (gi->hash >= GFS2_NR_SBSTATS) {
		preempt_enable();
		return NULL;
	}
	return SEQ_START_TOKEN;
}

static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr)
{
	preempt_enable();
}

static const struct seq_operations gfs2_glock_seq_ops = {
	.start = gfs2_glock_seq_start,
	.next  = gfs2_glock_seq_next,
@@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = {
	.show  = gfs2_glock_seq_show,
};

static int gfs2_debugfs_open(struct inode *inode, struct file *file)
static const struct seq_operations gfs2_glstats_seq_ops = {
	.start = gfs2_glock_seq_start,
	.next  = gfs2_glock_seq_next,
	.stop  = gfs2_glock_seq_stop,
	.show  = gfs2_glstats_seq_show,
};

static const struct seq_operations gfs2_sbstats_seq_ops = {
	.start = gfs2_sbstats_seq_start,
	.next  = gfs2_sbstats_seq_next,
	.stop  = gfs2_sbstats_seq_stop,
	.show  = gfs2_sbstats_seq_show,
};

static int gfs2_glocks_open(struct inode *inode, struct file *file)
{
	int ret = seq_open_private(file, &gfs2_glock_seq_ops,
				   sizeof(struct gfs2_glock_iter));
@@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file)
	return ret;
}

static const struct file_operations gfs2_debug_fops = {
static int gfs2_glstats_open(struct inode *inode, struct file *file)
{
	int ret = seq_open_private(file, &gfs2_glstats_seq_ops,
				   sizeof(struct gfs2_glock_iter));
	if (ret == 0) {
		struct seq_file *seq = file->private_data;
		struct gfs2_glock_iter *gi = seq->private;
		gi->sdp = inode->i_private;
	}
	return ret;
}

static int gfs2_sbstats_open(struct inode *inode, struct file *file)
{
	int ret = seq_open_private(file, &gfs2_sbstats_seq_ops,
				   sizeof(struct gfs2_glock_iter));
	if (ret == 0) {
		struct seq_file *seq = file->private_data;
		struct gfs2_glock_iter *gi = seq->private;
		gi->sdp = inode->i_private;
	}
	return ret;
}

static const struct file_operations gfs2_glocks_fops = {
	.owner   = THIS_MODULE,
	.open    = gfs2_debugfs_open,
	.open    = gfs2_glocks_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release_private,
};

static const struct file_operations gfs2_glstats_fops = {
	.owner   = THIS_MODULE,
	.open    = gfs2_glstats_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release_private,
};

static const struct file_operations gfs2_sbstats_fops = {
	.owner   = THIS_MODULE,
	.open	 = gfs2_sbstats_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release_private,
@@ -1863,20 +2032,45 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
	sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
							 S_IFREG | S_IRUGO,
							 sdp->debugfs_dir, sdp,
							 &gfs2_debug_fops);
							 &gfs2_glocks_fops);
	if (!sdp->debugfs_dentry_glocks)
		return -ENOMEM;
		goto fail;

	sdp->debugfs_dentry_glstats = debugfs_create_file("glstats",
							S_IFREG | S_IRUGO,
							sdp->debugfs_dir, sdp,
							&gfs2_glstats_fops);
	if (!sdp->debugfs_dentry_glstats)
		goto fail;

	sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats",
							S_IFREG | S_IRUGO,
							sdp->debugfs_dir, sdp,
							&gfs2_sbstats_fops);
	if (!sdp->debugfs_dentry_sbstats)
		goto fail;

	return 0;
fail:
	gfs2_delete_debugfs_file(sdp);
	return -ENOMEM;
}

void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
{
	if (sdp && sdp->debugfs_dir) {
	if (sdp->debugfs_dir) {
		if (sdp->debugfs_dentry_glocks) {
			debugfs_remove(sdp->debugfs_dentry_glocks);
			sdp->debugfs_dentry_glocks = NULL;
		}
		if (sdp->debugfs_dentry_glstats) {
			debugfs_remove(sdp->debugfs_dentry_glstats);
			sdp->debugfs_dentry_glstats = NULL;
		}
		if (sdp->debugfs_dentry_sbstats) {
			debugfs_remove(sdp->debugfs_dentry_sbstats);
			sdp->debugfs_dentry_sbstats = NULL;
		}
		debugfs_remove(sdp->debugfs_dir);
		sdp->debugfs_dir = NULL;
	}
+44 −6
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <linux/rculist_bl.h>
#include <linux/completion.h>
#include <linux/rbtree.h>
#include <linux/ktime.h>
#include <linux/percpu.h>

#define DIO_WAIT	0x00000010
#define DIO_METADATA	0x00000020
@@ -204,6 +206,22 @@ struct gfs2_glock_operations {
#define GLOF_ASPACE 1
};

enum {
	GFS2_LKS_SRTT = 0,	/* Non blocking smoothed round trip time */
	GFS2_LKS_SRTTVAR = 1,	/* Non blocking smoothed variance */
	GFS2_LKS_SRTTB = 2,	/* Blocking smoothed round trip time */
	GFS2_LKS_SRTTVARB = 3,	/* Blocking smoothed variance */
	GFS2_LKS_SIRT = 4,	/* Smoothed Inter-request time */
	GFS2_LKS_SIRTVAR = 5,	/* Smoothed Inter-request variance */
	GFS2_LKS_DCOUNT = 6,	/* Count of dlm requests */
	GFS2_LKS_QCOUNT = 7,	/* Count of gfs2_holder queues */
	GFS2_NR_LKSTATS
};

struct gfs2_lkstats {
	s64 stats[GFS2_NR_LKSTATS];
};

enum {
	/* States */
	HIF_HOLDER		= 6,  /* Set for gh that "holds" the glock */
@@ -238,10 +256,12 @@ enum {
	GLF_QUEUED			= 12,
	GLF_LRU				= 13,
	GLF_OBJECT			= 14, /* Used only for tracing */
	GLF_BLOCKING			= 15,
};

struct gfs2_glock {
	struct hlist_bl_node gl_list;
	struct gfs2_sbd *gl_sbd;
	unsigned long gl_flags;		/* GLF_... */
	struct lm_lockname gl_name;
	atomic_t gl_ref;
@@ -261,16 +281,14 @@ struct gfs2_glock {
	struct list_head gl_holders;

	const struct gfs2_glock_operations *gl_ops;
	char gl_strname[GDLM_STRNAME_BYTES];
	ktime_t gl_dstamp;
	struct gfs2_lkstats gl_stats;
	struct dlm_lksb gl_lksb;
	char gl_lvb[32];
	unsigned long gl_tchange;
	void *gl_object;

	struct list_head gl_lru;

	struct gfs2_sbd *gl_sbd;

	struct list_head gl_ail_list;
	atomic_t gl_ail_count;
	atomic_t gl_revokes;
@@ -560,8 +578,14 @@ struct lm_lockstruct {
	uint32_t *ls_recover_result; /* result of last jid recovery */
};

struct gfs2_pcpu_lkstats {
	/* One struct for each glock type */
	struct gfs2_lkstats lkstats[10];
};

struct gfs2_sbd {
	struct super_block *sd_vfs;
	struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
	struct kobject sd_kobj;
	unsigned long sd_flags;	/* SDF_... */
	struct gfs2_sb_host sd_sb;
@@ -620,7 +644,6 @@ struct gfs2_sbd {

	int sd_rindex_uptodate;
	spinlock_t sd_rindex_spin;
	struct mutex sd_rindex_mutex;
	struct rb_root sd_rindex_tree;
	unsigned int sd_rgrps;
	unsigned int sd_max_rg_data;
@@ -725,8 +748,23 @@ struct gfs2_sbd {

	unsigned long sd_last_warning;
	struct dentry *debugfs_dir;    /* debugfs directory */
	struct dentry *debugfs_dentry_glocks; /* for debugfs */
	struct dentry *debugfs_dentry_glocks;
	struct dentry *debugfs_dentry_glstats;
	struct dentry *debugfs_dentry_sbstats;
};

static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which)
{
	gl->gl_stats.stats[which]++;
}

static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which)
{
	const struct gfs2_sbd *sdp = gl->gl_sbd;
	preempt_disable();
	this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++;
	preempt_enable();
}

#endif /* __INCORE_DOT_H__ */
+2 −2
Original line number Diff line number Diff line
@@ -1036,7 +1036,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);

	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
	rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
	if (!rgd)
		goto out_inodes;

@@ -1255,7 +1255,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
		 * this is the case of the target file already existing
		 * so we unlink before doing the rename
		 */
		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr);
		nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1);
		if (nrgd)
			gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
	}
Loading