]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/tier.c
Update bcachefs sources to e99d29e402 bcachefs: zstd support, compression refactoring
[bcachefs-tools-debian] / libbcachefs / tier.c
1
2 #include "bcachefs.h"
3 #include "alloc.h"
4 #include "btree_iter.h"
5 #include "buckets.h"
6 #include "clock.h"
7 #include "extents.h"
8 #include "io.h"
9 #include "move.h"
10 #include "super-io.h"
11 #include "tier.h"
12
13 #include <linux/freezer.h>
14 #include <linux/kthread.h>
15 #include <trace/events/bcachefs.h>
16
17 static bool __tiering_pred(struct bch_fs *c, struct bch_tier *tier,
18                            struct bkey_s_c_extent e)
19 {
20         const struct bch_extent_ptr *ptr;
21         unsigned replicas = 0;
22
23         /* Make sure we have room to add a new pointer: */
24         if (bkey_val_u64s(e.k) + BKEY_EXTENT_PTR_U64s_MAX >
25             BKEY_EXTENT_VAL_U64s_MAX)
26                 return false;
27
28         extent_for_each_ptr(e, ptr)
29                 if (bch_dev_bkey_exists(c, ptr->dev)->mi.tier >= tier->idx)
30                         replicas++;
31
32         return replicas < c->opts.data_replicas;
33 }
34
35 static enum data_cmd tiering_pred(struct bch_fs *c, void *arg,
36                                   enum bkey_type type,
37                                   struct bkey_s_c_extent e,
38                                   struct bch_io_opts *io_opts,
39                                   struct data_opts *data_opts)
40 {
41         struct bch_tier *tier = arg;
42
43         if (!__tiering_pred(c, tier, e))
44                 return DATA_SKIP;
45
46         data_opts->btree_insert_flags = 0;
47         return DATA_ADD_REPLICAS;
48 }
49
50 static int bch2_tiering_thread(void *arg)
51 {
52         struct bch_tier *tier = arg;
53         struct bch_fs *c = container_of(tier, struct bch_fs, tiers[tier->idx]);
54         struct io_clock *clock = &c->io_clock[WRITE];
55         struct bch_dev *ca;
56         struct bch_move_stats move_stats;
57         u64 tier_capacity, available_sectors;
58         unsigned long last;
59         unsigned i, nr_devices;
60
61         memset(&move_stats, 0, sizeof(move_stats));
62         set_freezable();
63
64         while (!kthread_should_stop()) {
65                 if (kthread_wait_freezable(c->tiering_enabled &&
66                                            (nr_devices = dev_mask_nr(&tier->devs))))
67                         break;
68
69                 while (1) {
70                         struct bch_tier *faster_tier;
71
72                         last = atomic_long_read(&clock->now);
73
74                         tier_capacity = available_sectors = 0;
75                         for (faster_tier = c->tiers;
76                              faster_tier != tier;
77                              faster_tier++) {
78                                 rcu_read_lock();
79                                 for_each_member_device_rcu(ca, c, i,
80                                                 &faster_tier->devs) {
81                                         tier_capacity +=
82                                                 bucket_to_sector(ca,
83                                                         ca->mi.nbuckets -
84                                                         ca->mi.first_bucket);
85                                         available_sectors +=
86                                                 bucket_to_sector(ca,
87                                                         dev_buckets_available(c, ca));
88                                 }
89                                 rcu_read_unlock();
90                         }
91
92                         if (available_sectors < (tier_capacity >> 1))
93                                 break;
94
95                         bch2_kthread_io_clock_wait(clock,
96                                                   last +
97                                                   available_sectors -
98                                                   (tier_capacity >> 1));
99                         if (kthread_should_stop())
100                                 return 0;
101                 }
102
103                 bch2_move_data(c, &tier->pd.rate,
104                                SECTORS_IN_FLIGHT_PER_DEVICE * nr_devices,
105                                &tier->devs,
106                                writepoint_ptr(&tier->wp),
107                                POS_MIN, POS_MAX,
108                                tiering_pred, tier,
109                                &move_stats);
110         }
111
112         return 0;
113 }
114
115 static void __bch2_tiering_stop(struct bch_tier *tier)
116 {
117         tier->pd.rate.rate = UINT_MAX;
118         bch2_ratelimit_reset(&tier->pd.rate);
119
120         if (tier->migrate)
121                 kthread_stop(tier->migrate);
122
123         tier->migrate = NULL;
124 }
125
126 void bch2_tiering_stop(struct bch_fs *c)
127 {
128         struct bch_tier *tier;
129
130         for (tier = c->tiers; tier < c->tiers + ARRAY_SIZE(c->tiers); tier++)
131                 __bch2_tiering_stop(tier);
132 }
133
134 static int __bch2_tiering_start(struct bch_tier *tier)
135 {
136         if (!tier->migrate) {
137                 struct task_struct *p =
138                         kthread_create(bch2_tiering_thread, tier,
139                                        "bch_tier[%u]", tier->idx);
140                 if (IS_ERR(p))
141                         return PTR_ERR(p);
142
143                 tier->migrate = p;
144         }
145
146         wake_up_process(tier->migrate);
147         return 0;
148 }
149
150 int bch2_tiering_start(struct bch_fs *c)
151 {
152         struct bch_tier *tier;
153         bool have_faster_tier = false;
154
155         if (c->opts.nochanges)
156                 return 0;
157
158         for (tier = c->tiers; tier < c->tiers + ARRAY_SIZE(c->tiers); tier++) {
159                 if (!dev_mask_nr(&tier->devs))
160                         continue;
161
162                 if (have_faster_tier) {
163                         int ret = __bch2_tiering_start(tier);
164                         if (ret)
165                                 return ret;
166                 } else {
167                         __bch2_tiering_stop(tier);
168                 }
169
170                 have_faster_tier = true;
171         }
172
173         return 0;
174 }
175
176 void bch2_fs_tiering_init(struct bch_fs *c)
177 {
178         unsigned i;
179
180         for (i = 0; i < ARRAY_SIZE(c->tiers); i++) {
181                 c->tiers[i].idx = i;
182                 bch2_pd_controller_init(&c->tiers[i].pd);
183         }
184 }