Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / fs / gfs2 / super.c
index db7fff5a29c15b42de84674578a803bbe863daa7..894fb01a91dab74be395685ecc5ab08f58533d37 100644 (file)
@@ -7,6 +7,8 @@
  * of the GNU General Public License version 2.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/bio.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -24,6 +26,7 @@
 #include <linux/wait.h>
 #include <linux/writeback.h>
 #include <linux/backing-dev.h>
+#include <linux/kernel.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -175,8 +178,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        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");
+                               pr_warn("-o debug and -o errors=panic are mutually exclusive\n");
                                return -EINVAL;
                        }
                        args->ar_debug = 1;
@@ -228,21 +230,21 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                case Opt_commit:
                        rv = match_int(&tmp[0], &args->ar_commit);
                        if (rv || args->ar_commit <= 0) {
-                               printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n");
+                               pr_warn("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");
+                               pr_warn("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");
+                               pr_warn("quota_quantum mount option requires a positive numeric argument\n");
                                return rv ? rv : -EINVAL;
                        }
                        break;
@@ -250,7 +252,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        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");
+                               pr_warn("statfs_percent mount option requires a numeric argument between 0 and 100\n");
                                return rv ? rv : -EINVAL;
                        }
                        break;
@@ -259,8 +261,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        break;
                case Opt_err_panic:
                        if (args->ar_debug) {
-                               printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
-                                       "are mutually exclusive.\n");
+                               pr_warn("-o debug and -o errors=panic are mutually exclusive\n");
                                return -EINVAL;
                        }
                        args->ar_errors = GFS2_ERRORS_PANIC;
@@ -279,7 +280,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        break;
                case Opt_error:
                default:
-                       printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o);
+                       pr_warn("invalid mount option: %s\n", o);
                        return -EINVAL;
                }
        }
@@ -295,9 +296,8 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
 
 void gfs2_jindex_free(struct gfs2_sbd *sdp)
 {
-       struct list_head list, *head;
+       struct list_head list;
        struct gfs2_jdesc *jd;
-       struct gfs2_journal_extent *jext;
 
        spin_lock(&sdp->sd_jindex_spin);
        list_add(&list, &sdp->sd_jindex_list);
@@ -307,14 +307,7 @@ void gfs2_jindex_free(struct gfs2_sbd *sdp)
 
        while (!list_empty(&list)) {
                jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
-               head = &jd->extent_list;
-               while (!list_empty(head)) {
-                       jext = list_entry(head->next,
-                                         struct gfs2_journal_extent,
-                                         extent_list);
-                       list_del(&jext->extent_list);
-                       kfree(jext);
-               }
+               gfs2_free_journal_extents(jd);
                list_del(&jd->jd_list);
                iput(jd->jd_inode);
                kfree(jd);
@@ -369,6 +362,33 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
        return 0;
 }
 
+static int init_threads(struct gfs2_sbd *sdp)
+{
+       struct task_struct *p;
+       int error = 0;
+
+       p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
+       if (IS_ERR(p)) {
+               error = PTR_ERR(p);
+               fs_err(sdp, "can't start logd thread: %d\n", error);
+               return error;
+       }
+       sdp->sd_logd_process = p;
+
+       p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
+       if (IS_ERR(p)) {
+               error = PTR_ERR(p);
+               fs_err(sdp, "can't start quotad thread: %d\n", error);
+               goto fail;
+       }
+       sdp->sd_quotad_process = p;
+       return 0;
+
+fail:
+       kthread_stop(sdp->sd_logd_process);
+       return error;
+}
+
 /**
  * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
  * @sdp: the filesystem
@@ -380,14 +400,19 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
 {
        struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
        struct gfs2_glock *j_gl = ip->i_gl;
-       struct gfs2_holder t_gh;
+       struct gfs2_holder freeze_gh;
        struct gfs2_log_header_host head;
        int error;
 
-       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh);
+       error = init_threads(sdp);
        if (error)
                return error;
 
+       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
+                                  &freeze_gh);
+       if (error)
+               goto fail_threads;
+
        j_gl->gl_ops->go_inval(j_gl, DIO_METADATA);
 
        error = gfs2_find_jhead(sdp->sd_jdesc, &head);
@@ -410,14 +435,16 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
 
        set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
 
-       gfs2_glock_dq_uninit(&t_gh);
+       gfs2_glock_dq_uninit(&freeze_gh);
 
        return 0;
 
 fail:
-       t_gh.gh_flags |= GL_NOCACHE;
-       gfs2_glock_dq_uninit(&t_gh);
-
+       freeze_gh.gh_flags |= GL_NOCACHE;
+       gfs2_glock_dq_uninit(&freeze_gh);
+fail_threads:
+       kthread_stop(sdp->sd_quotad_process);
+       kthread_stop(sdp->sd_logd_process);
        return error;
 }
 
@@ -554,14 +581,15 @@ int gfs2_statfs_sync(struct super_block *sb, int type)
        struct buffer_head *m_bh, *l_bh;
        int error;
 
+       sb_start_write(sb);
        error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
                                   &gh);
        if (error)
-               return error;
+               goto out;
 
        error = gfs2_meta_inode_buffer(m_ip, &m_bh);
        if (error)
-               goto out;
+               goto out_unlock;
 
        spin_lock(&sdp->sd_statfs_spin);
        gfs2_statfs_change_in(m_sc, m_bh->b_data +
@@ -589,8 +617,10 @@ out_bh2:
        brelse(l_bh);
 out_bh:
        brelse(m_bh);
-out:
+out_unlock:
        gfs2_glock_dq_uninit(&gh);
+out:
+       sb_end_write(sb);
        return error;
 }
 
@@ -610,7 +640,7 @@ struct lfcc {
  */
 
 static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
-                                   struct gfs2_holder *t_gh)
+                                   struct gfs2_holder *freeze_gh)
 {
        struct gfs2_inode *ip;
        struct gfs2_jdesc *jd;
@@ -634,8 +664,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
                list_add(&lfcc->list, &list);
        }
 
-       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED,
-                                  GL_NOCACHE, t_gh);
+       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_EXCLUSIVE,
+                                  GL_NOCACHE, freeze_gh);
 
        list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
                error = gfs2_jdesc_check(jd);
@@ -651,7 +681,7 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
        }
 
        if (error)
-               gfs2_glock_dq_uninit(t_gh);
+               gfs2_glock_dq_uninit(freeze_gh);
 
 out:
        while (!list_empty(&list)) {
@@ -713,12 +743,12 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
-       struct backing_dev_info *bdi = metamapping->backing_dev_info;
+       struct backing_dev_info *bdi = inode_to_bdi(metamapping->host);
        int ret = 0;
 
        if (wbc->sync_mode == WB_SYNC_ALL)
-               gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
-       if (bdi->dirty_exceeded)
+               gfs2_log_flush(GFS2_SB(inode), ip->i_gl, NORMAL_FLUSH);
+       if (bdi->wb.dirty_exceeded)
                gfs2_ail1_flush(sdp, wbc);
        else
                filemap_fdatawrite(metamapping);
@@ -797,37 +827,37 @@ out:
 
 static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
 {
-       struct gfs2_holder t_gh;
+       struct gfs2_holder freeze_gh;
        int error;
 
-       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);
+       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
+                                  &freeze_gh);
        if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
                return error;
 
-       gfs2_meta_syncfs(sdp);
-       gfs2_log_shutdown(sdp);
+       kthread_stop(sdp->sd_quotad_process);
+       kthread_stop(sdp->sd_logd_process);
 
+       flush_workqueue(gfs2_delete_workqueue);
+       gfs2_quota_sync(sdp->sd_vfs, 0);
+       gfs2_statfs_sync(sdp->sd_vfs, 0);
+
+       down_write(&sdp->sd_log_flush_lock);
        clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+       up_write(&sdp->sd_log_flush_lock);
 
-       if (t_gh.gh_gl)
-               gfs2_glock_dq_uninit(&t_gh);
+       gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH);
+       wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0);
+       gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
+
+       if (freeze_gh.gh_gl)
+               gfs2_glock_dq_uninit(&freeze_gh);
 
        gfs2_quota_cleanup(sdp);
 
        return error;
 }
 
-static int gfs2_umount_recovery_wait(void *word)
-{
-       schedule();
-       return 0;
-}
-
 /**
  * gfs2_put_super - Unmount the filesystem
  * @sb: The VFS superblock
@@ -852,14 +882,11 @@ restart:
                        continue;
                spin_unlock(&sdp->sd_jindex_spin);
                wait_on_bit(&jd->jd_flags, JDF_RECOVERY,
-                           gfs2_umount_recovery_wait, TASK_UNINTERRUPTIBLE);
+                           TASK_UNINTERRUPTIBLE);
                goto restart;
        }
        spin_unlock(&sdp->sd_jindex_spin);
 
-       kthread_stop(sdp->sd_quotad_process);
-       kthread_stop(sdp->sd_logd_process);
-
        if (!(sb->s_flags & MS_RDONLY)) {
                error = gfs2_make_fs_ro(sdp);
                if (error)
@@ -875,7 +902,7 @@ restart:
        iput(sdp->sd_quota_inode);
 
        gfs2_glock_put(sdp->sd_rename_gl);
-       gfs2_glock_put(sdp->sd_trans_gl);
+       gfs2_glock_put(sdp->sd_freeze_gl);
 
        if (!sdp->sd_args.ar_spectator) {
                gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
@@ -911,10 +938,40 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
 
        gfs2_quota_sync(sb, -1);
        if (wait && sdp)
-               gfs2_log_flush(sdp, NULL);
+               gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
        return 0;
 }
 
+void gfs2_freeze_func(struct work_struct *work)
+{
+       int error;
+       struct gfs2_holder freeze_gh;
+       struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_freeze_work);
+       struct super_block *sb = sdp->sd_vfs;
+
+       atomic_inc(&sb->s_active);
+       error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
+                                  &freeze_gh);
+       if (error) {
+               printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
+               gfs2_assert_withdraw(sdp, 0);
+       }
+       else {
+               atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
+               error = thaw_super(sb);
+               if (error) {
+                       printk(KERN_INFO "GFS2: couldn't thaw filesystem: %d\n",
+                              error);
+                       gfs2_assert_withdraw(sdp, 0);
+               }
+               if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+                       freeze_gh.gh_flags |= GL_NOCACHE;
+               gfs2_glock_dq_uninit(&freeze_gh);
+       }
+       deactivate_super(sb);
+       return;
+}
+
 /**
  * gfs2_freeze - prevent further writes to the filesystem
  * @sb: the VFS structure for the filesystem
@@ -924,10 +981,16 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
 static int gfs2_freeze(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
-       int error;
+       int error = 0;
 
-       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
-               return -EINVAL;
+       mutex_lock(&sdp->sd_freeze_mutex);
+       if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
+               goto out;
+
+       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
+               error = -EINVAL;
+               goto out;
+       }
 
        for (;;) {
                error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
@@ -947,7 +1010,10 @@ static int gfs2_freeze(struct super_block *sb)
                fs_err(sdp, "retrying...\n");
                msleep(1000);
        }
-       return 0;
+       error = 0;
+out:
+       mutex_unlock(&sdp->sd_freeze_mutex);
+       return error;
 }
 
 /**
@@ -960,7 +1026,15 @@ static int gfs2_unfreeze(struct super_block *sb)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
 
+       mutex_lock(&sdp->sd_freeze_mutex);
+        if (atomic_read(&sdp->sd_freeze_state) != SFS_FROZEN ||
+           sdp->sd_freeze_gh.gh_gl == NULL) {
+               mutex_unlock(&sdp->sd_freeze_mutex);
+                return 0;
+       }
+
        gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+       mutex_unlock(&sdp->sd_freeze_mutex);
        return 0;
 }
 
@@ -1097,7 +1171,7 @@ static int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change_host *s
 
 static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct super_block *sb = dentry->d_inode->i_sb;
+       struct super_block *sb = d_inode(dentry)->i_sb;
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_statfs_change_host sc;
        int error;
@@ -1225,7 +1299,7 @@ static int gfs2_drop_inode(struct inode *inode)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
 
-       if (inode->i_nlink) {
+       if (!test_bit(GIF_FREE_VFS_INODE, &ip->i_flags) && inode->i_nlink) {
                struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
                if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
                        clear_nlink(inode);
@@ -1258,21 +1332,21 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
        int val;
 
        if (is_ancestor(root, sdp->sd_master_dir))
-               seq_printf(s, ",meta");
+               seq_puts(s, ",meta");
        if (args->ar_lockproto[0])
-               seq_printf(s, ",lockproto=%s", args->ar_lockproto);
+               seq_show_option(s, "lockproto", args->ar_lockproto);
        if (args->ar_locktable[0])
-               seq_printf(s, ",locktable=%s", args->ar_locktable);
+               seq_show_option(s, "locktable", args->ar_locktable);
        if (args->ar_hostdata[0])
-               seq_printf(s, ",hostdata=%s", args->ar_hostdata);
+               seq_show_option(s, "hostdata", args->ar_hostdata);
        if (args->ar_spectator)
-               seq_printf(s, ",spectator");
+               seq_puts(s, ",spectator");
        if (args->ar_localflocks)
-               seq_printf(s, ",localflocks");
+               seq_puts(s, ",localflocks");
        if (args->ar_debug)
-               seq_printf(s, ",debug");
+               seq_puts(s, ",debug");
        if (args->ar_posix_acl)
-               seq_printf(s, ",acl");
+               seq_puts(s, ",acl");
        if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
                char *state;
                switch (args->ar_quota) {
@@ -1292,7 +1366,7 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
                seq_printf(s, ",quota=%s", state);
        }
        if (args->ar_suiddir)
-               seq_printf(s, ",suiddir");
+               seq_puts(s, ",suiddir");
        if (args->ar_data != GFS2_DATA_DEFAULT) {
                char *state;
                switch (args->ar_data) {
@@ -1309,7 +1383,7 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
                seq_printf(s, ",data=%s", state);
        }
        if (args->ar_discard)
-               seq_printf(s, ",discard");
+               seq_puts(s, ",discard");
        val = sdp->sd_tune.gt_logd_secs;
        if (val != 30)
                seq_printf(s, ",commit=%d", val);
@@ -1340,11 +1414,11 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root)
                seq_printf(s, ",errors=%s", state);
        }
        if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags))
-               seq_printf(s, ",nobarrier");
+               seq_puts(s, ",nobarrier");
        if (test_bit(SDF_DEMOTE, &sdp->sd_flags))
-               seq_printf(s, ",demote_interface_used");
+               seq_puts(s, ",demote_interface_used");
        if (args->ar_rgrplvb)
-               seq_printf(s, ",rgrplvb");
+               seq_puts(s, ",rgrplvb");
        return 0;
 }
 
@@ -1440,6 +1514,11 @@ static void gfs2_evict_inode(struct inode *inode)
        struct gfs2_holder gh;
        int error;
 
+       if (test_bit(GIF_FREE_VFS_INODE, &ip->i_flags)) {
+               clear_inode(inode);
+               return;
+       }
+
        if (inode->i_nlink || (sb->s_flags & MS_RDONLY))
                goto out;
 
@@ -1495,7 +1574,7 @@ static void gfs2_evict_inode(struct inode *inode)
        goto out_unlock;
 
 out_truncate:
-       gfs2_log_flush(sdp, ip->i_gl);
+       gfs2_log_flush(sdp, ip->i_gl, NORMAL_FLUSH);
        if (test_bit(GLF_DIRTY, &ip->i_gl->gl_flags)) {
                struct address_space *metamapping = gfs2_glock2aspace(ip->i_gl);
                filemap_fdatawrite(metamapping);
@@ -1527,8 +1606,8 @@ out_unlock:
                fs_warn(sdp, "gfs2_evict_inode: %d\n", error);
 out:
        /* Case 3 starts here */
-       truncate_inode_pages(&inode->i_data, 0);
-       gfs2_rs_delete(ip);
+       truncate_inode_pages_final(&inode->i_data);
+       gfs2_rs_delete(ip, NULL);
        gfs2_ordered_del_inode(ip);
        clear_inode(inode);
        gfs2_dir_hash_inval(ip);
@@ -1577,8 +1656,8 @@ const struct super_operations gfs2_super_ops = {
        .evict_inode            = gfs2_evict_inode,
        .put_super              = gfs2_put_super,
        .sync_fs                = gfs2_sync_fs,
-       .freeze_fs              = gfs2_freeze,
-       .unfreeze_fs            = gfs2_unfreeze,
+       .freeze_super           = gfs2_freeze,
+       .thaw_super             = gfs2_unfreeze,
        .statfs                 = gfs2_statfs,
        .remount_fs             = gfs2_remount_fs,
        .drop_inode             = gfs2_drop_inode,