]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/btrfs/ctree.h
Btrfs: fix race between using extent maps and merging them
[linux.git] / fs / btrfs / ctree.h
index fe2b8765d9e6b4fc6e991028895580a7c5211426..36df977b64d91d1f3bbdd90edcb9da91751e87e4 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/dynamic_debug.h>
 #include <linux/refcount.h>
 #include <linux/crc32c.h>
+#include "extent-io-tree.h"
 #include "extent_io.h"
 #include "extent_map.h"
 #include "async-thread.h"
@@ -38,7 +39,7 @@ struct btrfs_transaction;
 struct btrfs_pending_snapshot;
 struct btrfs_delayed_ref_root;
 struct btrfs_space_info;
-struct btrfs_block_group_cache;
+struct btrfs_block_group;
 extern struct kmem_cache *btrfs_trans_handle_cachep;
 extern struct kmem_cache *btrfs_bit_radix_cachep;
 extern struct kmem_cache *btrfs_path_cachep;
@@ -56,9 +57,9 @@ struct btrfs_ref;
  * filesystem data as well that can be used to read data in order to repair
  * read errors on other disks.
  *
- * Current value is derived from RAID1 with 2 copies.
+ * Current value is derived from RAID1C4 with 4 copies.
  */
-#define BTRFS_MAX_MIRRORS (2 + 1)
+#define BTRFS_MAX_MIRRORS (4 + 1)
 
 #define BTRFS_MAX_LEVEL 8
 
@@ -100,6 +101,14 @@ struct btrfs_ref;
 
 #define BTRFS_MAX_EXTENT_SIZE SZ_128M
 
+/*
+ * Deltas are an effective way to populate global statistics.  Give macro names
+ * to make it clear what we're doing.  An example is discard_extents in
+ * btrfs_free_space_ctl.
+ */
+#define BTRFS_STAT_NR_ENTRIES  2
+#define BTRFS_STAT_CURR                0
+#define BTRFS_STAT_PREV                1
 
 /*
  * Count how many BTRFS_MAX_EXTENT_SIZE cover the @size
@@ -291,7 +300,8 @@ struct btrfs_super_block {
         BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF |         \
         BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA |       \
         BTRFS_FEATURE_INCOMPAT_NO_HOLES        |       \
-        BTRFS_FEATURE_INCOMPAT_METADATA_UUID)
+        BTRFS_FEATURE_INCOMPAT_METADATA_UUID   |       \
+        BTRFS_FEATURE_INCOMPAT_RAID1C34)
 
 #define BTRFS_FEATURE_INCOMPAT_SAFE_SET                        \
        (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
@@ -413,7 +423,7 @@ struct btrfs_free_cluster {
        /* We did a full search and couldn't create a cluster */
        bool fragmented;
 
-       struct btrfs_block_group_cache *block_group;
+       struct btrfs_block_group *block_group;
        /*
         * when a cluster is allocated from a block group, we put the
         * cluster onto a list in the block group so that it can
@@ -438,6 +448,36 @@ struct btrfs_full_stripe_locks_tree {
        struct mutex lock;
 };
 
+/* Discard control. */
+/*
+ * Async discard uses multiple lists to differentiate the discard filter
+ * parameters.  Index 0 is for completely free block groups where we need to
+ * ensure the entire block group is trimmed without being lossy.  Indices
+ * afterwards represent monotonically decreasing discard filter sizes to
+ * prioritize what should be discarded next.
+ */
+#define BTRFS_NR_DISCARD_LISTS         3
+#define BTRFS_DISCARD_INDEX_UNUSED     0
+#define BTRFS_DISCARD_INDEX_START      1
+
+struct btrfs_discard_ctl {
+       struct workqueue_struct *discard_workers;
+       struct delayed_work work;
+       spinlock_t lock;
+       struct btrfs_block_group *block_group;
+       struct list_head discard_list[BTRFS_NR_DISCARD_LISTS];
+       u64 prev_discard;
+       atomic_t discardable_extents;
+       atomic64_t discardable_bytes;
+       u64 max_discard_size;
+       unsigned long delay;
+       u32 iops_limit;
+       u32 kbps_limit;
+       u64 discard_extent_bytes;
+       u64 discard_bitmap_bytes;
+       atomic64_t discard_bytes_saved;
+};
+
 /* delayed seq elem */
 struct seq_list {
        struct list_head list;
@@ -476,8 +516,8 @@ struct btrfs_swapfile_pin {
        void *ptr;
        struct inode *inode;
        /*
-        * If true, ptr points to a struct btrfs_block_group_cache. Otherwise,
-        * ptr points to a struct btrfs_device.
+        * If true, ptr points to a struct btrfs_block_group. Otherwise, ptr
+        * points to a struct btrfs_device.
         */
        bool is_block_group;
 };
@@ -524,6 +564,9 @@ enum {
         * so we don't need to offload checksums to workqueues.
         */
        BTRFS_FS_CSUM_IMPL_FAST,
+
+       /* Indicate that the discard workqueue can service discards. */
+       BTRFS_FS_DISCARD_RUNNING,
 };
 
 struct btrfs_fs_info {
@@ -671,14 +714,12 @@ struct btrfs_fs_info {
        atomic_t nr_delayed_iputs;
        wait_queue_head_t delayed_iputs_wait;
 
-       /* this protects tree_mod_seq_list */
-       spinlock_t tree_mod_seq_lock;
        atomic64_t tree_mod_seq;
-       struct list_head tree_mod_seq_list;
 
-       /* this protects tree_mod_log */
+       /* this protects tree_mod_log and tree_mod_seq_list */
        rwlock_t tree_mod_log_lock;
        struct rb_root tree_mod_log;
+       struct list_head tree_mod_seq_list;
 
        atomic_t async_delalloc_pages;
 
@@ -722,7 +763,6 @@ struct btrfs_fs_info {
        struct btrfs_workqueue *endio_meta_write_workers;
        struct btrfs_workqueue *endio_write_workers;
        struct btrfs_workqueue *endio_freespace_worker;
-       struct btrfs_workqueue *submit_workers;
        struct btrfs_workqueue *caching_workers;
        struct btrfs_workqueue *readahead_workers;
 
@@ -815,6 +855,8 @@ struct btrfs_fs_info {
        struct btrfs_workqueue *scrub_wr_completion_workers;
        struct btrfs_workqueue *scrub_parity_workers;
 
+       struct btrfs_discard_ctl discard_ctl;
+
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
        u32 check_integrity_print_mask;
 #endif
@@ -901,6 +943,11 @@ struct btrfs_fs_info {
        spinlock_t ref_verify_lock;
        struct rb_root block_tree;
 #endif
+
+#ifdef CONFIG_BTRFS_DEBUG
+       struct kobject *debug_kobj;
+       struct kobject *discard_debug_kobj;
+#endif
 };
 
 static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
@@ -1169,7 +1216,7 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
 #define BTRFS_MOUNT_FLUSHONCOMMIT       (1 << 7)
 #define BTRFS_MOUNT_SSD_SPREAD         (1 << 8)
 #define BTRFS_MOUNT_NOSSD              (1 << 9)
-#define BTRFS_MOUNT_DISCARD            (1 << 10)
+#define BTRFS_MOUNT_DISCARD_SYNC       (1 << 10)
 #define BTRFS_MOUNT_FORCE_COMPRESS      (1 << 11)
 #define BTRFS_MOUNT_SPACE_CACHE                (1 << 12)
 #define BTRFS_MOUNT_CLEAR_CACHE                (1 << 13)
@@ -1188,6 +1235,7 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info)
 #define BTRFS_MOUNT_FREE_SPACE_TREE    (1 << 26)
 #define BTRFS_MOUNT_NOLOGREPLAY                (1 << 27)
 #define BTRFS_MOUNT_REF_VERIFY         (1 << 28)
+#define BTRFS_MOUNT_DISCARD_ASYNC      (1 << 29)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
 #define BTRFS_DEFAULT_MAX_INLINE       (2048)
@@ -1519,18 +1567,18 @@ static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb,
 }
 
 /* struct btrfs_block_group_item */
-BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item,
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_used, struct btrfs_block_group_item,
                         used, 64);
-BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item,
+BTRFS_SETGET_FUNCS(block_group_used, struct btrfs_block_group_item,
                         used, 64);
-BTRFS_SETGET_STACK_FUNCS(block_group_chunk_objectid,
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_chunk_objectid,
                        struct btrfs_block_group_item, chunk_objectid, 64);
 
-BTRFS_SETGET_FUNCS(disk_block_group_chunk_objectid,
+BTRFS_SETGET_FUNCS(block_group_chunk_objectid,
                   struct btrfs_block_group_item, chunk_objectid, 64);
-BTRFS_SETGET_FUNCS(disk_block_group_flags,
+BTRFS_SETGET_FUNCS(block_group_flags,
                   struct btrfs_block_group_item, flags, 64);
-BTRFS_SETGET_STACK_FUNCS(block_group_flags,
+BTRFS_SETGET_STACK_FUNCS(stack_block_group_flags,
                        struct btrfs_block_group_item, flags, 64);
 
 /* struct btrfs_free_space_info */
@@ -2163,6 +2211,9 @@ BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
 
 int btrfs_super_csum_size(const struct btrfs_super_block *s);
 const char *btrfs_super_csum_name(u16 csum_type);
+const char *btrfs_super_csum_driver(u16 csum_type);
+size_t __const btrfs_get_num_csums(void);
+
 
 /*
  * The leaf data grows from end-to-front in the node.
@@ -2397,7 +2448,7 @@ static inline u64 btrfs_calc_metadata_size(struct btrfs_fs_info *fs_info,
 
 int btrfs_add_excluded_extent(struct btrfs_fs_info *fs_info,
                              u64 start, u64 num_bytes);
-void btrfs_free_excluded_extents(struct btrfs_block_group_cache *cache);
+void btrfs_free_excluded_extents(struct btrfs_block_group *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           unsigned long count);
 void btrfs_cleanup_ref_head_accounting(struct btrfs_fs_info *fs_info,
@@ -2445,16 +2496,16 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_ref *ref);
 
 int btrfs_free_reserved_extent(struct btrfs_fs_info *fs_info,
                               u64 start, u64 len, int delalloc);
-int btrfs_free_and_pin_reserved_extent(struct btrfs_fs_info *fs_info,
-                                      u64 start, u64 len);
+int btrfs_pin_reserved_extent(struct btrfs_fs_info *fs_info, u64 start,
+                             u64 len);
 void btrfs_prepare_extent_commit(struct btrfs_fs_info *fs_info);
 int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans);
 int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
                         struct btrfs_ref *generic_ref);
 
 int btrfs_extent_readonly(struct btrfs_fs_info *fs_info, u64 bytenr);
-void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache);
-void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache);
+void btrfs_get_block_group_trimming(struct btrfs_block_group *cache);
+void btrfs_put_block_group_trimming(struct btrfs_block_group *cache);
 void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
 
 enum btrfs_reserve_flush_enum {
@@ -2507,7 +2558,7 @@ void btrfs_wait_for_snapshot_creation(struct btrfs_root *root);
 /* ctree.c */
 int btrfs_bin_search(struct extent_buffer *eb, const struct btrfs_key *key,
                     int level, int *slot);
-int btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
+int __pure btrfs_comp_cpu_keys(const struct btrfs_key *k1, const struct btrfs_key *k2);
 int btrfs_previous_item(struct btrfs_root *root,
                        struct btrfs_path *path, u64 min_objectid,
                        int type);
@@ -2567,8 +2618,6 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 void btrfs_release_path(struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
-void btrfs_set_path_blocking(struct btrfs_path *p);
-void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                   struct btrfs_path *path, int slot, int nr);
@@ -2785,11 +2834,9 @@ struct btrfs_inode_extref *btrfs_find_name_in_ext_backref(
 /* file-item.c */
 struct btrfs_dio_private;
 int btrfs_del_csums(struct btrfs_trans_handle *trans,
-                   struct btrfs_fs_info *fs_info, u64 bytenr, u64 len);
+                   struct btrfs_root *root, u64 bytenr, u64 len);
 blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio,
-                                  u8 *dst);
-blk_status_t btrfs_lookup_bio_sums_dio(struct inode *inode, struct bio *bio,
-                             u64 logical_offset);
+                                  u64 offset, u8 *dst);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             u64 objectid, u64 pos,
@@ -2870,13 +2917,12 @@ int btrfs_drop_inode(struct inode *inode);
 int __init btrfs_init_cachep(void);
 void __cold btrfs_destroy_cachep(void);
 struct inode *btrfs_iget_path(struct super_block *s, struct btrfs_key *location,
-                             struct btrfs_root *root, int *new,
-                             struct btrfs_path *path);
+                             struct btrfs_root *root, struct btrfs_path *path);
 struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
-                        struct btrfs_root *root, int *was_new);
+                        struct btrfs_root *root);
 struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
                                    struct page *page, size_t pg_offset,
-                                   u64 start, u64 end, int create);
+                                   u64 start, u64 end);
 int btrfs_update_inode(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root,
                              struct inode *inode);
@@ -2909,7 +2955,7 @@ long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 int btrfs_ioctl_get_supported_features(void __user *arg);
 void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
-int btrfs_is_empty_uuid(u8 *uuid);
+int __pure btrfs_is_empty_uuid(u8 *uuid);
 int btrfs_defrag_file(struct inode *inode, struct file *file,
                      struct btrfs_ioctl_defrag_range_args *range,
                      u64 newer_than, unsigned long max_pages);
@@ -3109,17 +3155,21 @@ do {                                                            \
        rcu_read_unlock();                                      \
 } while (0)
 
-__cold
-static inline void assfail(const char *expr, const char *file, int line)
+#ifdef CONFIG_BTRFS_ASSERT
+__cold __noreturn
+static inline void assertfail(const char *expr, const char *file, int line)
 {
-       if (IS_ENABLED(CONFIG_BTRFS_ASSERT)) {
-               pr_err("assertion failed: %s, in %s:%d\n", expr, file, line);
-               BUG();
-       }
+       pr_err("assertion failed: %s, in %s:%d\n", expr, file, line);
+       BUG();
 }
 
-#define ASSERT(expr)   \
-       (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+#define ASSERT(expr)                                           \
+       (likely(expr) ? (void)0 : assertfail(#expr, __FILE__, __LINE__))
+
+#else
+static inline void assertfail(const char *expr, const char* file, int line) { }
+#define ASSERT(expr)   (void)(expr)
+#endif
 
 /*
  * Use that for functions that are conditionally exported for sanity tests but
@@ -3143,7 +3193,7 @@ __cold
 void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function,
                     unsigned int line, int errno, const char *fmt, ...);
 
-const char *btrfs_decode_error(int errno);
+const char * __attribute_const__ btrfs_decode_error(int errno);
 
 __cold
 void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,