aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-07-23 23:37:11 -0400
committerChris Mason <clm@fb.com>2014-09-17 16:37:46 -0400
commitaddc3fa74e5bcfabc0766f934a8895d1f9f6a67c (patch)
treeeae6105559c9163b1800b5a5b7340a134d389bb5 /fs
parentd5ee37bcb1dff9c1d1cac5f7e5752309f1ff66b6 (diff)
Btrfs: Fix the problem that the dirty flag of dev stats is cleared
The io error might happen during writing out the device stats, and the device stats information and dirty flag would be update at that time, but the current code didn't consider this case, just clear the dirty flag, it would cause that we forgot to write out the new device stats information. Fix it. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/volumes.c7
-rw-r--r--fs/btrfs/volumes.h19
2 files changed, 20 insertions, 6 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 7f25ff1c3854..e04424490f12 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -159,6 +159,7 @@ static struct btrfs_device *__alloc_device(void)
159 159
160 spin_lock_init(&dev->reada_lock); 160 spin_lock_init(&dev->reada_lock);
161 atomic_set(&dev->reada_in_flight, 0); 161 atomic_set(&dev->reada_in_flight, 0);
162 atomic_set(&dev->dev_stats_ccnt, 0);
162 INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT); 163 INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT);
163 INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT); 164 INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT);
164 165
@@ -6394,16 +6395,18 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
6394 struct btrfs_root *dev_root = fs_info->dev_root; 6395 struct btrfs_root *dev_root = fs_info->dev_root;
6395 struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; 6396 struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
6396 struct btrfs_device *device; 6397 struct btrfs_device *device;
6398 int stats_cnt;
6397 int ret = 0; 6399 int ret = 0;
6398 6400
6399 mutex_lock(&fs_devices->device_list_mutex); 6401 mutex_lock(&fs_devices->device_list_mutex);
6400 list_for_each_entry(device, &fs_devices->devices, dev_list) { 6402 list_for_each_entry(device, &fs_devices->devices, dev_list) {
6401 if (!device->dev_stats_valid || !device->dev_stats_dirty) 6403 if (!device->dev_stats_valid || !btrfs_dev_stats_dirty(device))
6402 continue; 6404 continue;
6403 6405
6406 stats_cnt = atomic_read(&device->dev_stats_ccnt);
6404 ret = update_dev_stat_item(trans, dev_root, device); 6407 ret = update_dev_stat_item(trans, dev_root, device);
6405 if (!ret) 6408 if (!ret)
6406 device->dev_stats_dirty = 0; 6409 atomic_sub(stats_cnt, &device->dev_stats_ccnt);
6407 } 6410 }
6408 mutex_unlock(&fs_devices->device_list_mutex); 6411 mutex_unlock(&fs_devices->device_list_mutex);
6409 6412
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 6fcc8eae7834..0defd232e290 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -110,7 +110,9 @@ struct btrfs_device {
110 /* disk I/O failure stats. For detailed description refer to 110 /* disk I/O failure stats. For detailed description refer to
111 * enum btrfs_dev_stat_values in ioctl.h */ 111 * enum btrfs_dev_stat_values in ioctl.h */
112 int dev_stats_valid; 112 int dev_stats_valid;
113 int dev_stats_dirty; /* counters need to be written to disk */ 113
114 /* Counter to record the change of device stats */
115 atomic_t dev_stats_ccnt;
114 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX]; 116 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
115}; 117};
116 118
@@ -359,11 +361,18 @@ unsigned long btrfs_full_stripe_len(struct btrfs_root *root,
359int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, 361int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
360 struct btrfs_root *extent_root, 362 struct btrfs_root *extent_root,
361 u64 chunk_offset, u64 chunk_size); 363 u64 chunk_offset, u64 chunk_size);
364
365static inline int btrfs_dev_stats_dirty(struct btrfs_device *dev)
366{
367 return atomic_read(&dev->dev_stats_ccnt);
368}
369
362static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, 370static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
363 int index) 371 int index)
364{ 372{
365 atomic_inc(dev->dev_stat_values + index); 373 atomic_inc(dev->dev_stat_values + index);
366 dev->dev_stats_dirty = 1; 374 smp_mb__before_atomic();
375 atomic_inc(&dev->dev_stats_ccnt);
367} 376}
368 377
369static inline int btrfs_dev_stat_read(struct btrfs_device *dev, 378static inline int btrfs_dev_stat_read(struct btrfs_device *dev,
@@ -378,7 +387,8 @@ static inline int btrfs_dev_stat_read_and_reset(struct btrfs_device *dev,
378 int ret; 387 int ret;
379 388
380 ret = atomic_xchg(dev->dev_stat_values + index, 0); 389 ret = atomic_xchg(dev->dev_stat_values + index, 0);
381 dev->dev_stats_dirty = 1; 390 smp_mb__before_atomic();
391 atomic_inc(&dev->dev_stats_ccnt);
382 return ret; 392 return ret;
383} 393}
384 394
@@ -386,7 +396,8 @@ static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
386 int index, unsigned long val) 396 int index, unsigned long val)
387{ 397{
388 atomic_set(dev->dev_stat_values + index, val); 398 atomic_set(dev->dev_stat_values + index, val);
389 dev->dev_stats_dirty = 1; 399 smp_mb__before_atomic();
400 atomic_inc(&dev->dev_stats_ccnt);
390} 401}
391 402
392static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, 403static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,