Commit 3d3c10f2 authored by Benjamin Marzinski's avatar Benjamin Marzinski Committed by Steven Whitehouse

GFS2: Improve statfs and quota usability

GFS2 now has three new mount options, statfs_quantum, quota_quantum and
statfs_percent.  statfs_quantum and quota_quantum simply allow you to
set the tunables of the same name.  Setting setting statfs_quantum to 0
will also turn on the statfs_slow tunable.  statfs_percent accepts an
integer between 0 and 100.  Numbers between 1 and 100 will cause GFS2 to
do any early sync when the local number of blocks free changes by at
least statfs_percent from the totoal number of blocks free.  Setting
statfs_percent to 0 disables this.
Signed-off-by: default avatarBenjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 2ec46505
...@@ -430,6 +430,9 @@ struct gfs2_args { ...@@ -430,6 +430,9 @@ struct gfs2_args {
unsigned int ar_discard:1; /* discard requests */ unsigned int ar_discard:1; /* discard requests */
unsigned int ar_errors:2; /* errors=withdraw | panic */ unsigned int ar_errors:2; /* errors=withdraw | panic */
int ar_commit; /* Commit interval */ int ar_commit; /* Commit interval */
int ar_statfs_quantum; /* The fast statfs interval */
int ar_quota_quantum; /* The quota interval */
int ar_statfs_percent; /* The % change to force sync */
}; };
struct gfs2_tune { struct gfs2_tune {
...@@ -558,6 +561,7 @@ struct gfs2_sbd { ...@@ -558,6 +561,7 @@ struct gfs2_sbd {
spinlock_t sd_statfs_spin; spinlock_t sd_statfs_spin;
struct gfs2_statfs_change_host sd_statfs_master; struct gfs2_statfs_change_host sd_statfs_master;
struct gfs2_statfs_change_host sd_statfs_local; struct gfs2_statfs_change_host sd_statfs_local;
int sd_statfs_force_sync;
/* Resource group stuff */ /* Resource group stuff */
......
...@@ -63,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt) ...@@ -63,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
gt->gt_quota_warn_period = 10; gt->gt_quota_warn_period = 10;
gt->gt_quota_scale_num = 1; gt->gt_quota_scale_num = 1;
gt->gt_quota_scale_den = 1; gt->gt_quota_scale_den = 1;
gt->gt_quota_quantum = 60;
gt->gt_new_files_jdata = 0; gt->gt_new_files_jdata = 0;
gt->gt_max_readahead = 1 << 18; gt->gt_max_readahead = 1 << 18;
gt->gt_stall_secs = 600; gt->gt_stall_secs = 600;
gt->gt_complain_secs = 10; gt->gt_complain_secs = 10;
gt->gt_statfs_quantum = 30;
gt->gt_statfs_slow = 0;
} }
static struct gfs2_sbd *init_sbd(struct super_block *sb) static struct gfs2_sbd *init_sbd(struct super_block *sb)
...@@ -1153,6 +1150,15 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent ...@@ -1153,6 +1150,15 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift; sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit; sdp->sd_tune.gt_log_flush_secs = sdp->sd_args.ar_commit;
sdp->sd_tune.gt_quota_quantum = sdp->sd_args.ar_quota_quantum;
if (sdp->sd_args.ar_statfs_quantum) {
sdp->sd_tune.gt_statfs_slow = 0;
sdp->sd_tune.gt_statfs_quantum = sdp->sd_args.ar_statfs_quantum;
}
else {
sdp->sd_tune.gt_statfs_slow = 1;
sdp->sd_tune.gt_statfs_quantum = 30;
}
error = init_names(sdp, silent); error = init_names(sdp, silent);
if (error) if (error)
...@@ -1308,6 +1314,8 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1308,6 +1314,8 @@ static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
args.ar_quota = GFS2_QUOTA_DEFAULT; args.ar_quota = GFS2_QUOTA_DEFAULT;
args.ar_data = GFS2_DATA_DEFAULT; args.ar_data = GFS2_DATA_DEFAULT;
args.ar_commit = 60; args.ar_commit = 60;
args.ar_statfs_quantum = 30;
args.ar_quota_quantum = 60;
args.ar_errors = GFS2_ERRORS_DEFAULT; args.ar_errors = GFS2_ERRORS_DEFAULT;
error = gfs2_mount_args(&args, data); error = gfs2_mount_args(&args, data);
......
...@@ -1344,6 +1344,14 @@ static void quotad_check_trunc_list(struct gfs2_sbd *sdp) ...@@ -1344,6 +1344,14 @@ static void quotad_check_trunc_list(struct gfs2_sbd *sdp)
} }
} }
void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) {
if (!sdp->sd_statfs_force_sync) {
sdp->sd_statfs_force_sync = 1;
wake_up(&sdp->sd_quota_wait);
}
}
/** /**
* gfs2_quotad - Write cached quota changes into the quota file * gfs2_quotad - Write cached quota changes into the quota file
* @sdp: Pointer to GFS2 superblock * @sdp: Pointer to GFS2 superblock
...@@ -1363,8 +1371,15 @@ int gfs2_quotad(void *data) ...@@ -1363,8 +1371,15 @@ int gfs2_quotad(void *data)
while (!kthread_should_stop()) { while (!kthread_should_stop()) {
/* Update the master statfs file */ /* Update the master statfs file */
quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, if (sdp->sd_statfs_force_sync) {
&statfs_timeo, &tune->gt_statfs_quantum); int error = gfs2_statfs_sync(sdp->sd_vfs, 0);
quotad_error(sdp, "statfs", error);
statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
}
else
quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t,
&statfs_timeo,
&tune->gt_statfs_quantum);
/* Update quota file */ /* Update quota file */
quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t, quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
...@@ -1381,7 +1396,7 @@ int gfs2_quotad(void *data) ...@@ -1381,7 +1396,7 @@ int gfs2_quotad(void *data)
spin_lock(&sdp->sd_trunc_lock); spin_lock(&sdp->sd_trunc_lock);
empty = list_empty(&sdp->sd_trunc_list); empty = list_empty(&sdp->sd_trunc_list);
spin_unlock(&sdp->sd_trunc_lock); spin_unlock(&sdp->sd_trunc_lock);
if (empty) if (empty && !sdp->sd_statfs_force_sync)
t -= schedule_timeout(t); t -= schedule_timeout(t);
else else
t = 0; t = 0;
......
...@@ -32,6 +32,8 @@ extern int gfs2_quota_init(struct gfs2_sbd *sdp); ...@@ -32,6 +32,8 @@ extern int gfs2_quota_init(struct gfs2_sbd *sdp);
extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp); extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
extern int gfs2_quotad(void *data); extern int gfs2_quotad(void *data);
extern void gfs2_wake_up_statfs(struct gfs2_sbd *sdp);
static inline int gfs2_quota_lock_check(struct gfs2_inode *ip) static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
......
...@@ -70,6 +70,9 @@ enum { ...@@ -70,6 +70,9 @@ enum {
Opt_commit, Opt_commit,
Opt_err_withdraw, Opt_err_withdraw,
Opt_err_panic, Opt_err_panic,
Opt_statfs_quantum,
Opt_statfs_percent,
Opt_quota_quantum,
Opt_error, Opt_error,
}; };
...@@ -101,6 +104,9 @@ static const match_table_t tokens = { ...@@ -101,6 +104,9 @@ static const match_table_t tokens = {
{Opt_commit, "commit=%d"}, {Opt_commit, "commit=%d"},
{Opt_err_withdraw, "errors=withdraw"}, {Opt_err_withdraw, "errors=withdraw"},
{Opt_err_panic, "errors=panic"}, {Opt_err_panic, "errors=panic"},
{Opt_statfs_quantum, "statfs_quantum=%d"},
{Opt_statfs_percent, "statfs_percent=%d"},
{Opt_quota_quantum, "quota_quantum=%d"},
{Opt_error, NULL} {Opt_error, NULL}
}; };
...@@ -214,6 +220,28 @@ int gfs2_mount_args(struct gfs2_args *args, char *options) ...@@ -214,6 +220,28 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
return rv ? rv : -EINVAL; return rv ? rv : -EINVAL;
} }
break; break;
case Opt_statfs_quantum:
rv = match_int(&tmp[0], &args->ar_statfs_quantum);
if (rv || args->ar_statfs_quantum < 0) {
printk(KERN_WARNING "GFS2: statfs_quantum mount option requires a non-negative numeric argument\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_quota_quantum:
rv = match_int(&tmp[0], &args->ar_quota_quantum);
if (rv || args->ar_quota_quantum <= 0) {
printk(KERN_WARNING "GFS2: quota_quantum mount option requires a positive numeric argument\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_statfs_percent:
rv = match_int(&tmp[0], &args->ar_statfs_percent);
if (rv || args->ar_statfs_percent < 0 ||
args->ar_statfs_percent > 100) {
printk(KERN_WARNING "statfs_percent mount option requires a numeric argument between 0 and 100\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_err_withdraw: case Opt_err_withdraw:
args->ar_errors = GFS2_ERRORS_WITHDRAW; args->ar_errors = GFS2_ERRORS_WITHDRAW;
break; break;
...@@ -442,7 +470,9 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, ...@@ -442,7 +470,9 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
{ {
struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
struct buffer_head *l_bh; struct buffer_head *l_bh;
int percent, sync_percent;
int error; int error;
error = gfs2_meta_inode_buffer(l_ip, &l_bh); error = gfs2_meta_inode_buffer(l_ip, &l_bh);
...@@ -456,9 +486,17 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, ...@@ -456,9 +486,17 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
l_sc->sc_free += free; l_sc->sc_free += free;
l_sc->sc_dinodes += dinodes; l_sc->sc_dinodes += dinodes;
gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode)); gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode));
if (m_sc->sc_free)
percent = (100 * l_sc->sc_free) / m_sc->sc_free;
else
percent = 100;
spin_unlock(&sdp->sd_statfs_spin); spin_unlock(&sdp->sd_statfs_spin);
brelse(l_bh); brelse(l_bh);
sync_percent = sdp->sd_args.ar_statfs_percent;
if (sync_percent && (percent >= sync_percent ||
percent <= -sync_percent))
gfs2_wake_up_statfs(sdp);
} }
void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
...@@ -522,6 +560,7 @@ int gfs2_statfs_sync(struct super_block *sb, int type) ...@@ -522,6 +560,7 @@ int gfs2_statfs_sync(struct super_block *sb, int type)
goto out_bh2; goto out_bh2;
update_statfs(sdp, m_bh, l_bh); update_statfs(sdp, m_bh, l_bh);
sdp->sd_statfs_force_sync = 0;
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
...@@ -1062,6 +1101,11 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -1062,6 +1101,11 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
spin_lock(&gt->gt_spin); spin_lock(&gt->gt_spin);
args.ar_commit = gt->gt_log_flush_secs; args.ar_commit = gt->gt_log_flush_secs;
args.ar_quota_quantum = gt->gt_quota_quantum;
if (gt->gt_statfs_slow)
args.ar_statfs_quantum = 0;
else
args.ar_statfs_quantum = gt->gt_statfs_quantum;
spin_unlock(&gt->gt_spin); spin_unlock(&gt->gt_spin);
error = gfs2_mount_args(&args, data); error = gfs2_mount_args(&args, data);
if (error) if (error)
...@@ -1100,6 +1144,15 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) ...@@ -1100,6 +1144,15 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
sb->s_flags &= ~MS_POSIXACL; sb->s_flags &= ~MS_POSIXACL;
spin_lock(&gt->gt_spin); spin_lock(&gt->gt_spin);
gt->gt_log_flush_secs = args.ar_commit; gt->gt_log_flush_secs = args.ar_commit;
gt->gt_quota_quantum = args.ar_quota_quantum;
if (args.ar_statfs_quantum) {
gt->gt_statfs_slow = 0;
gt->gt_statfs_quantum = args.ar_statfs_quantum;
}
else {
gt->gt_statfs_slow = 1;
gt->gt_statfs_quantum = 30;
}
spin_unlock(&gt->gt_spin); spin_unlock(&gt->gt_spin);
gfs2_online_uevent(sdp); gfs2_online_uevent(sdp);
...@@ -1180,7 +1233,7 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) ...@@ -1180,7 +1233,7 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
{ {
struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info; struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
struct gfs2_args *args = &sdp->sd_args; struct gfs2_args *args = &sdp->sd_args;
int lfsecs; int val;
if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir)) if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
seq_printf(s, ",meta"); seq_printf(s, ",meta");
...@@ -1241,9 +1294,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) ...@@ -1241,9 +1294,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
} }
if (args->ar_discard) if (args->ar_discard)
seq_printf(s, ",discard"); seq_printf(s, ",discard");
lfsecs = sdp->sd_tune.gt_log_flush_secs; val = sdp->sd_tune.gt_log_flush_secs;
if (lfsecs != 60) if (val != 60)
seq_printf(s, ",commit=%d", lfsecs); seq_printf(s, ",commit=%d", val);
val = sdp->sd_tune.gt_statfs_quantum;
if (val != 30)
seq_printf(s, ",statfs_quantum=%d", val);
val = sdp->sd_tune.gt_quota_quantum;
if (val != 60)
seq_printf(s, ",quota_quantum=%d", val);
if (args->ar_statfs_percent)
seq_printf(s, ",statfs_percent=%d", args->ar_statfs_percent);
if (args->ar_errors != GFS2_ERRORS_DEFAULT) { if (args->ar_errors != GFS2_ERRORS_DEFAULT) {
const char *state; const char *state;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment