diff options
author | Elena Reshetova <elena.reshetova@intel.com> | 2017-03-03 03:55:12 -0500 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-04-18 08:07:23 -0400 |
commit | 490b54d6fb75f6ffd0471ec58bb38a992e2b40cd (patch) | |
tree | a7f431ea6a0f4369ba43be8736090efd54d6998b | |
parent | 9b64f57ddf8673d29fafb3405d4aa1e93f5a4cd7 (diff) |
btrfs: convert extent_map.refs from atomic_t to refcount_t
refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/extent_io.c | 4 | ||||
-rw-r--r-- | fs/btrfs/extent_map.c | 10 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 3 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 2 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 2 | ||||
-rw-r--r-- | include/trace/events/btrfs.h | 2 |
6 files changed, 12 insertions, 11 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 27fdb250b446..3649932e48d5 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -2859,7 +2859,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, | |||
2859 | em = *em_cached; | 2859 | em = *em_cached; |
2860 | if (extent_map_in_tree(em) && start >= em->start && | 2860 | if (extent_map_in_tree(em) && start >= em->start && |
2861 | start < extent_map_end(em)) { | 2861 | start < extent_map_end(em)) { |
2862 | atomic_inc(&em->refs); | 2862 | refcount_inc(&em->refs); |
2863 | return em; | 2863 | return em; |
2864 | } | 2864 | } |
2865 | 2865 | ||
@@ -2870,7 +2870,7 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, | |||
2870 | em = get_extent(BTRFS_I(inode), page, pg_offset, start, len, 0); | 2870 | em = get_extent(BTRFS_I(inode), page, pg_offset, start, len, 0); |
2871 | if (em_cached && !IS_ERR_OR_NULL(em)) { | 2871 | if (em_cached && !IS_ERR_OR_NULL(em)) { |
2872 | BUG_ON(*em_cached); | 2872 | BUG_ON(*em_cached); |
2873 | atomic_inc(&em->refs); | 2873 | refcount_inc(&em->refs); |
2874 | *em_cached = em; | 2874 | *em_cached = em; |
2875 | } | 2875 | } |
2876 | return em; | 2876 | return em; |
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 26f9ac719d20..69850155870c 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -55,7 +55,7 @@ struct extent_map *alloc_extent_map(void) | |||
55 | em->flags = 0; | 55 | em->flags = 0; |
56 | em->compress_type = BTRFS_COMPRESS_NONE; | 56 | em->compress_type = BTRFS_COMPRESS_NONE; |
57 | em->generation = 0; | 57 | em->generation = 0; |
58 | atomic_set(&em->refs, 1); | 58 | refcount_set(&em->refs, 1); |
59 | INIT_LIST_HEAD(&em->list); | 59 | INIT_LIST_HEAD(&em->list); |
60 | return em; | 60 | return em; |
61 | } | 61 | } |
@@ -71,8 +71,8 @@ void free_extent_map(struct extent_map *em) | |||
71 | { | 71 | { |
72 | if (!em) | 72 | if (!em) |
73 | return; | 73 | return; |
74 | WARN_ON(atomic_read(&em->refs) == 0); | 74 | WARN_ON(refcount_read(&em->refs) == 0); |
75 | if (atomic_dec_and_test(&em->refs)) { | 75 | if (refcount_dec_and_test(&em->refs)) { |
76 | WARN_ON(extent_map_in_tree(em)); | 76 | WARN_ON(extent_map_in_tree(em)); |
77 | WARN_ON(!list_empty(&em->list)); | 77 | WARN_ON(!list_empty(&em->list)); |
78 | if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) | 78 | if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) |
@@ -322,7 +322,7 @@ static inline void setup_extent_mapping(struct extent_map_tree *tree, | |||
322 | struct extent_map *em, | 322 | struct extent_map *em, |
323 | int modified) | 323 | int modified) |
324 | { | 324 | { |
325 | atomic_inc(&em->refs); | 325 | refcount_inc(&em->refs); |
326 | em->mod_start = em->start; | 326 | em->mod_start = em->start; |
327 | em->mod_len = em->len; | 327 | em->mod_len = em->len; |
328 | 328 | ||
@@ -381,7 +381,7 @@ __lookup_extent_mapping(struct extent_map_tree *tree, | |||
381 | if (strict && !(end > em->start && start < extent_map_end(em))) | 381 | if (strict && !(end > em->start && start < extent_map_end(em))) |
382 | return NULL; | 382 | return NULL; |
383 | 383 | ||
384 | atomic_inc(&em->refs); | 384 | refcount_inc(&em->refs); |
385 | return em; | 385 | return em; |
386 | } | 386 | } |
387 | 387 | ||
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index eb8b8fae036b..a67b2def5413 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __EXTENTMAP__ | 2 | #define __EXTENTMAP__ |
3 | 3 | ||
4 | #include <linux/rbtree.h> | 4 | #include <linux/rbtree.h> |
5 | #include <linux/refcount.h> | ||
5 | 6 | ||
6 | #define EXTENT_MAP_LAST_BYTE ((u64)-4) | 7 | #define EXTENT_MAP_LAST_BYTE ((u64)-4) |
7 | #define EXTENT_MAP_HOLE ((u64)-3) | 8 | #define EXTENT_MAP_HOLE ((u64)-3) |
@@ -41,7 +42,7 @@ struct extent_map { | |||
41 | */ | 42 | */ |
42 | struct map_lookup *map_lookup; | 43 | struct map_lookup *map_lookup; |
43 | }; | 44 | }; |
44 | atomic_t refs; | 45 | refcount_t refs; |
45 | unsigned int compress_type; | 46 | unsigned int compress_type; |
46 | struct list_head list; | 47 | struct list_head list; |
47 | }; | 48 | }; |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index a59674c3e69e..ccfe9fe7754a 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -4196,7 +4196,7 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, | |||
4196 | if (em->generation <= test_gen) | 4196 | if (em->generation <= test_gen) |
4197 | continue; | 4197 | continue; |
4198 | /* Need a ref to keep it from getting evicted from cache */ | 4198 | /* Need a ref to keep it from getting evicted from cache */ |
4199 | atomic_inc(&em->refs); | 4199 | refcount_inc(&em->refs); |
4200 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); | 4200 | set_bit(EXTENT_FLAG_LOGGING, &em->flags); |
4201 | list_add_tail(&em->list, &extents); | 4201 | list_add_tail(&em->list, &extents); |
4202 | num++; | 4202 | num++; |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0f6706047167..dce59fb59b0c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4839,7 +4839,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
4839 | ret = add_extent_mapping(em_tree, em, 0); | 4839 | ret = add_extent_mapping(em_tree, em, 0); |
4840 | if (!ret) { | 4840 | if (!ret) { |
4841 | list_add_tail(&em->list, &trans->transaction->pending_chunks); | 4841 | list_add_tail(&em->list, &trans->transaction->pending_chunks); |
4842 | atomic_inc(&em->refs); | 4842 | refcount_inc(&em->refs); |
4843 | } | 4843 | } |
4844 | write_unlock(&em_tree->lock); | 4844 | write_unlock(&em_tree->lock); |
4845 | if (ret) { | 4845 | if (ret) { |
diff --git a/include/trace/events/btrfs.h b/include/trace/events/btrfs.h index a3c3cab643a9..9dd29e806fed 100644 --- a/include/trace/events/btrfs.h +++ b/include/trace/events/btrfs.h | |||
@@ -213,7 +213,7 @@ TRACE_EVENT_CONDITION(btrfs_get_extent, | |||
213 | __entry->block_start = map->block_start; | 213 | __entry->block_start = map->block_start; |
214 | __entry->block_len = map->block_len; | 214 | __entry->block_len = map->block_len; |
215 | __entry->flags = map->flags; | 215 | __entry->flags = map->flags; |
216 | __entry->refs = atomic_read(&map->refs); | 216 | __entry->refs = refcount_read(&map->refs); |
217 | __entry->compress_type = map->compress_type; | 217 | __entry->compress_type = map->compress_type; |
218 | ), | 218 | ), |
219 | 219 | ||