aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.h
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-09-03 09:35:38 -0400
committerChris Mason <clm@fb.com>2014-09-17 16:38:38 -0400
commit7cc8e58d53cd2295c3c1cee7b503bd1790ea4486 (patch)
tree1befd9a2bea8e1808f0fe1b12406c05b3f7dbe2d /fs/btrfs/volumes.h
parent1c1161870c8bcb0d966ebbf1aec05a87a79a4175 (diff)
Btrfs: fix unprotected device's variants on 32bits machine
->total_bytes,->disk_total_bytes,->bytes_used is protected by chunk lock when we change them, but sometimes we read them without any lock, and we might get unexpected value. We fix this problem like inode's i_size. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/volumes.h')
-rw-r--r--fs/btrfs/volumes.h84
1 files changed, 84 insertions, 0 deletions
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index f79d532fedb0..76600a3fedbe 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -32,6 +32,19 @@ struct btrfs_pending_bios {
32 struct bio *tail; 32 struct bio *tail;
33}; 33};
34 34
35/*
36 * Use sequence counter to get consistent device stat data on
37 * 32-bit processors.
38 */
39#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
40#include <linux/seqlock.h>
41#define __BTRFS_NEED_DEVICE_DATA_ORDERED
42#define btrfs_device_data_ordered_init(device) \
43 seqcount_init(&device->data_seqcount)
44#else
45#define btrfs_device_data_ordered_init(device) do { } while (0)
46#endif
47
35struct btrfs_device { 48struct btrfs_device {
36 struct list_head dev_list; 49 struct list_head dev_list;
37 struct list_head dev_alloc_list; 50 struct list_head dev_alloc_list;
@@ -61,6 +74,10 @@ struct btrfs_device {
61 int can_discard; 74 int can_discard;
62 int is_tgtdev_for_dev_replace; 75 int is_tgtdev_for_dev_replace;
63 76
77#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
78 seqcount_t data_seqcount;
79#endif
80
64 /* the internal btrfs device id */ 81 /* the internal btrfs device id */
65 u64 devid; 82 u64 devid;
66 83
@@ -133,6 +150,73 @@ struct btrfs_device {
133 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX]; 150 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
134}; 151};
135 152
153/*
154 * If we read those variants at the context of their own lock, we needn't
155 * use the following helpers, reading them directly is safe.
156 */
157#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
158#define BTRFS_DEVICE_GETSET_FUNCS(name) \
159static inline u64 \
160btrfs_device_get_##name(const struct btrfs_device *dev) \
161{ \
162 u64 size; \
163 unsigned int seq; \
164 \
165 do { \
166 seq = read_seqcount_begin(&dev->data_seqcount); \
167 size = dev->name; \
168 } while (read_seqcount_retry(&dev->data_seqcount, seq)); \
169 return size; \
170} \
171 \
172static inline void \
173btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
174{ \
175 preempt_disable(); \
176 write_seqcount_begin(&dev->data_seqcount); \
177 dev->name = size; \
178 write_seqcount_end(&dev->data_seqcount); \
179 preempt_enable(); \
180}
181#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
182#define BTRFS_DEVICE_GETSET_FUNCS(name) \
183static inline u64 \
184btrfs_device_get_##name(const struct btrfs_device *dev) \
185{ \
186 u64 size; \
187 \
188 preempt_disable(); \
189 size = dev->name; \
190 preempt_enable(); \
191 return size; \
192} \
193 \
194static inline void \
195btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
196{ \
197 preempt_disable(); \
198 dev->name = size; \
199 preempt_enable(); \
200}
201#else
202#define BTRFS_DEVICE_GETSET_FUNCS(name) \
203static inline u64 \
204btrfs_device_get_##name(const struct btrfs_device *dev) \
205{ \
206 return dev->name; \
207} \
208 \
209static inline void \
210btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \
211{ \
212 dev->name = size; \
213}
214#endif
215
216BTRFS_DEVICE_GETSET_FUNCS(total_bytes);
217BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes);
218BTRFS_DEVICE_GETSET_FUNCS(bytes_used);
219
136struct btrfs_fs_devices { 220struct btrfs_fs_devices {
137 u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ 221 u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
138 222