]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/btrfs/super.c
Merge tag 'trace-v5.6-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux.git] / fs / btrfs / super.c
index f452a94abdc312f011dac108906320f2daef6c55..0616a5434793d100ffa1db67c0afe961c687ba51 100644 (file)
@@ -46,6 +46,7 @@
 #include "sysfs.h"
 #include "tests/btrfs-tests.h"
 #include "block-group.h"
+#include "discard.h"
 
 #include "qgroup.h"
 #define CREATE_TRACE_POINTS
@@ -146,6 +147,8 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function
        if (sb_rdonly(sb))
                return;
 
+       btrfs_discard_stop(fs_info);
+
        /* btrfs handle error by forcing the filesystem readonly */
        sb->s_flags |= SB_RDONLY;
        btrfs_info(fs_info, "forced readonly");
@@ -313,6 +316,7 @@ enum {
        Opt_datasum, Opt_nodatasum,
        Opt_defrag, Opt_nodefrag,
        Opt_discard, Opt_nodiscard,
+       Opt_discard_mode,
        Opt_nologreplay,
        Opt_norecovery,
        Opt_ratio,
@@ -375,6 +379,7 @@ static const match_table_t tokens = {
        {Opt_defrag, "autodefrag"},
        {Opt_nodefrag, "noautodefrag"},
        {Opt_discard, "discard"},
+       {Opt_discard_mode, "discard=%s"},
        {Opt_nodiscard, "nodiscard"},
        {Opt_nologreplay, "nologreplay"},
        {Opt_norecovery, "norecovery"},
@@ -695,12 +700,26 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
                                   info->metadata_ratio);
                        break;
                case Opt_discard:
-                       btrfs_set_and_info(info, DISCARD,
-                                          "turning on discard");
+               case Opt_discard_mode:
+                       if (token == Opt_discard ||
+                           strcmp(args[0].from, "sync") == 0) {
+                               btrfs_clear_opt(info->mount_opt, DISCARD_ASYNC);
+                               btrfs_set_and_info(info, DISCARD_SYNC,
+                                                  "turning on sync discard");
+                       } else if (strcmp(args[0].from, "async") == 0) {
+                               btrfs_clear_opt(info->mount_opt, DISCARD_SYNC);
+                               btrfs_set_and_info(info, DISCARD_ASYNC,
+                                                  "turning on async discard");
+                       } else {
+                               ret = -EINVAL;
+                               goto out;
+                       }
                        break;
                case Opt_nodiscard:
-                       btrfs_clear_and_info(info, DISCARD,
+                       btrfs_clear_and_info(info, DISCARD_SYNC,
                                             "turning off discard");
+                       btrfs_clear_and_info(info, DISCARD_ASYNC,
+                                            "turning off async discard");
                        break;
                case Opt_space_cache:
                case Opt_space_cache_version:
@@ -1322,8 +1341,10 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",nologreplay");
        if (btrfs_test_opt(info, FLUSHONCOMMIT))
                seq_puts(seq, ",flushoncommit");
-       if (btrfs_test_opt(info, DISCARD))
+       if (btrfs_test_opt(info, DISCARD_SYNC))
                seq_puts(seq, ",discard");
+       if (btrfs_test_opt(info, DISCARD_ASYNC))
+               seq_puts(seq, ",discard=async");
        if (!(info->sb->s_flags & SB_POSIXACL))
                seq_puts(seq, ",noacl");
        if (btrfs_test_opt(info, SPACE_CACHE))
@@ -1713,6 +1734,14 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,
                btrfs_cleanup_defrag_inodes(fs_info);
        }
 
+       /* If we toggled discard async */
+       if (!btrfs_raw_test_opt(old_opts, DISCARD_ASYNC) &&
+           btrfs_test_opt(fs_info, DISCARD_ASYNC))
+               btrfs_discard_resume(fs_info);
+       else if (btrfs_raw_test_opt(old_opts, DISCARD_ASYNC) &&
+                !btrfs_test_opt(fs_info, DISCARD_ASYNC))
+               btrfs_discard_cleanup(fs_info);
+
        clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state);
 }
 
@@ -1760,6 +1789,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                 */
                cancel_work_sync(&fs_info->async_reclaim_work);
 
+               btrfs_discard_cleanup(fs_info);
+
                /* wait for the uuid_scan task to finish */
                down(&fs_info->uuid_tree_rescan_sem);
                /* avoid complains from lockdep et al. */
@@ -2104,7 +2135,15 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
         */
        thresh = SZ_4M;
 
-       if (!mixed && total_free_meta - thresh < block_rsv->size)
+       /*
+        * We only want to claim there's no available space if we can no longer
+        * allocate chunks for our metadata profile and our global reserve will
+        * not fit in the free metadata space.  If we aren't ->full then we
+        * still can allocate chunks and thus are fine using the currently
+        * calculated f_bavail.
+        */
+       if (!mixed && block_rsv->space_info->full &&
+           total_free_meta - thresh < block_rsv->size)
                buf->f_bavail = 0;
 
        buf->f_type = BTRFS_SUPER_MAGIC;