GFS2: Improve statfs and quota usability
Benjamin Marzinski [Tue, 20 Oct 2009 07:39:44 +0000 (02:39 -0500)]
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: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>

fs/gfs2/incore.h
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/gfs2/super.c

index 6edb423..c239b0f 100644 (file)
@@ -430,6 +430,9 @@ struct gfs2_args {
        unsigned int ar_discard:1;              /* discard requests */
        unsigned int ar_errors:2;               /* errors=withdraw | panic */
        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 {
@@ -558,6 +561,7 @@ struct gfs2_sbd {
        spinlock_t sd_statfs_spin;
        struct gfs2_statfs_change_host sd_statfs_master;
        struct gfs2_statfs_change_host sd_statfs_local;
+       int sd_statfs_force_sync;
 
        /* Resource group stuff */
 
index 36b11cb..9744ee9 100644 (file)
@@ -63,13 +63,10 @@ static void gfs2_tune_init(struct gfs2_tune *gt)
        gt->gt_quota_warn_period = 10;
        gt->gt_quota_scale_num = 1;
        gt->gt_quota_scale_den = 1;
-       gt->gt_quota_quantum = 60;
        gt->gt_new_files_jdata = 0;
        gt->gt_max_readahead = 1 << 18;
        gt->gt_stall_secs = 600;
        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)
@@ -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_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);
        if (error)
@@ -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_data = GFS2_DATA_DEFAULT;
        args.ar_commit = 60;
+       args.ar_statfs_quantum = 30;
+       args.ar_quota_quantum = 60;
        args.ar_errors = GFS2_ERRORS_DEFAULT;
 
        error = gfs2_mount_args(&args, data);
index 1d4fc04..e3bf6ea 100644 (file)
@@ -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
  * @sdp: Pointer to GFS2 superblock
@@ -1363,8 +1371,15 @@ int gfs2_quotad(void *data)
        while (!kthread_should_stop()) {
 
                /* Update the master statfs file */
-               quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t,
-                                  &statfs_timeo, &tune->gt_statfs_quantum);
+               if (sdp->sd_statfs_force_sync) {
+                       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 */
                quotad_check_timeo(sdp, "sync", gfs2_quota_sync, t,
@@ -1381,7 +1396,7 @@ int gfs2_quotad(void *data)
                spin_lock(&sdp->sd_trunc_lock);
                empty = list_empty(&sdp->sd_trunc_list);
                spin_unlock(&sdp->sd_trunc_lock);
-               if (empty)
+               if (empty && !sdp->sd_statfs_force_sync)
                        t -= schedule_timeout(t);
                else
                        t = 0;
index 025d15b..e271fa0 100644 (file)
@@ -32,6 +32,8 @@ extern int gfs2_quota_init(struct gfs2_sbd *sdp);
 extern void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
 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)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
index e7b24d5..3fee2fd 100644 (file)
@@ -70,6 +70,9 @@ enum {
        Opt_commit,
        Opt_err_withdraw,
        Opt_err_panic,
+       Opt_statfs_quantum,
+       Opt_statfs_percent,
+       Opt_quota_quantum,
        Opt_error,
 };
 
@@ -101,6 +104,9 @@ static const match_table_t tokens = {
        {Opt_commit, "commit=%d"},
        {Opt_err_withdraw, "errors=withdraw"},
        {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}
 };
 
@@ -214,6 +220,28 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                                return rv ? rv : -EINVAL;
                        }
                        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:
                        args->ar_errors = GFS2_ERRORS_WITHDRAW;
                        break;
@@ -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_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;
+       int percent, sync_percent;
        int error;
 
        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,
        l_sc->sc_free += free;
        l_sc->sc_dinodes += dinodes;
        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);
 
        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,
@@ -522,6 +560,7 @@ int gfs2_statfs_sync(struct super_block *sb, int type)
                goto out_bh2;
 
        update_statfs(sdp, m_bh, l_bh);
+       sdp->sd_statfs_force_sync = 0;
 
        gfs2_trans_end(sdp);
 
@@ -1062,6 +1101,11 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 
        spin_lock(&gt->gt_spin);
        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);
        error = gfs2_mount_args(&args, data);
        if (error)
@@ -1100,6 +1144,15 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
                sb->s_flags &= ~MS_POSIXACL;
        spin_lock(&gt->gt_spin);
        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);
 
        gfs2_online_uevent(sdp);
@@ -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_args *args = &sdp->sd_args;
-       int lfsecs;
+       int val;
 
        if (is_ancestor(mnt->mnt_root, sdp->sd_master_dir))
                seq_printf(s, ",meta");
@@ -1241,9 +1294,17 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        }
        if (args->ar_discard)
                seq_printf(s, ",discard");
-       lfsecs = sdp->sd_tune.gt_log_flush_secs;
-       if (lfsecs != 60)
-               seq_printf(s, ",commit=%d", lfsecs);
+       val = sdp->sd_tune.gt_log_flush_secs;
+       if (val != 60)
+               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) {
                const char *state;