Merge branch 'x86-seccomp-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / btrfs / volumes.h
index 2aaa00c4781637f508302829ed51e3ae05402c84..08980fa2303916ee08c0f2b6bd30a6b9a6f0a711 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/btrfs.h>
 #include "async-thread.h"
 
+extern struct mutex uuid_mutex;
+
 #define BTRFS_STRIPE_LEN       (64 * 1024)
 
 struct buffer_head;
@@ -32,41 +34,59 @@ struct btrfs_pending_bios {
        struct bio *tail;
 };
 
+/*
+ * Use sequence counter to get consistent device stat data on
+ * 32-bit processors.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#include <linux/seqlock.h>
+#define __BTRFS_NEED_DEVICE_DATA_ORDERED
+#define btrfs_device_data_ordered_init(device) \
+       seqcount_init(&device->data_seqcount)
+#else
+#define btrfs_device_data_ordered_init(device) do { } while (0)
+#endif
+
 struct btrfs_device {
        struct list_head dev_list;
        struct list_head dev_alloc_list;
        struct btrfs_fs_devices *fs_devices;
+
        struct btrfs_root *dev_root;
 
+       struct rcu_string *name;
+
+       u64 generation;
+
+       spinlock_t io_lock ____cacheline_aligned;
+       int running_pending;
        /* regular prio bios */
        struct btrfs_pending_bios pending_bios;
        /* WRITE_SYNC bios */
        struct btrfs_pending_bios pending_sync_bios;
 
-       u64 generation;
-       int running_pending;
+       struct block_device *bdev;
+
+       /* the mode sent to blkdev_get */
+       fmode_t mode;
+
        int writeable;
        int in_fs_metadata;
        int missing;
        int can_discard;
        int is_tgtdev_for_dev_replace;
 
-       spinlock_t io_lock;
-       /* the mode sent to blkdev_get */
-       fmode_t mode;
-
-       struct block_device *bdev;
-
-
-       struct rcu_string *name;
+#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
+       seqcount_t data_seqcount;
+#endif
 
        /* the internal btrfs device id */
        u64 devid;
 
-       /* size of the device */
+       /* size of the device in memory */
        u64 total_bytes;
 
-       /* size of the disk */
+       /* size of the device on disk */
        u64 disk_total_bytes;
 
        /* bytes used */
@@ -83,10 +103,26 @@ struct btrfs_device {
        /* minimal io size for this device */
        u32 sector_size;
 
-
        /* physical drive uuid (or lvm uuid) */
        u8 uuid[BTRFS_UUID_SIZE];
 
+       /*
+        * size of the device on the current transaction
+        *
+        * This variant is update when committing the transaction,
+        * and protected by device_list_mutex
+        */
+       u64 commit_total_bytes;
+
+       /* bytes used on the current transaction */
+       u64 commit_bytes_used;
+       /*
+        * used to manage the device which is resized
+        *
+        * It is protected by chunk_lock.
+        */
+       struct list_head resized_list;
+
        /* for sending down flush barriers */
        int nobarriers;
        struct bio *flush_bio;
@@ -107,26 +143,90 @@ struct btrfs_device {
        struct radix_tree_root reada_zones;
        struct radix_tree_root reada_extents;
 
-
        /* disk I/O failure stats. For detailed description refer to
         * enum btrfs_dev_stat_values in ioctl.h */
        int dev_stats_valid;
-       int dev_stats_dirty; /* counters need to be written to disk */
+
+       /* Counter to record the change of device stats */
+       atomic_t dev_stats_ccnt;
        atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
 };
 
+/*
+ * If we read those variants at the context of their own lock, we needn't
+ * use the following helpers, reading them directly is safe.
+ */
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       u64 size;                                                       \
+       unsigned int seq;                                               \
+                                                                       \
+       do {                                                            \
+               seq = read_seqcount_begin(&dev->data_seqcount);         \
+               size = dev->name;                                       \
+       } while (read_seqcount_retry(&dev->data_seqcount, seq));        \
+       return size;                                                    \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       preempt_disable();                                              \
+       write_seqcount_begin(&dev->data_seqcount);                      \
+       dev->name = size;                                               \
+       write_seqcount_end(&dev->data_seqcount);                        \
+       preempt_enable();                                               \
+}
+#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT)
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       u64 size;                                                       \
+                                                                       \
+       preempt_disable();                                              \
+       size = dev->name;                                               \
+       preempt_enable();                                               \
+       return size;                                                    \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       preempt_disable();                                              \
+       dev->name = size;                                               \
+       preempt_enable();                                               \
+}
+#else
+#define BTRFS_DEVICE_GETSET_FUNCS(name)                                        \
+static inline u64                                                      \
+btrfs_device_get_##name(const struct btrfs_device *dev)                        \
+{                                                                      \
+       return dev->name;                                               \
+}                                                                      \
+                                                                       \
+static inline void                                                     \
+btrfs_device_set_##name(struct btrfs_device *dev, u64 size)            \
+{                                                                      \
+       dev->name = size;                                               \
+}
+#endif
+
+BTRFS_DEVICE_GETSET_FUNCS(total_bytes);
+BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes);
+BTRFS_DEVICE_GETSET_FUNCS(bytes_used);
+
 struct btrfs_fs_devices {
        u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
 
-       /* the device with this id has the most recent copy of the super */
-       u64 latest_devid;
-       u64 latest_trans;
        u64 num_devices;
        u64 open_devices;
        u64 rw_devices;
        u64 missing_devices;
        u64 total_rw_bytes;
-       u64 num_can_discard;
        u64 total_devices;
        struct block_device *latest_bdev;
 
@@ -139,6 +239,7 @@ struct btrfs_fs_devices {
        struct mutex device_list_mutex;
        struct list_head devices;
 
+       struct list_head resized_devices;
        /* devices not currently being allocated */
        struct list_head alloc_list;
        struct list_head list;
@@ -167,8 +268,9 @@ struct btrfs_fs_devices {
  */
 typedef void (btrfs_io_bio_end_io_t) (struct btrfs_io_bio *bio, int err);
 struct btrfs_io_bio {
-       unsigned long mirror_num;
-       unsigned long stripe_index;
+       unsigned int mirror_num;
+       unsigned int stripe_index;
+       u64 logical;
        u8 *csum;
        u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
        u8 *csum_allocated;
@@ -325,6 +427,7 @@ struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
 int btrfs_shrink_device(struct btrfs_device *device, u64 new_size);
 int btrfs_init_new_device(struct btrfs_root *root, char *path);
 int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
+                                 struct btrfs_device *srcdev,
                                  struct btrfs_device **device_out);
 int btrfs_balance(struct btrfs_balance_control *bctl,
                  struct btrfs_ioctl_balance_args *bargs);
@@ -360,11 +463,20 @@ unsigned long btrfs_full_stripe_len(struct btrfs_root *root,
 int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans,
                                struct btrfs_root *extent_root,
                                u64 chunk_offset, u64 chunk_size);
+int btrfs_remove_chunk(struct btrfs_trans_handle *trans,
+                      struct btrfs_root *root, u64 chunk_offset);
+
+static inline int btrfs_dev_stats_dirty(struct btrfs_device *dev)
+{
+       return atomic_read(&dev->dev_stats_ccnt);
+}
+
 static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
                                      int index)
 {
        atomic_inc(dev->dev_stat_values + index);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
 }
 
 static inline int btrfs_dev_stat_read(struct btrfs_device *dev,
@@ -379,7 +491,8 @@ static inline int btrfs_dev_stat_read_and_reset(struct btrfs_device *dev,
        int ret;
 
        ret = atomic_xchg(dev->dev_stat_values + index, 0);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
        return ret;
 }
 
@@ -387,7 +500,8 @@ static inline void btrfs_dev_stat_set(struct btrfs_device *dev,
                                      int index, unsigned long val)
 {
        atomic_set(dev->dev_stat_values + index, val);
-       dev->dev_stats_dirty = 1;
+       smp_mb__before_atomic();
+       atomic_inc(&dev->dev_stats_ccnt);
 }
 
 static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
@@ -395,4 +509,8 @@ static inline void btrfs_dev_stat_reset(struct btrfs_device *dev,
 {
        btrfs_dev_stat_set(dev, index, 0);
 }
+
+void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info);
+void btrfs_update_commit_device_bytes_used(struct btrfs_root *root,
+                                       struct btrfs_transaction *transaction);
 #endif