ext4: Convert to generic reserved quota's space management.
[safe/jmp/linux-2.6] / fs / gfs2 / super.c
index 40bcc37..c282ad4 100644 (file)
@@ -38,7 +38,7 @@
 #include "trans.h"
 #include "util.h"
 #include "sys.h"
-#include "eattr.h"
+#include "xattr.h"
 
 #define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
 
@@ -68,6 +68,13 @@ enum {
        Opt_discard,
        Opt_nodiscard,
        Opt_commit,
+       Opt_err_withdraw,
+       Opt_err_panic,
+       Opt_statfs_quantum,
+       Opt_statfs_percent,
+       Opt_quota_quantum,
+       Opt_barrier,
+       Opt_nobarrier,
        Opt_error,
 };
 
@@ -97,18 +104,25 @@ static const match_table_t tokens = {
        {Opt_discard, "discard"},
        {Opt_nodiscard, "nodiscard"},
        {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_barrier, "barrier"},
+       {Opt_nobarrier, "nobarrier"},
        {Opt_error, NULL}
 };
 
 /**
  * gfs2_mount_args - Parse mount options
- * @sdp:
- * @data:
+ * @args: The structure into which the parsed options will be written
+ * @options: The options to parse
  *
  * Return: errno
  */
 
-int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
+int gfs2_mount_args(struct gfs2_args *args, char *options)
 {
        char *o;
        int token;
@@ -152,6 +166,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
                        args->ar_localcaching = 1;
                        break;
                case Opt_debug:
+                       if (args->ar_errors == GFS2_ERRORS_PANIC) {
+                               printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
+                                      "are mutually exclusive.\n");
+                               return -EINVAL;
+                       }
                        args->ar_debug = 1;
                        break;
                case Opt_nodebug:
@@ -201,13 +220,52 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
                case Opt_commit:
                        rv = match_int(&tmp[0], &args->ar_commit);
                        if (rv || args->ar_commit <= 0) {
-                               fs_info(sdp, "commit mount option requires a positive numeric argument\n");
+                               printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n");
+                               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;
+               case Opt_err_panic:
+                       if (args->ar_debug) {
+                               printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
+                                       "are mutually exclusive.\n");
+                               return -EINVAL;
+                       }
+                       args->ar_errors = GFS2_ERRORS_PANIC;
+                       break;
+               case Opt_barrier:
+                       args->ar_nobarrier = 0;
+                       break;
+               case Opt_nobarrier:
+                       args->ar_nobarrier = 1;
+                       break;
                case Opt_error:
                default:
-                       fs_info(sdp, "invalid mount option: %s\n", o);
+                       printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o);
                        return -EINVAL;
                }
        }
@@ -353,7 +411,7 @@ fail:
        return error;
 }
 
-static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
+void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf)
 {
        const struct gfs2_statfs_change *str = buf;
 
@@ -422,7 +480,10 @@ 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;
+       s64 x, y;
+       int need_sync = 0;
        int error;
 
        error = gfs2_meta_inode_buffer(l_ip, &l_bh);
@@ -436,17 +497,49 @@ 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 (sdp->sd_args.ar_statfs_percent) {
+               x = 100 * l_sc->sc_free;
+               y = m_sc->sc_free * sdp->sd_args.ar_statfs_percent;
+               if (x >= y || x <= -y)
+                       need_sync = 1;
+       }
        spin_unlock(&sdp->sd_statfs_spin);
 
        brelse(l_bh);
+       if (need_sync)
+               gfs2_wake_up_statfs(sdp);
 }
 
-int gfs2_statfs_sync(struct gfs2_sbd *sdp)
+void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
+                  struct buffer_head *l_bh)
 {
        struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
        struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
        struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
        struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
+
+       gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+
+       spin_lock(&sdp->sd_statfs_spin);
+       m_sc->sc_total += l_sc->sc_total;
+       m_sc->sc_free += l_sc->sc_free;
+       m_sc->sc_dinodes += l_sc->sc_dinodes;
+       memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
+       memset(l_bh->b_data + sizeof(struct gfs2_dinode),
+              0, sizeof(struct gfs2_statfs_change));
+       spin_unlock(&sdp->sd_statfs_spin);
+
+       gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+       gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+}
+
+int gfs2_statfs_sync(struct super_block *sb, int type)
+{
+       struct gfs2_sbd *sdp = sb->s_fs_info;
+       struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+       struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+       struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master;
+       struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local;
        struct gfs2_holder gh;
        struct buffer_head *m_bh, *l_bh;
        int error;
@@ -477,19 +570,8 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp)
        if (error)
                goto out_bh2;
 
-       gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
-
-       spin_lock(&sdp->sd_statfs_spin);
-       m_sc->sc_total += l_sc->sc_total;
-       m_sc->sc_free += l_sc->sc_free;
-       m_sc->sc_dinodes += l_sc->sc_dinodes;
-       memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
-       memset(l_bh->b_data + sizeof(struct gfs2_dinode),
-              0, sizeof(struct gfs2_statfs_change));
-       spin_unlock(&sdp->sd_statfs_spin);
-
-       gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
-       gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+       update_statfs(sdp, m_bh, l_bh);
+       sdp->sd_statfs_force_sync = 0;
 
        gfs2_trans_end(sdp);
 
@@ -680,8 +762,9 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
        struct gfs2_holder t_gh;
        int error;
 
-       gfs2_quota_sync(sdp);
-       gfs2_statfs_sync(sdp);
+       flush_workqueue(gfs2_delete_workqueue);
+       gfs2_quota_sync(sdp->sd_vfs, 0);
+       gfs2_statfs_sync(sdp->sd_vfs, 0);
 
        error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
                                   &t_gh);
@@ -756,7 +839,6 @@ restart:
        /*  Release stuff  */
 
        iput(sdp->sd_jindex);
-       iput(sdp->sd_inum_inode);
        iput(sdp->sd_statfs_inode);
        iput(sdp->sd_rindex);
        iput(sdp->sd_quota_inode);
@@ -767,10 +849,8 @@ restart:
        if (!sdp->sd_args.ar_spectator) {
                gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
                gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
-               gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
                gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
                gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
-               iput(sdp->sd_ir_inode);
                iput(sdp->sd_sc_inode);
                iput(sdp->sd_qc_inode);
        }
@@ -788,17 +868,6 @@ restart:
 }
 
 /**
- * gfs2_write_super
- * @sb: the superblock
- *
- */
-
-static void gfs2_write_super(struct super_block *sb)
-{
-       sb->s_dirt = 0;
-}
-
-/**
  * gfs2_sync_fs - sync the filesystem
  * @sb: the superblock
  *
@@ -807,7 +876,6 @@ static void gfs2_write_super(struct super_block *sb)
 
 static int gfs2_sync_fs(struct super_block *sb, int wait)
 {
-       sb->s_dirt = 0;
        if (wait && sb->s_fs_info)
                gfs2_log_flush(sb->s_fs_info, NULL);
        return 0;
@@ -1044,8 +1112,13 @@ 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(sdp, &args, data);
+       error = gfs2_mount_args(&args, data);
        if (error)
                return error;
 
@@ -1080,10 +1153,24 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
                sb->s_flags |= MS_POSIXACL;
        else
                sb->s_flags &= ~MS_POSIXACL;
+       if (sdp->sd_args.ar_nobarrier)
+               set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
+       else
+               clear_bit(SDF_NOBARRIERS, &sdp->sd_flags);
        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);
        return 0;
 }
 
@@ -1161,7 +1248,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");
@@ -1222,9 +1309,36 @@ 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;
+
+               switch (args->ar_errors) {
+               case GFS2_ERRORS_WITHDRAW:
+                       state = "withdraw";
+                       break;
+               case GFS2_ERRORS_PANIC:
+                       state = "panic";
+                       break;
+               default:
+                       state = "unknown";
+                       break;
+               }
+               seq_printf(s, ",errors=%s", state);
+       }
+       if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
+               seq_printf(s, ",nobarrier");
+
        return 0;
 }
 
@@ -1252,6 +1366,10 @@ static void gfs2_delete_inode(struct inode *inode)
                goto out;
        }
 
+       error = gfs2_check_blk_type(sdp, ip->i_no_addr, GFS2_BLKST_UNLINKED);
+       if (error)
+               goto out_truncate;
+
        gfs2_glock_dq_wait(&ip->i_iopen_gh);
        gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
        error = gfs2_glock_nq(&ip->i_iopen_gh);
@@ -1324,7 +1442,6 @@ const struct super_operations gfs2_super_ops = {
        .write_inode            = gfs2_write_inode,
        .delete_inode           = gfs2_delete_inode,
        .put_super              = gfs2_put_super,
-       .write_super            = gfs2_write_super,
        .sync_fs                = gfs2_sync_fs,
        .freeze_fs              = gfs2_freeze,
        .unfreeze_fs            = gfs2_unfreeze,