mirror of https://gitee.com/openkylin/linux.git
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw
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
This commit is contained in:
commit
ad12ab259d
|
@ -60,7 +60,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
|
||||||
int release = 0;
|
int release = 0;
|
||||||
|
|
||||||
if (!page || page->index) {
|
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)
|
if (!page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
release = 1;
|
release = 1;
|
||||||
|
@ -930,7 +930,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
|
||||||
struct page *page;
|
struct page *page;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
page = grab_cache_page(mapping, index);
|
page = find_or_create_page(mapping, index, GFP_NOFS);
|
||||||
if (!page)
|
if (!page)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
return gfs2_get_flags(filp, (u32 __user *)arg);
|
||||||
case FS_IOC_SETFLAGS:
|
case FS_IOC_SETFLAGS:
|
||||||
return gfs2_set_flags(filp, (u32 __user *)arg);
|
return gfs2_set_flags(filp, (u32 __user *)arg);
|
||||||
|
case FITRIM:
|
||||||
|
return gfs2_fitrim(filp, (void __user *)arg);
|
||||||
}
|
}
|
||||||
return -ENOTTY;
|
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 gfs2_inode *ip = GFS2_I(inode);
|
||||||
struct buffer_head *dibh;
|
struct buffer_head *dibh;
|
||||||
int error;
|
int error;
|
||||||
|
loff_t size = len;
|
||||||
unsigned int nr_blks;
|
unsigned int nr_blks;
|
||||||
sector_t lblock = offset >> inode->i_blkbits;
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
|
if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
|
||||||
i_size_write(inode, offset + len);
|
i_size_write(inode, offset + size);
|
||||||
|
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
|
|
||||||
|
@ -777,12 +780,14 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
|
||||||
if (unlikely(error))
|
if (unlikely(error))
|
||||||
goto out_uninit;
|
goto out_uninit;
|
||||||
|
|
||||||
if (!gfs2_write_alloc_required(ip, offset, len))
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
if (len < bytes)
|
if (len < bytes)
|
||||||
bytes = len;
|
bytes = len;
|
||||||
|
if (!gfs2_write_alloc_required(ip, offset, bytes)) {
|
||||||
|
len -= bytes;
|
||||||
|
offset += bytes;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
qa = gfs2_qadata_get(ip);
|
qa = gfs2_qadata_get(ip);
|
||||||
if (!qa) {
|
if (!qa) {
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
|
|
210
fs/gfs2/glock.c
210
fs/gfs2/glock.c
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/rculist_bl.h>
|
#include <linux/rculist_bl.h>
|
||||||
#include <linux/bit_spinlock.h>
|
#include <linux/bit_spinlock.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
|
||||||
#include "gfs2.h"
|
#include "gfs2.h"
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
|
@ -543,6 +544,11 @@ __acquires(&gl->gl_spin)
|
||||||
do_error(gl, 0); /* Fail queued try locks */
|
do_error(gl, 0); /* Fail queued try locks */
|
||||||
}
|
}
|
||||||
gl->gl_req = target;
|
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);
|
spin_unlock(&gl->gl_spin);
|
||||||
if (glops->go_xmote_th)
|
if (glops->go_xmote_th)
|
||||||
glops->go_xmote_th(gl);
|
glops->go_xmote_th(gl);
|
||||||
|
@ -744,6 +750,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
atomic_inc(&sdp->sd_glock_disposal);
|
atomic_inc(&sdp->sd_glock_disposal);
|
||||||
|
gl->gl_sbd = sdp;
|
||||||
gl->gl_flags = 0;
|
gl->gl_flags = 0;
|
||||||
gl->gl_name = name;
|
gl->gl_name = name;
|
||||||
atomic_set(&gl->gl_ref, 1);
|
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_demote_state = LM_ST_EXCLUSIVE;
|
||||||
gl->gl_hash = hash;
|
gl->gl_hash = hash;
|
||||||
gl->gl_ops = glops;
|
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));
|
memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb));
|
||||||
gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
|
gl->gl_lksb.sb_lvbptr = gl->gl_lvb;
|
||||||
gl->gl_tchange = jiffies;
|
gl->gl_tchange = jiffies;
|
||||||
gl->gl_object = NULL;
|
gl->gl_object = NULL;
|
||||||
gl->gl_sbd = sdp;
|
|
||||||
gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
|
gl->gl_hold_time = GL_GLOCK_DFT_HOLD;
|
||||||
INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
|
INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
|
||||||
INIT_WORK(&gl->gl_delete, delete_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);
|
set_bit(GLF_QUEUED, &gl->gl_flags);
|
||||||
trace_gfs2_glock_queue(gh, 1);
|
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)) {
|
if (likely(insert_pt == NULL)) {
|
||||||
list_add_tail(&gh->gh_list, &gl->gl_holders);
|
list_add_tail(&gh->gh_list, &gl->gl_holders);
|
||||||
if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
|
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';
|
*p++ = 'L';
|
||||||
if (gl->gl_object)
|
if (gl->gl_object)
|
||||||
*p++ = 'o';
|
*p++ = 'o';
|
||||||
|
if (test_bit(GLF_BLOCKING, gflags))
|
||||||
|
*p++ = 'b';
|
||||||
*p = 0;
|
*p = 0;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -1714,8 +1730,78 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl)
|
||||||
return error;
|
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)
|
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);
|
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 = {
|
static const struct seq_operations gfs2_glock_seq_ops = {
|
||||||
.start = gfs2_glock_seq_start,
|
.start = gfs2_glock_seq_start,
|
||||||
.next = gfs2_glock_seq_next,
|
.next = gfs2_glock_seq_next,
|
||||||
|
@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = {
|
||||||
.show = gfs2_glock_seq_show,
|
.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,
|
int ret = seq_open_private(file, &gfs2_glock_seq_ops,
|
||||||
sizeof(struct gfs2_glock_iter));
|
sizeof(struct gfs2_glock_iter));
|
||||||
|
@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file)
|
||||||
return ret;
|
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,
|
.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,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = seq_release_private,
|
.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",
|
sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
|
||||||
S_IFREG | S_IRUGO,
|
S_IFREG | S_IRUGO,
|
||||||
sdp->debugfs_dir, sdp,
|
sdp->debugfs_dir, sdp,
|
||||||
&gfs2_debug_fops);
|
&gfs2_glocks_fops);
|
||||||
if (!sdp->debugfs_dentry_glocks)
|
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;
|
return 0;
|
||||||
|
fail:
|
||||||
|
gfs2_delete_debugfs_file(sdp);
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
|
void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
if (sdp && sdp->debugfs_dir) {
|
if (sdp->debugfs_dir) {
|
||||||
if (sdp->debugfs_dentry_glocks) {
|
if (sdp->debugfs_dentry_glocks) {
|
||||||
debugfs_remove(sdp->debugfs_dentry_glocks);
|
debugfs_remove(sdp->debugfs_dentry_glocks);
|
||||||
sdp->debugfs_dentry_glocks = NULL;
|
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);
|
debugfs_remove(sdp->debugfs_dir);
|
||||||
sdp->debugfs_dir = NULL;
|
sdp->debugfs_dir = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <linux/rculist_bl.h>
|
#include <linux/rculist_bl.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
|
#include <linux/percpu.h>
|
||||||
|
|
||||||
#define DIO_WAIT 0x00000010
|
#define DIO_WAIT 0x00000010
|
||||||
#define DIO_METADATA 0x00000020
|
#define DIO_METADATA 0x00000020
|
||||||
|
@ -204,6 +206,22 @@ struct gfs2_glock_operations {
|
||||||
#define GLOF_ASPACE 1
|
#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 {
|
enum {
|
||||||
/* States */
|
/* States */
|
||||||
HIF_HOLDER = 6, /* Set for gh that "holds" the glock */
|
HIF_HOLDER = 6, /* Set for gh that "holds" the glock */
|
||||||
|
@ -238,10 +256,12 @@ enum {
|
||||||
GLF_QUEUED = 12,
|
GLF_QUEUED = 12,
|
||||||
GLF_LRU = 13,
|
GLF_LRU = 13,
|
||||||
GLF_OBJECT = 14, /* Used only for tracing */
|
GLF_OBJECT = 14, /* Used only for tracing */
|
||||||
|
GLF_BLOCKING = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gfs2_glock {
|
struct gfs2_glock {
|
||||||
struct hlist_bl_node gl_list;
|
struct hlist_bl_node gl_list;
|
||||||
|
struct gfs2_sbd *gl_sbd;
|
||||||
unsigned long gl_flags; /* GLF_... */
|
unsigned long gl_flags; /* GLF_... */
|
||||||
struct lm_lockname gl_name;
|
struct lm_lockname gl_name;
|
||||||
atomic_t gl_ref;
|
atomic_t gl_ref;
|
||||||
|
@ -261,16 +281,14 @@ struct gfs2_glock {
|
||||||
struct list_head gl_holders;
|
struct list_head gl_holders;
|
||||||
|
|
||||||
const struct gfs2_glock_operations *gl_ops;
|
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;
|
struct dlm_lksb gl_lksb;
|
||||||
char gl_lvb[32];
|
char gl_lvb[32];
|
||||||
unsigned long gl_tchange;
|
unsigned long gl_tchange;
|
||||||
void *gl_object;
|
void *gl_object;
|
||||||
|
|
||||||
struct list_head gl_lru;
|
struct list_head gl_lru;
|
||||||
|
|
||||||
struct gfs2_sbd *gl_sbd;
|
|
||||||
|
|
||||||
struct list_head gl_ail_list;
|
struct list_head gl_ail_list;
|
||||||
atomic_t gl_ail_count;
|
atomic_t gl_ail_count;
|
||||||
atomic_t gl_revokes;
|
atomic_t gl_revokes;
|
||||||
|
@ -560,8 +578,14 @@ struct lm_lockstruct {
|
||||||
uint32_t *ls_recover_result; /* result of last jid recovery */
|
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 gfs2_sbd {
|
||||||
struct super_block *sd_vfs;
|
struct super_block *sd_vfs;
|
||||||
|
struct gfs2_pcpu_lkstats __percpu *sd_lkstats;
|
||||||
struct kobject sd_kobj;
|
struct kobject sd_kobj;
|
||||||
unsigned long sd_flags; /* SDF_... */
|
unsigned long sd_flags; /* SDF_... */
|
||||||
struct gfs2_sb_host sd_sb;
|
struct gfs2_sb_host sd_sb;
|
||||||
|
@ -620,7 +644,6 @@ struct gfs2_sbd {
|
||||||
|
|
||||||
int sd_rindex_uptodate;
|
int sd_rindex_uptodate;
|
||||||
spinlock_t sd_rindex_spin;
|
spinlock_t sd_rindex_spin;
|
||||||
struct mutex sd_rindex_mutex;
|
|
||||||
struct rb_root sd_rindex_tree;
|
struct rb_root sd_rindex_tree;
|
||||||
unsigned int sd_rgrps;
|
unsigned int sd_rgrps;
|
||||||
unsigned int sd_max_rg_data;
|
unsigned int sd_max_rg_data;
|
||||||
|
@ -725,8 +748,23 @@ struct gfs2_sbd {
|
||||||
|
|
||||||
unsigned long sd_last_warning;
|
unsigned long sd_last_warning;
|
||||||
struct dentry *debugfs_dir; /* debugfs directory */
|
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__ */
|
#endif /* __INCORE_DOT_H__ */
|
||||||
|
|
||||||
|
|
|
@ -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(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
|
||||||
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
|
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)
|
if (!rgd)
|
||||||
goto out_inodes;
|
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
|
* this is the case of the target file already existing
|
||||||
* so we unlink before doing the rename
|
* 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)
|
if (nrgd)
|
||||||
gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
|
gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,106 @@
|
||||||
#include "glock.h"
|
#include "glock.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
|
#include "trace_gfs2.h"
|
||||||
|
|
||||||
extern struct workqueue_struct *gfs2_control_wq;
|
extern struct workqueue_struct *gfs2_control_wq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_update_stats - Update time based stats
|
||||||
|
* @mv: Pointer to mean/variance structure to update
|
||||||
|
* @sample: New data to include
|
||||||
|
*
|
||||||
|
* @delta is the difference between the current rtt sample and the
|
||||||
|
* running average srtt. We add 1/8 of that to the srtt in order to
|
||||||
|
* update the current srtt estimate. The varience estimate is a bit
|
||||||
|
* more complicated. We subtract the abs value of the @delta from
|
||||||
|
* the current variance estimate and add 1/4 of that to the running
|
||||||
|
* total.
|
||||||
|
*
|
||||||
|
* Note that the index points at the array entry containing the smoothed
|
||||||
|
* mean value, and the variance is always in the following entry
|
||||||
|
*
|
||||||
|
* Reference: TCP/IP Illustrated, vol 2, p. 831,832
|
||||||
|
* All times are in units of integer nanoseconds. Unlike the TCP/IP case,
|
||||||
|
* they are not scaled fixed point.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index,
|
||||||
|
s64 sample)
|
||||||
|
{
|
||||||
|
s64 delta = sample - s->stats[index];
|
||||||
|
s->stats[index] += (delta >> 3);
|
||||||
|
index++;
|
||||||
|
s->stats[index] += ((abs64(delta) - s->stats[index]) >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_update_reply_times - Update locking statistics
|
||||||
|
* @gl: The glock to update
|
||||||
|
*
|
||||||
|
* This assumes that gl->gl_dstamp has been set earlier.
|
||||||
|
*
|
||||||
|
* The rtt (lock round trip time) is an estimate of the time
|
||||||
|
* taken to perform a dlm lock request. We update it on each
|
||||||
|
* reply from the dlm.
|
||||||
|
*
|
||||||
|
* The blocking flag is set on the glock for all dlm requests
|
||||||
|
* which may potentially block due to lock requests from other nodes.
|
||||||
|
* DLM requests where the current lock state is exclusive, the
|
||||||
|
* requested state is null (or unlocked) or where the TRY or
|
||||||
|
* TRY_1CB flags are set are classified as non-blocking. All
|
||||||
|
* other DLM requests are counted as (potentially) blocking.
|
||||||
|
*/
|
||||||
|
static inline void gfs2_update_reply_times(struct gfs2_glock *gl)
|
||||||
|
{
|
||||||
|
struct gfs2_pcpu_lkstats *lks;
|
||||||
|
const unsigned gltype = gl->gl_name.ln_type;
|
||||||
|
unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ?
|
||||||
|
GFS2_LKS_SRTTB : GFS2_LKS_SRTT;
|
||||||
|
s64 rtt;
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
|
rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp));
|
||||||
|
lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
|
||||||
|
gfs2_update_stats(&gl->gl_stats, index, rtt); /* Local */
|
||||||
|
gfs2_update_stats(&lks->lkstats[gltype], index, rtt); /* Global */
|
||||||
|
preempt_enable();
|
||||||
|
|
||||||
|
trace_gfs2_glock_lock_time(gl, rtt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_update_request_times - Update locking statistics
|
||||||
|
* @gl: The glock to update
|
||||||
|
*
|
||||||
|
* The irt (lock inter-request times) measures the average time
|
||||||
|
* between requests to the dlm. It is updated immediately before
|
||||||
|
* each dlm call.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline void gfs2_update_request_times(struct gfs2_glock *gl)
|
||||||
|
{
|
||||||
|
struct gfs2_pcpu_lkstats *lks;
|
||||||
|
const unsigned gltype = gl->gl_name.ln_type;
|
||||||
|
ktime_t dstamp;
|
||||||
|
s64 irt;
|
||||||
|
|
||||||
|
preempt_disable();
|
||||||
|
dstamp = gl->gl_dstamp;
|
||||||
|
gl->gl_dstamp = ktime_get_real();
|
||||||
|
irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp));
|
||||||
|
lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats);
|
||||||
|
gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt); /* Local */
|
||||||
|
gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt); /* Global */
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
static void gdlm_ast(void *arg)
|
static void gdlm_ast(void *arg)
|
||||||
{
|
{
|
||||||
struct gfs2_glock *gl = arg;
|
struct gfs2_glock *gl = arg;
|
||||||
unsigned ret = gl->gl_state;
|
unsigned ret = gl->gl_state;
|
||||||
|
|
||||||
|
gfs2_update_reply_times(gl);
|
||||||
BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
|
BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED);
|
||||||
|
|
||||||
if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
|
if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID)
|
||||||
|
@ -111,7 +203,7 @@ static int make_mode(const unsigned int lmstate)
|
||||||
static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
|
static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
|
||||||
const int req)
|
const int req)
|
||||||
{
|
{
|
||||||
u32 lkf = 0;
|
u32 lkf = DLM_LKF_VALBLK;
|
||||||
|
|
||||||
if (gfs_flags & LM_FLAG_TRY)
|
if (gfs_flags & LM_FLAG_TRY)
|
||||||
lkf |= DLM_LKF_NOQUEUE;
|
lkf |= DLM_LKF_NOQUEUE;
|
||||||
|
@ -138,26 +230,43 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags,
|
||||||
if (lkid != 0)
|
if (lkid != 0)
|
||||||
lkf |= DLM_LKF_CONVERT;
|
lkf |= DLM_LKF_CONVERT;
|
||||||
|
|
||||||
lkf |= DLM_LKF_VALBLK;
|
|
||||||
|
|
||||||
return lkf;
|
return lkf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gfs2_reverse_hex(char *c, u64 value)
|
||||||
|
{
|
||||||
|
while (value) {
|
||||||
|
*c-- = hex_asc[value & 0x0f];
|
||||||
|
value >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
|
static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
|
struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct;
|
||||||
int req;
|
int req;
|
||||||
u32 lkf;
|
u32 lkf;
|
||||||
|
char strname[GDLM_STRNAME_BYTES] = "";
|
||||||
|
|
||||||
req = make_mode(req_state);
|
req = make_mode(req_state);
|
||||||
lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
|
lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req);
|
||||||
|
gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
|
||||||
|
gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
|
||||||
|
if (gl->gl_lksb.sb_lkid) {
|
||||||
|
gfs2_update_request_times(gl);
|
||||||
|
} else {
|
||||||
|
memset(strname, ' ', GDLM_STRNAME_BYTES - 1);
|
||||||
|
strname[GDLM_STRNAME_BYTES - 1] = '\0';
|
||||||
|
gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type);
|
||||||
|
gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number);
|
||||||
|
gl->gl_dstamp = ktime_get_real();
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Submit the actual lock request.
|
* Submit the actual lock request.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname,
|
return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname,
|
||||||
GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
|
GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,6 +281,10 @@ static void gdlm_put_lock(struct gfs2_glock *gl)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clear_bit(GLF_BLOCKING, &gl->gl_flags);
|
||||||
|
gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
|
||||||
|
gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
|
||||||
|
gfs2_update_request_times(gl);
|
||||||
error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
|
error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
|
||||||
NULL, gl);
|
NULL, gl);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
244
fs/gfs2/log.c
244
fs/gfs2/log.c
|
@ -19,6 +19,7 @@
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
|
#include <linux/list_sort.h>
|
||||||
|
|
||||||
#include "gfs2.h"
|
#include "gfs2.h"
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
|
@ -358,7 +359,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
|
u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
|
||||||
{
|
{
|
||||||
struct gfs2_journal_extent *je;
|
struct gfs2_journal_extent *je;
|
||||||
|
|
||||||
|
@ -467,8 +468,8 @@ static unsigned int current_tail(struct gfs2_sbd *sdp)
|
||||||
|
|
||||||
void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
if (sdp->sd_log_flush_head == sdp->sd_log_tail)
|
BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) &&
|
||||||
BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
|
(sdp->sd_log_flush_head != sdp->sd_log_head));
|
||||||
|
|
||||||
if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
|
if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
|
||||||
sdp->sd_log_flush_head = 0;
|
sdp->sd_log_flush_head = 0;
|
||||||
|
@ -476,99 +477,6 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_log_write_endio - End of I/O for a log buffer
|
|
||||||
* @bh: The buffer head
|
|
||||||
* @uptodate: I/O Status
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
|
|
||||||
{
|
|
||||||
struct gfs2_sbd *sdp = bh->b_private;
|
|
||||||
bh->b_private = NULL;
|
|
||||||
|
|
||||||
end_buffer_write_sync(bh, uptodate);
|
|
||||||
if (atomic_dec_and_test(&sdp->sd_log_in_flight))
|
|
||||||
wake_up(&sdp->sd_log_flush_wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_log_get_buf - Get and initialize a buffer to use for log control data
|
|
||||||
* @sdp: The GFS2 superblock
|
|
||||||
*
|
|
||||||
* Returns: the buffer_head
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
|
|
||||||
{
|
|
||||||
u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
|
|
||||||
struct buffer_head *bh;
|
|
||||||
|
|
||||||
bh = sb_getblk(sdp->sd_vfs, blkno);
|
|
||||||
lock_buffer(bh);
|
|
||||||
memset(bh->b_data, 0, bh->b_size);
|
|
||||||
set_buffer_uptodate(bh);
|
|
||||||
clear_buffer_dirty(bh);
|
|
||||||
gfs2_log_incr_head(sdp);
|
|
||||||
atomic_inc(&sdp->sd_log_in_flight);
|
|
||||||
bh->b_private = sdp;
|
|
||||||
bh->b_end_io = gfs2_log_write_endio;
|
|
||||||
|
|
||||||
return bh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_fake_write_endio -
|
|
||||||
* @bh: The buffer head
|
|
||||||
* @uptodate: The I/O Status
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
|
|
||||||
{
|
|
||||||
struct buffer_head *real_bh = bh->b_private;
|
|
||||||
struct gfs2_bufdata *bd = real_bh->b_private;
|
|
||||||
struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
|
|
||||||
|
|
||||||
end_buffer_write_sync(bh, uptodate);
|
|
||||||
free_buffer_head(bh);
|
|
||||||
unlock_buffer(real_bh);
|
|
||||||
brelse(real_bh);
|
|
||||||
if (atomic_dec_and_test(&sdp->sd_log_in_flight))
|
|
||||||
wake_up(&sdp->sd_log_flush_wait);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
|
|
||||||
* @sdp: the filesystem
|
|
||||||
* @data: the data the buffer_head should point to
|
|
||||||
*
|
|
||||||
* Returns: the log buffer descriptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
|
||||||
struct buffer_head *real)
|
|
||||||
{
|
|
||||||
u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
|
|
||||||
struct buffer_head *bh;
|
|
||||||
|
|
||||||
bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
|
|
||||||
atomic_set(&bh->b_count, 1);
|
|
||||||
bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
|
|
||||||
set_bh_page(bh, real->b_page, bh_offset(real));
|
|
||||||
bh->b_blocknr = blkno;
|
|
||||||
bh->b_size = sdp->sd_sb.sb_bsize;
|
|
||||||
bh->b_bdev = sdp->sd_vfs->s_bdev;
|
|
||||||
bh->b_private = real;
|
|
||||||
bh->b_end_io = gfs2_fake_write_endio;
|
|
||||||
|
|
||||||
gfs2_log_incr_head(sdp);
|
|
||||||
atomic_inc(&sdp->sd_log_in_flight);
|
|
||||||
|
|
||||||
return bh;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
|
static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
|
||||||
{
|
{
|
||||||
unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
|
unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
|
||||||
|
@ -583,66 +491,8 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail)
|
||||||
sdp->sd_log_tail = new_tail;
|
sdp->sd_log_tail = new_tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* log_write_header - Get and initialize a journal header buffer
|
|
||||||
* @sdp: The GFS2 superblock
|
|
||||||
*
|
|
||||||
* Returns: the initialized log buffer descriptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
|
static void log_flush_wait(struct gfs2_sbd *sdp)
|
||||||
{
|
|
||||||
u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
|
|
||||||
struct buffer_head *bh;
|
|
||||||
struct gfs2_log_header *lh;
|
|
||||||
unsigned int tail;
|
|
||||||
u32 hash;
|
|
||||||
|
|
||||||
bh = sb_getblk(sdp->sd_vfs, blkno);
|
|
||||||
lock_buffer(bh);
|
|
||||||
memset(bh->b_data, 0, bh->b_size);
|
|
||||||
set_buffer_uptodate(bh);
|
|
||||||
clear_buffer_dirty(bh);
|
|
||||||
|
|
||||||
gfs2_ail1_empty(sdp);
|
|
||||||
tail = current_tail(sdp);
|
|
||||||
|
|
||||||
lh = (struct gfs2_log_header *)bh->b_data;
|
|
||||||
memset(lh, 0, sizeof(struct gfs2_log_header));
|
|
||||||
lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
|
|
||||||
lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
|
|
||||||
lh->lh_header.__pad0 = cpu_to_be64(0);
|
|
||||||
lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
|
|
||||||
lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
|
|
||||||
lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
|
|
||||||
lh->lh_flags = cpu_to_be32(flags);
|
|
||||||
lh->lh_tail = cpu_to_be32(tail);
|
|
||||||
lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
|
|
||||||
hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
|
|
||||||
lh->lh_hash = cpu_to_be32(hash);
|
|
||||||
|
|
||||||
bh->b_end_io = end_buffer_write_sync;
|
|
||||||
get_bh(bh);
|
|
||||||
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
|
|
||||||
submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
|
|
||||||
else
|
|
||||||
submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
|
|
||||||
wait_on_buffer(bh);
|
|
||||||
|
|
||||||
if (!buffer_uptodate(bh))
|
|
||||||
gfs2_io_error_bh(sdp, bh);
|
|
||||||
brelse(bh);
|
|
||||||
|
|
||||||
if (sdp->sd_log_tail != tail)
|
|
||||||
log_pull_tail(sdp, tail);
|
|
||||||
else
|
|
||||||
gfs2_assert_withdraw(sdp, !pull);
|
|
||||||
|
|
||||||
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
|
|
||||||
gfs2_log_incr_head(sdp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void log_flush_commit(struct gfs2_sbd *sdp)
|
|
||||||
{
|
{
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT(wait);
|
||||||
|
|
||||||
|
@ -655,8 +505,20 @@ static void log_flush_commit(struct gfs2_sbd *sdp)
|
||||||
} while(atomic_read(&sdp->sd_log_in_flight));
|
} while(atomic_read(&sdp->sd_log_in_flight));
|
||||||
finish_wait(&sdp->sd_log_flush_wait, &wait);
|
finish_wait(&sdp->sd_log_flush_wait, &wait);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log_write_header(sdp, 0, 0);
|
static int bd_cmp(void *priv, struct list_head *a, struct list_head *b)
|
||||||
|
{
|
||||||
|
struct gfs2_bufdata *bda, *bdb;
|
||||||
|
|
||||||
|
bda = list_entry(a, struct gfs2_bufdata, bd_le.le_list);
|
||||||
|
bdb = list_entry(b, struct gfs2_bufdata, bd_le.le_list);
|
||||||
|
|
||||||
|
if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr)
|
||||||
|
return -1;
|
||||||
|
if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfs2_ordered_write(struct gfs2_sbd *sdp)
|
static void gfs2_ordered_write(struct gfs2_sbd *sdp)
|
||||||
|
@ -666,6 +528,7 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp)
|
||||||
LIST_HEAD(written);
|
LIST_HEAD(written);
|
||||||
|
|
||||||
gfs2_log_lock(sdp);
|
gfs2_log_lock(sdp);
|
||||||
|
list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp);
|
||||||
while (!list_empty(&sdp->sd_log_le_ordered)) {
|
while (!list_empty(&sdp->sd_log_le_ordered)) {
|
||||||
bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
|
bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
|
||||||
list_move(&bd->bd_le.le_list, &written);
|
list_move(&bd->bd_le.le_list, &written);
|
||||||
|
@ -710,6 +573,68 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
|
||||||
gfs2_log_unlock(sdp);
|
gfs2_log_unlock(sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log_write_header - Get and initialize a journal header buffer
|
||||||
|
* @sdp: The GFS2 superblock
|
||||||
|
*
|
||||||
|
* Returns: the initialized log buffer descriptor
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
|
||||||
|
{
|
||||||
|
u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
|
||||||
|
struct buffer_head *bh;
|
||||||
|
struct gfs2_log_header *lh;
|
||||||
|
unsigned int tail;
|
||||||
|
u32 hash;
|
||||||
|
|
||||||
|
bh = sb_getblk(sdp->sd_vfs, blkno);
|
||||||
|
lock_buffer(bh);
|
||||||
|
memset(bh->b_data, 0, bh->b_size);
|
||||||
|
set_buffer_uptodate(bh);
|
||||||
|
clear_buffer_dirty(bh);
|
||||||
|
|
||||||
|
gfs2_ail1_empty(sdp);
|
||||||
|
tail = current_tail(sdp);
|
||||||
|
|
||||||
|
lh = (struct gfs2_log_header *)bh->b_data;
|
||||||
|
memset(lh, 0, sizeof(struct gfs2_log_header));
|
||||||
|
lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
|
||||||
|
lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
|
||||||
|
lh->lh_header.__pad0 = cpu_to_be64(0);
|
||||||
|
lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
|
||||||
|
lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
|
||||||
|
lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
|
||||||
|
lh->lh_flags = cpu_to_be32(flags);
|
||||||
|
lh->lh_tail = cpu_to_be32(tail);
|
||||||
|
lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
|
||||||
|
hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
|
||||||
|
lh->lh_hash = cpu_to_be32(hash);
|
||||||
|
|
||||||
|
bh->b_end_io = end_buffer_write_sync;
|
||||||
|
get_bh(bh);
|
||||||
|
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
|
||||||
|
gfs2_ordered_wait(sdp);
|
||||||
|
log_flush_wait(sdp);
|
||||||
|
submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh);
|
||||||
|
} else {
|
||||||
|
submit_bh(WRITE_FLUSH_FUA | REQ_META, bh);
|
||||||
|
}
|
||||||
|
wait_on_buffer(bh);
|
||||||
|
|
||||||
|
if (!buffer_uptodate(bh))
|
||||||
|
gfs2_io_error_bh(sdp, bh);
|
||||||
|
brelse(bh);
|
||||||
|
|
||||||
|
if (sdp->sd_log_tail != tail)
|
||||||
|
log_pull_tail(sdp, tail);
|
||||||
|
else
|
||||||
|
gfs2_assert_withdraw(sdp, !pull);
|
||||||
|
|
||||||
|
sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
|
||||||
|
gfs2_log_incr_head(sdp);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gfs2_log_flush - flush incore transaction(s)
|
* gfs2_log_flush - flush incore transaction(s)
|
||||||
* @sdp: the filesystem
|
* @sdp: the filesystem
|
||||||
|
@ -753,11 +678,10 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
|
||||||
|
|
||||||
gfs2_ordered_write(sdp);
|
gfs2_ordered_write(sdp);
|
||||||
lops_before_commit(sdp);
|
lops_before_commit(sdp);
|
||||||
gfs2_ordered_wait(sdp);
|
|
||||||
|
|
||||||
if (sdp->sd_log_head != sdp->sd_log_flush_head)
|
if (sdp->sd_log_head != sdp->sd_log_flush_head) {
|
||||||
log_flush_commit(sdp);
|
log_write_header(sdp, 0, 0);
|
||||||
else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
|
} else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
|
||||||
gfs2_log_lock(sdp);
|
gfs2_log_lock(sdp);
|
||||||
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
|
atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */
|
||||||
trace_gfs2_log_blocks(sdp, -1);
|
trace_gfs2_log_blocks(sdp, -1);
|
||||||
|
|
|
@ -53,10 +53,7 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
|
||||||
|
|
||||||
extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
|
extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
|
||||||
extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
|
extern void gfs2_log_incr_head(struct gfs2_sbd *sdp);
|
||||||
|
extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn);
|
||||||
extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
|
|
||||||
extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
|
||||||
struct buffer_head *real);
|
|
||||||
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
|
extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
|
||||||
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
|
extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
|
||||||
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
|
extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
|
#include <linux/mempool.h>
|
||||||
#include <linux/gfs2_ondisk.h>
|
#include <linux/gfs2_ondisk.h>
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
@ -76,7 +77,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd)
|
||||||
if (bi->bi_clone == 0)
|
if (bi->bi_clone == 0)
|
||||||
return;
|
return;
|
||||||
if (sdp->sd_args.ar_discard)
|
if (sdp->sd_args.ar_discard)
|
||||||
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi);
|
gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL);
|
||||||
memcpy(bi->bi_clone + bi->bi_offset,
|
memcpy(bi->bi_clone + bi->bi_offset,
|
||||||
bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
|
bd->bd_bh->b_data + bi->bi_offset, bi->bi_len);
|
||||||
clear_bit(GBF_FULL, &bi->bi_flags);
|
clear_bit(GBF_FULL, &bi->bi_flags);
|
||||||
|
@ -143,6 +144,98 @@ static inline __be64 *bh_ptr_end(struct buffer_head *bh)
|
||||||
return (__force __be64 *)(bh->b_data + bh->b_size);
|
return (__force __be64 *)(bh->b_data + bh->b_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_log_write_endio - End of I/O for a log buffer
|
||||||
|
* @bh: The buffer head
|
||||||
|
* @uptodate: I/O Status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
|
||||||
|
{
|
||||||
|
struct gfs2_sbd *sdp = bh->b_private;
|
||||||
|
bh->b_private = NULL;
|
||||||
|
|
||||||
|
end_buffer_write_sync(bh, uptodate);
|
||||||
|
if (atomic_dec_and_test(&sdp->sd_log_in_flight))
|
||||||
|
wake_up(&sdp->sd_log_flush_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_log_get_buf - Get and initialize a buffer to use for log control data
|
||||||
|
* @sdp: The GFS2 superblock
|
||||||
|
*
|
||||||
|
* tReturns: the buffer_head
|
||||||
|
*/
|
||||||
|
|
||||||
|
static struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
|
||||||
|
{
|
||||||
|
u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
|
||||||
|
struct buffer_head *bh;
|
||||||
|
|
||||||
|
bh = sb_getblk(sdp->sd_vfs, blkno);
|
||||||
|
lock_buffer(bh);
|
||||||
|
memset(bh->b_data, 0, bh->b_size);
|
||||||
|
set_buffer_uptodate(bh);
|
||||||
|
clear_buffer_dirty(bh);
|
||||||
|
gfs2_log_incr_head(sdp);
|
||||||
|
atomic_inc(&sdp->sd_log_in_flight);
|
||||||
|
bh->b_private = sdp;
|
||||||
|
bh->b_end_io = gfs2_log_write_endio;
|
||||||
|
|
||||||
|
return bh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_fake_write_endio -
|
||||||
|
* @bh: The buffer head
|
||||||
|
* @uptodate: The I/O Status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
|
||||||
|
{
|
||||||
|
struct buffer_head *real_bh = bh->b_private;
|
||||||
|
struct gfs2_bufdata *bd = real_bh->b_private;
|
||||||
|
struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
|
||||||
|
|
||||||
|
end_buffer_write_sync(bh, uptodate);
|
||||||
|
mempool_free(bh, gfs2_bh_pool);
|
||||||
|
unlock_buffer(real_bh);
|
||||||
|
brelse(real_bh);
|
||||||
|
if (atomic_dec_and_test(&sdp->sd_log_in_flight))
|
||||||
|
wake_up(&sdp->sd_log_flush_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
|
||||||
|
* @sdp: the filesystem
|
||||||
|
* @data: the data the buffer_head should point to
|
||||||
|
*
|
||||||
|
* Returns: the log buffer descriptor
|
||||||
|
*/
|
||||||
|
|
||||||
|
static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
|
||||||
|
struct buffer_head *real)
|
||||||
|
{
|
||||||
|
u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head);
|
||||||
|
struct buffer_head *bh;
|
||||||
|
|
||||||
|
bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS);
|
||||||
|
atomic_set(&bh->b_count, 1);
|
||||||
|
bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
|
||||||
|
set_bh_page(bh, real->b_page, bh_offset(real));
|
||||||
|
bh->b_blocknr = blkno;
|
||||||
|
bh->b_size = sdp->sd_sb.sb_bsize;
|
||||||
|
bh->b_bdev = sdp->sd_vfs->s_bdev;
|
||||||
|
bh->b_private = real;
|
||||||
|
bh->b_end_io = gfs2_fake_write_endio;
|
||||||
|
|
||||||
|
gfs2_log_incr_head(sdp);
|
||||||
|
atomic_inc(&sdp->sd_log_in_flight);
|
||||||
|
|
||||||
|
return bh;
|
||||||
|
}
|
||||||
|
|
||||||
static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
|
static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/rculist_bl.h>
|
#include <linux/rculist_bl.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/mempool.h>
|
||||||
|
|
||||||
#include "gfs2.h"
|
#include "gfs2.h"
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
|
@ -69,6 +70,16 @@ static void gfs2_init_gl_aspace_once(void *foo)
|
||||||
address_space_init_once(mapping);
|
address_space_init_once(mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *gfs2_bh_alloc(gfp_t mask, void *data)
|
||||||
|
{
|
||||||
|
return alloc_buffer_head(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gfs2_bh_free(void *ptr, void *data)
|
||||||
|
{
|
||||||
|
return free_buffer_head(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init_gfs2_fs - Register GFS2 as a filesystem
|
* init_gfs2_fs - Register GFS2 as a filesystem
|
||||||
*
|
*
|
||||||
|
@ -151,6 +162,10 @@ static int __init init_gfs2_fs(void)
|
||||||
gfs2_control_wq = alloc_workqueue("gfs2_control",
|
gfs2_control_wq = alloc_workqueue("gfs2_control",
|
||||||
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
|
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0);
|
||||||
if (!gfs2_control_wq)
|
if (!gfs2_control_wq)
|
||||||
|
goto fail_recovery;
|
||||||
|
|
||||||
|
gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL);
|
||||||
|
if (!gfs2_bh_pool)
|
||||||
goto fail_control;
|
goto fail_control;
|
||||||
|
|
||||||
gfs2_register_debugfs();
|
gfs2_register_debugfs();
|
||||||
|
@ -160,6 +175,8 @@ static int __init init_gfs2_fs(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_control:
|
fail_control:
|
||||||
|
destroy_workqueue(gfs2_control_wq);
|
||||||
|
fail_recovery:
|
||||||
destroy_workqueue(gfs_recovery_wq);
|
destroy_workqueue(gfs_recovery_wq);
|
||||||
fail_wq:
|
fail_wq:
|
||||||
unregister_filesystem(&gfs2meta_fs_type);
|
unregister_filesystem(&gfs2meta_fs_type);
|
||||||
|
@ -208,6 +225,7 @@ static void __exit exit_gfs2_fs(void)
|
||||||
|
|
||||||
rcu_barrier();
|
rcu_barrier();
|
||||||
|
|
||||||
|
mempool_destroy(gfs2_bh_pool);
|
||||||
kmem_cache_destroy(gfs2_quotad_cachep);
|
kmem_cache_destroy(gfs2_quotad_cachep);
|
||||||
kmem_cache_destroy(gfs2_rgrpd_cachep);
|
kmem_cache_destroy(gfs2_rgrpd_cachep);
|
||||||
kmem_cache_destroy(gfs2_bufdata_cachep);
|
kmem_cache_destroy(gfs2_bufdata_cachep);
|
||||||
|
|
|
@ -68,6 +68,12 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
||||||
|
|
||||||
sb->s_fs_info = sdp;
|
sb->s_fs_info = sdp;
|
||||||
sdp->sd_vfs = sb;
|
sdp->sd_vfs = sb;
|
||||||
|
sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats);
|
||||||
|
if (!sdp->sd_lkstats) {
|
||||||
|
kfree(sdp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
|
set_bit(SDF_NOJOURNALID, &sdp->sd_flags);
|
||||||
gfs2_tune_init(&sdp->sd_tune);
|
gfs2_tune_init(&sdp->sd_tune);
|
||||||
|
|
||||||
|
@ -77,7 +83,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
|
||||||
spin_lock_init(&sdp->sd_statfs_spin);
|
spin_lock_init(&sdp->sd_statfs_spin);
|
||||||
|
|
||||||
spin_lock_init(&sdp->sd_rindex_spin);
|
spin_lock_init(&sdp->sd_rindex_spin);
|
||||||
mutex_init(&sdp->sd_rindex_mutex);
|
|
||||||
sdp->sd_rindex_tree.rb_node = NULL;
|
sdp->sd_rindex_tree.rb_node = NULL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&sdp->sd_jindex_list);
|
INIT_LIST_HEAD(&sdp->sd_jindex_list);
|
||||||
|
@ -1220,6 +1225,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
|
||||||
gfs2_sys_fs_del(sdp);
|
gfs2_sys_fs_del(sdp);
|
||||||
fail:
|
fail:
|
||||||
gfs2_delete_debugfs_file(sdp);
|
gfs2_delete_debugfs_file(sdp);
|
||||||
|
free_percpu(sdp->sd_lkstats);
|
||||||
kfree(sdp);
|
kfree(sdp);
|
||||||
sb->s_fs_info = NULL;
|
sb->s_fs_info = NULL;
|
||||||
return error;
|
return error;
|
||||||
|
@ -1392,6 +1398,7 @@ static void gfs2_kill_sb(struct super_block *sb)
|
||||||
shrink_dcache_sb(sb);
|
shrink_dcache_sb(sb);
|
||||||
kill_block_super(sb);
|
kill_block_super(sb);
|
||||||
gfs2_delete_debugfs_file(sdp);
|
gfs2_delete_debugfs_file(sdp);
|
||||||
|
free_percpu(sdp->sd_lkstats);
|
||||||
kfree(sdp);
|
kfree(sdp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -681,7 +681,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
|
||||||
ptr = qp;
|
ptr = qp;
|
||||||
nbytes = sizeof(struct gfs2_quota);
|
nbytes = sizeof(struct gfs2_quota);
|
||||||
get_a_page:
|
get_a_page:
|
||||||
page = grab_cache_page(mapping, index);
|
page = find_or_create_page(mapping, index, GFP_NOFS);
|
||||||
if (!page)
|
if (!page)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
|
189
fs/gfs2/rgrp.c
189
fs/gfs2/rgrp.c
|
@ -327,23 +327,34 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block)
|
||||||
* Returns: The resource group, or NULL if not found
|
* Returns: The resource group, or NULL if not found
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
|
struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact)
|
||||||
{
|
{
|
||||||
struct rb_node **newn;
|
struct rb_node *n, *next;
|
||||||
struct gfs2_rgrpd *cur;
|
struct gfs2_rgrpd *cur;
|
||||||
|
|
||||||
|
if (gfs2_rindex_update(sdp))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
spin_lock(&sdp->sd_rindex_spin);
|
spin_lock(&sdp->sd_rindex_spin);
|
||||||
newn = &sdp->sd_rindex_tree.rb_node;
|
n = sdp->sd_rindex_tree.rb_node;
|
||||||
while (*newn) {
|
while (n) {
|
||||||
cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node);
|
cur = rb_entry(n, struct gfs2_rgrpd, rd_node);
|
||||||
|
next = NULL;
|
||||||
if (blk < cur->rd_addr)
|
if (blk < cur->rd_addr)
|
||||||
newn = &((*newn)->rb_left);
|
next = n->rb_left;
|
||||||
else if (blk >= cur->rd_data0 + cur->rd_data)
|
else if (blk >= cur->rd_data0 + cur->rd_data)
|
||||||
newn = &((*newn)->rb_right);
|
next = n->rb_right;
|
||||||
else {
|
if (next == NULL) {
|
||||||
spin_unlock(&sdp->sd_rindex_spin);
|
spin_unlock(&sdp->sd_rindex_spin);
|
||||||
|
if (exact) {
|
||||||
|
if (blk < cur->rd_addr)
|
||||||
|
return NULL;
|
||||||
|
if (blk >= cur->rd_data0 + cur->rd_data)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
n = next;
|
||||||
}
|
}
|
||||||
spin_unlock(&sdp->sd_rindex_spin);
|
spin_unlock(&sdp->sd_rindex_spin);
|
||||||
|
|
||||||
|
@ -532,7 +543,6 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
|
||||||
struct file_ra_state ra_state;
|
struct file_ra_state ra_state;
|
||||||
int error, rgrps;
|
int error, rgrps;
|
||||||
|
|
||||||
mutex_lock(&sdp->sd_rindex_mutex);
|
|
||||||
file_ra_state_init(&ra_state, inode->i_mapping);
|
file_ra_state_init(&ra_state, inode->i_mapping);
|
||||||
for (rgrps = 0;; rgrps++) {
|
for (rgrps = 0;; rgrps++) {
|
||||||
loff_t pos = rgrps * sizeof(struct gfs2_rindex);
|
loff_t pos = rgrps * sizeof(struct gfs2_rindex);
|
||||||
|
@ -545,11 +555,10 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
|
||||||
break;
|
break;
|
||||||
total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data);
|
total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data);
|
||||||
}
|
}
|
||||||
mutex_unlock(&sdp->sd_rindex_mutex);
|
|
||||||
return total_data;
|
return total_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rgd_insert(struct gfs2_rgrpd *rgd)
|
static int rgd_insert(struct gfs2_rgrpd *rgd)
|
||||||
{
|
{
|
||||||
struct gfs2_sbd *sdp = rgd->rd_sbd;
|
struct gfs2_sbd *sdp = rgd->rd_sbd;
|
||||||
struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
|
struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL;
|
||||||
|
@ -565,11 +574,13 @@ static void rgd_insert(struct gfs2_rgrpd *rgd)
|
||||||
else if (rgd->rd_addr > cur->rd_addr)
|
else if (rgd->rd_addr > cur->rd_addr)
|
||||||
newn = &((*newn)->rb_right);
|
newn = &((*newn)->rb_right);
|
||||||
else
|
else
|
||||||
return;
|
return -EEXIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_link_node(&rgd->rd_node, parent, newn);
|
rb_link_node(&rgd->rd_node, parent, newn);
|
||||||
rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
|
rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree);
|
||||||
|
sdp->sd_rgrps++;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -623,10 +634,12 @@ static int read_rindex_entry(struct gfs2_inode *ip,
|
||||||
if (rgd->rd_data > sdp->sd_max_rg_data)
|
if (rgd->rd_data > sdp->sd_max_rg_data)
|
||||||
sdp->sd_max_rg_data = rgd->rd_data;
|
sdp->sd_max_rg_data = rgd->rd_data;
|
||||||
spin_lock(&sdp->sd_rindex_spin);
|
spin_lock(&sdp->sd_rindex_spin);
|
||||||
rgd_insert(rgd);
|
error = rgd_insert(rgd);
|
||||||
sdp->sd_rgrps++;
|
|
||||||
spin_unlock(&sdp->sd_rindex_spin);
|
spin_unlock(&sdp->sd_rindex_spin);
|
||||||
return error;
|
if (!error)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error = 0; /* someone else read in the rgrp; free it and ignore it */
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
kfree(rgd->rd_bits);
|
kfree(rgd->rd_bits);
|
||||||
|
@ -687,7 +700,6 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp)
|
||||||
|
|
||||||
/* Read new copy from disk if we don't have the latest */
|
/* Read new copy from disk if we don't have the latest */
|
||||||
if (!sdp->sd_rindex_uptodate) {
|
if (!sdp->sd_rindex_uptodate) {
|
||||||
mutex_lock(&sdp->sd_rindex_mutex);
|
|
||||||
if (!gfs2_glock_is_locked_by_me(gl)) {
|
if (!gfs2_glock_is_locked_by_me(gl)) {
|
||||||
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
|
error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -698,10 +710,8 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp)
|
||||||
error = gfs2_ri_update(ip);
|
error = gfs2_ri_update(ip);
|
||||||
if (unlock_required)
|
if (unlock_required)
|
||||||
gfs2_glock_dq_uninit(&ri_gh);
|
gfs2_glock_dq_uninit(&ri_gh);
|
||||||
mutex_unlock(&sdp->sd_rindex_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,9 +820,9 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||||
struct buffer_head *bh,
|
struct buffer_head *bh,
|
||||||
const struct gfs2_bitmap *bi)
|
const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
|
||||||
{
|
{
|
||||||
struct super_block *sb = sdp->sd_vfs;
|
struct super_block *sb = sdp->sd_vfs;
|
||||||
struct block_device *bdev = sb->s_bdev;
|
struct block_device *bdev = sb->s_bdev;
|
||||||
|
@ -823,11 +833,19 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||||
sector_t nr_sects = 0;
|
sector_t nr_sects = 0;
|
||||||
int rv;
|
int rv;
|
||||||
unsigned int x;
|
unsigned int x;
|
||||||
|
u32 trimmed = 0;
|
||||||
|
u8 diff;
|
||||||
|
|
||||||
for (x = 0; x < bi->bi_len; x++) {
|
for (x = 0; x < bi->bi_len; x++) {
|
||||||
const u8 *orig = bh->b_data + bi->bi_offset + x;
|
const u8 *clone = bi->bi_clone ? bi->bi_clone : bi->bi_bh->b_data;
|
||||||
const u8 *clone = bi->bi_clone + bi->bi_offset + x;
|
clone += bi->bi_offset;
|
||||||
u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
|
clone += x;
|
||||||
|
if (bh) {
|
||||||
|
const u8 *orig = bh->b_data + bi->bi_offset + x;
|
||||||
|
diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1));
|
||||||
|
} else {
|
||||||
|
diff = ~(*clone | (*clone >> 1));
|
||||||
|
}
|
||||||
diff &= 0x55;
|
diff &= 0x55;
|
||||||
if (diff == 0)
|
if (diff == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -838,11 +856,14 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||||
if (nr_sects == 0)
|
if (nr_sects == 0)
|
||||||
goto start_new_extent;
|
goto start_new_extent;
|
||||||
if ((start + nr_sects) != blk) {
|
if ((start + nr_sects) != blk) {
|
||||||
rv = blkdev_issue_discard(bdev, start,
|
if (nr_sects >= minlen) {
|
||||||
nr_sects, GFP_NOFS,
|
rv = blkdev_issue_discard(bdev,
|
||||||
0);
|
start, nr_sects,
|
||||||
if (rv)
|
GFP_NOFS, 0);
|
||||||
goto fail;
|
if (rv)
|
||||||
|
goto fail;
|
||||||
|
trimmed += nr_sects;
|
||||||
|
}
|
||||||
nr_sects = 0;
|
nr_sects = 0;
|
||||||
start_new_extent:
|
start_new_extent:
|
||||||
start = blk;
|
start = blk;
|
||||||
|
@ -853,15 +874,104 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||||
blk += sects_per_blk;
|
blk += sects_per_blk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nr_sects) {
|
if (nr_sects >= minlen) {
|
||||||
rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
|
rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
|
||||||
if (rv)
|
if (rv)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
trimmed += nr_sects;
|
||||||
}
|
}
|
||||||
return;
|
if (ptrimmed)
|
||||||
|
*ptrimmed = trimmed;
|
||||||
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
|
if (sdp->sd_args.ar_discard)
|
||||||
|
fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv);
|
||||||
sdp->sd_args.ar_discard = 0;
|
sdp->sd_args.ar_discard = 0;
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gfs2_fitrim - Generate discard requests for unused bits of the filesystem
|
||||||
|
* @filp: Any file on the filesystem
|
||||||
|
* @argp: Pointer to the arguments (also used to pass result)
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, otherwise error code
|
||||||
|
*/
|
||||||
|
|
||||||
|
int gfs2_fitrim(struct file *filp, void __user *argp)
|
||||||
|
{
|
||||||
|
struct inode *inode = filp->f_dentry->d_inode;
|
||||||
|
struct gfs2_sbd *sdp = GFS2_SB(inode);
|
||||||
|
struct request_queue *q = bdev_get_queue(sdp->sd_vfs->s_bdev);
|
||||||
|
struct buffer_head *bh;
|
||||||
|
struct gfs2_rgrpd *rgd;
|
||||||
|
struct gfs2_rgrpd *rgd_end;
|
||||||
|
struct gfs2_holder gh;
|
||||||
|
struct fstrim_range r;
|
||||||
|
int ret = 0;
|
||||||
|
u64 amt;
|
||||||
|
u64 trimmed = 0;
|
||||||
|
unsigned int x;
|
||||||
|
|
||||||
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
if (!blk_queue_discard(q))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (argp == NULL) {
|
||||||
|
r.start = 0;
|
||||||
|
r.len = ULLONG_MAX;
|
||||||
|
r.minlen = 0;
|
||||||
|
} else if (copy_from_user(&r, argp, sizeof(r)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
rgd = gfs2_blk2rgrpd(sdp, r.start, 0);
|
||||||
|
rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &gh);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!(rgd->rd_flags & GFS2_RGF_TRIMMED)) {
|
||||||
|
/* Trim each bitmap in the rgrp */
|
||||||
|
for (x = 0; x < rgd->rd_length; x++) {
|
||||||
|
struct gfs2_bitmap *bi = rgd->rd_bits + x;
|
||||||
|
ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt);
|
||||||
|
if (ret) {
|
||||||
|
gfs2_glock_dq_uninit(&gh);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
trimmed += amt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark rgrp as having been trimmed */
|
||||||
|
ret = gfs2_trans_begin(sdp, RES_RG_HDR, 0);
|
||||||
|
if (ret == 0) {
|
||||||
|
bh = rgd->rd_bits[0].bi_bh;
|
||||||
|
rgd->rd_flags |= GFS2_RGF_TRIMMED;
|
||||||
|
gfs2_trans_add_bh(rgd->rd_gl, bh, 1);
|
||||||
|
gfs2_rgrp_out(rgd, bh->b_data);
|
||||||
|
gfs2_trans_end(sdp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gfs2_glock_dq_uninit(&gh);
|
||||||
|
|
||||||
|
if (rgd == rgd_end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rgd = gfs2_rgrpd_get_next(rgd);
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
r.len = trimmed << 9;
|
||||||
|
if (argp && copy_to_user(argp, &r, sizeof(r)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1008,7 +1118,7 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked)
|
||||||
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
|
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal))
|
||||||
rgd = begin = ip->i_rgd;
|
rgd = begin = ip->i_rgd;
|
||||||
else
|
else
|
||||||
rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal);
|
rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
|
||||||
|
|
||||||
if (rgd == NULL)
|
if (rgd == NULL)
|
||||||
return -EBADSLT;
|
return -EBADSLT;
|
||||||
|
@ -1293,7 +1403,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
|
||||||
u32 length, rgrp_blk, buf_blk;
|
u32 length, rgrp_blk, buf_blk;
|
||||||
unsigned int buf;
|
unsigned int buf;
|
||||||
|
|
||||||
rgd = gfs2_blk2rgrpd(sdp, bstart);
|
rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
|
||||||
if (!rgd) {
|
if (!rgd) {
|
||||||
if (gfs2_consist(sdp))
|
if (gfs2_consist(sdp))
|
||||||
fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
|
fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
|
||||||
|
@ -1474,7 +1584,7 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta)
|
||||||
return;
|
return;
|
||||||
trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
|
trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE);
|
||||||
rgd->rd_free += blen;
|
rgd->rd_free += blen;
|
||||||
|
rgd->rd_flags &= ~GFS2_RGF_TRIMMED;
|
||||||
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
|
||||||
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
|
||||||
|
|
||||||
|
@ -1560,14 +1670,9 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type)
|
||||||
{
|
{
|
||||||
struct gfs2_rgrpd *rgd;
|
struct gfs2_rgrpd *rgd;
|
||||||
struct gfs2_holder rgd_gh;
|
struct gfs2_holder rgd_gh;
|
||||||
int error;
|
int error = -EINVAL;
|
||||||
|
|
||||||
error = gfs2_rindex_update(sdp);
|
rgd = gfs2_blk2rgrpd(sdp, no_addr, 1);
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error = -EINVAL;
|
|
||||||
rgd = gfs2_blk2rgrpd(sdp, no_addr);
|
|
||||||
if (!rgd)
|
if (!rgd)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -1610,7 +1715,7 @@ void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist,
|
||||||
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
|
if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block))
|
||||||
rgd = ip->i_rgd;
|
rgd = ip->i_rgd;
|
||||||
else
|
else
|
||||||
rgd = gfs2_blk2rgrpd(sdp, block);
|
rgd = gfs2_blk2rgrpd(sdp, block, 1);
|
||||||
if (!rgd) {
|
if (!rgd) {
|
||||||
fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
|
fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#define __RGRP_DOT_H__
|
#define __RGRP_DOT_H__
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
struct gfs2_rgrpd;
|
struct gfs2_rgrpd;
|
||||||
struct gfs2_sbd;
|
struct gfs2_sbd;
|
||||||
|
@ -18,7 +19,7 @@ struct gfs2_holder;
|
||||||
|
|
||||||
extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
|
extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
|
||||||
|
|
||||||
extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
|
extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact);
|
||||||
extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
|
extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
|
||||||
extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
|
extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
|
||||||
|
|
||||||
|
@ -62,8 +63,9 @@ extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state);
|
||||||
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
|
extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
|
||||||
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
|
extern u64 gfs2_ri_total(struct gfs2_sbd *sdp);
|
||||||
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
|
extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl);
|
||||||
extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
|
||||||
struct buffer_head *bh,
|
struct buffer_head *bh,
|
||||||
const struct gfs2_bitmap *bi);
|
const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
|
||||||
|
extern int gfs2_fitrim(struct file *filp, void __user *argp);
|
||||||
|
|
||||||
#endif /* __RGRP_DOT_H__ */
|
#endif /* __RGRP_DOT_H__ */
|
||||||
|
|
|
@ -1417,7 +1417,7 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip)
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr);
|
rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1);
|
||||||
if (!rgd) {
|
if (!rgd) {
|
||||||
gfs2_consist_inode(ip);
|
gfs2_consist_inode(ip);
|
||||||
error = -EIO;
|
error = -EIO;
|
||||||
|
@ -1557,6 +1557,7 @@ static void gfs2_evict_inode(struct inode *inode)
|
||||||
end_writeback(inode);
|
end_writeback(inode);
|
||||||
gfs2_dir_hash_inval(ip);
|
gfs2_dir_hash_inval(ip);
|
||||||
ip->i_gl->gl_object = NULL;
|
ip->i_gl->gl_object = NULL;
|
||||||
|
flush_delayed_work_sync(&ip->i_gl->gl_work);
|
||||||
gfs2_glock_add_to_lru(ip->i_gl);
|
gfs2_glock_add_to_lru(ip->i_gl);
|
||||||
gfs2_glock_put(ip->i_gl);
|
gfs2_glock_put(ip->i_gl);
|
||||||
ip->i_gl = NULL;
|
ip->i_gl = NULL;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/dlmconstants.h>
|
#include <linux/dlmconstants.h>
|
||||||
#include <linux/gfs2_ondisk.h>
|
#include <linux/gfs2_ondisk.h>
|
||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
|
#include <linux/ktime.h>
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
#include "glock.h"
|
#include "glock.h"
|
||||||
|
|
||||||
|
@ -43,7 +44,8 @@
|
||||||
{(1UL << GLF_FROZEN), "F" }, \
|
{(1UL << GLF_FROZEN), "F" }, \
|
||||||
{(1UL << GLF_QUEUED), "q" }, \
|
{(1UL << GLF_QUEUED), "q" }, \
|
||||||
{(1UL << GLF_LRU), "L" }, \
|
{(1UL << GLF_LRU), "L" }, \
|
||||||
{(1UL << GLF_OBJECT), "o" })
|
{(1UL << GLF_OBJECT), "o" }, \
|
||||||
|
{(1UL << GLF_BLOCKING), "b" })
|
||||||
|
|
||||||
#ifndef NUMPTY
|
#ifndef NUMPTY
|
||||||
#define NUMPTY
|
#define NUMPTY
|
||||||
|
@ -236,6 +238,62 @@ TRACE_EVENT(gfs2_glock_queue,
|
||||||
glock_trace_name(__entry->state))
|
glock_trace_name(__entry->state))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/* DLM sends a reply to GFS2 */
|
||||||
|
TRACE_EVENT(gfs2_glock_lock_time,
|
||||||
|
|
||||||
|
TP_PROTO(const struct gfs2_glock *gl, s64 tdiff),
|
||||||
|
|
||||||
|
TP_ARGS(gl, tdiff),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field( dev_t, dev )
|
||||||
|
__field( u64, glnum )
|
||||||
|
__field( u32, gltype )
|
||||||
|
__field( int, status )
|
||||||
|
__field( char, flags )
|
||||||
|
__field( s64, tdiff )
|
||||||
|
__field( s64, srtt )
|
||||||
|
__field( s64, srttvar )
|
||||||
|
__field( s64, srttb )
|
||||||
|
__field( s64, srttvarb )
|
||||||
|
__field( s64, sirt )
|
||||||
|
__field( s64, sirtvar )
|
||||||
|
__field( s64, dcount )
|
||||||
|
__field( s64, qcount )
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->dev = gl->gl_sbd->sd_vfs->s_dev;
|
||||||
|
__entry->glnum = gl->gl_name.ln_number;
|
||||||
|
__entry->gltype = gl->gl_name.ln_type;
|
||||||
|
__entry->status = gl->gl_lksb.sb_status;
|
||||||
|
__entry->flags = gl->gl_lksb.sb_flags;
|
||||||
|
__entry->tdiff = tdiff;
|
||||||
|
__entry->srtt = gl->gl_stats.stats[GFS2_LKS_SRTT];
|
||||||
|
__entry->srttvar = gl->gl_stats.stats[GFS2_LKS_SRTTVAR];
|
||||||
|
__entry->srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB];
|
||||||
|
__entry->srttvarb = gl->gl_stats.stats[GFS2_LKS_SRTTVARB];
|
||||||
|
__entry->sirt = gl->gl_stats.stats[GFS2_LKS_SIRT];
|
||||||
|
__entry->sirtvar = gl->gl_stats.stats[GFS2_LKS_SIRTVAR];
|
||||||
|
__entry->dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT];
|
||||||
|
__entry->qcount = gl->gl_stats.stats[GFS2_LKS_QCOUNT];
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("%u,%u glock %d:%lld status:%d flags:%02x tdiff:%lld srtt:%lld/%lld srttb:%lld/%lld sirt:%lld/%lld dcnt:%lld qcnt:%lld",
|
||||||
|
MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype,
|
||||||
|
(unsigned long long)__entry->glnum,
|
||||||
|
__entry->status, __entry->flags,
|
||||||
|
(long long)__entry->tdiff,
|
||||||
|
(long long)__entry->srtt,
|
||||||
|
(long long)__entry->srttvar,
|
||||||
|
(long long)__entry->srttb,
|
||||||
|
(long long)__entry->srttvarb,
|
||||||
|
(long long)__entry->sirt,
|
||||||
|
(long long)__entry->sirtvar,
|
||||||
|
(long long)__entry->dcount,
|
||||||
|
(long long)__entry->qcount)
|
||||||
|
);
|
||||||
|
|
||||||
/* Section 2 - Log/journal
|
/* Section 2 - Log/journal
|
||||||
*
|
*
|
||||||
* Objectives:
|
* Objectives:
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly;
|
||||||
struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
|
struct kmem_cache *gfs2_bufdata_cachep __read_mostly;
|
||||||
struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
|
struct kmem_cache *gfs2_rgrpd_cachep __read_mostly;
|
||||||
struct kmem_cache *gfs2_quotad_cachep __read_mostly;
|
struct kmem_cache *gfs2_quotad_cachep __read_mostly;
|
||||||
|
mempool_t *gfs2_bh_pool __read_mostly;
|
||||||
|
|
||||||
void gfs2_assert_i(struct gfs2_sbd *sdp)
|
void gfs2_assert_i(struct gfs2_sbd *sdp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#ifndef __UTIL_DOT_H__
|
#ifndef __UTIL_DOT_H__
|
||||||
#define __UTIL_DOT_H__
|
#define __UTIL_DOT_H__
|
||||||
|
|
||||||
|
#include <linux/mempool.h>
|
||||||
|
|
||||||
#include "incore.h"
|
#include "incore.h"
|
||||||
|
|
||||||
#define fs_printk(level, fs, fmt, arg...) \
|
#define fs_printk(level, fs, fmt, arg...) \
|
||||||
|
@ -150,6 +152,7 @@ extern struct kmem_cache *gfs2_inode_cachep;
|
||||||
extern struct kmem_cache *gfs2_bufdata_cachep;
|
extern struct kmem_cache *gfs2_bufdata_cachep;
|
||||||
extern struct kmem_cache *gfs2_rgrpd_cachep;
|
extern struct kmem_cache *gfs2_rgrpd_cachep;
|
||||||
extern struct kmem_cache *gfs2_quotad_cachep;
|
extern struct kmem_cache *gfs2_quotad_cachep;
|
||||||
|
extern mempool_t *gfs2_bh_pool;
|
||||||
|
|
||||||
static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
|
static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
|
||||||
unsigned int *p)
|
unsigned int *p)
|
||||||
|
|
|
@ -251,7 +251,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
|
||||||
if (!blks)
|
if (!blks)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rgd = gfs2_blk2rgrpd(sdp, bn);
|
rgd = gfs2_blk2rgrpd(sdp, bn, 1);
|
||||||
if (!rgd) {
|
if (!rgd) {
|
||||||
gfs2_consist_inode(ip);
|
gfs2_consist_inode(ip);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -1439,7 +1439,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip)
|
||||||
struct gfs2_holder gh;
|
struct gfs2_holder gh;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr);
|
rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1);
|
||||||
if (!rgd) {
|
if (!rgd) {
|
||||||
gfs2_consist_inode(ip);
|
gfs2_consist_inode(ip);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
|
@ -168,6 +168,7 @@ struct gfs2_rindex {
|
||||||
#define GFS2_RGF_METAONLY 0x00000002
|
#define GFS2_RGF_METAONLY 0x00000002
|
||||||
#define GFS2_RGF_DATAONLY 0x00000004
|
#define GFS2_RGF_DATAONLY 0x00000004
|
||||||
#define GFS2_RGF_NOALLOC 0x00000008
|
#define GFS2_RGF_NOALLOC 0x00000008
|
||||||
|
#define GFS2_RGF_TRIMMED 0x00000010
|
||||||
|
|
||||||
struct gfs2_rgrp {
|
struct gfs2_rgrp {
|
||||||
struct gfs2_meta_header rg_header;
|
struct gfs2_meta_header rg_header;
|
||||||
|
|
Loading…
Reference in New Issue