~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/bcachefs/clock.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include "bcachefs.h"
  3 #include "clock.h"
  4 
  5 #include <linux/freezer.h>
  6 #include <linux/kthread.h>
  7 #include <linux/preempt.h>
  8 
  9 static inline bool io_timer_cmp(const void *l, const void *r, void __always_unused *args)
 10 {
 11         struct io_timer **_l = (struct io_timer **)l;
 12         struct io_timer **_r = (struct io_timer **)r;
 13 
 14         return (*_l)->expire < (*_r)->expire;
 15 }
 16 
 17 static inline void io_timer_swp(void *l, void *r, void __always_unused *args)
 18 {
 19         struct io_timer **_l = (struct io_timer **)l;
 20         struct io_timer **_r = (struct io_timer **)r;
 21 
 22         swap(*_l, *_r);
 23 }
 24 
 25 void bch2_io_timer_add(struct io_clock *clock, struct io_timer *timer)
 26 {
 27         const struct min_heap_callbacks callbacks = {
 28                 .less = io_timer_cmp,
 29                 .swp = io_timer_swp,
 30         };
 31 
 32         spin_lock(&clock->timer_lock);
 33 
 34         if (time_after_eq64((u64) atomic64_read(&clock->now), timer->expire)) {
 35                 spin_unlock(&clock->timer_lock);
 36                 timer->fn(timer);
 37                 return;
 38         }
 39 
 40         for (size_t i = 0; i < clock->timers.nr; i++)
 41                 if (clock->timers.data[i] == timer)
 42                         goto out;
 43 
 44         BUG_ON(!min_heap_push(&clock->timers, &timer, &callbacks, NULL));
 45 out:
 46         spin_unlock(&clock->timer_lock);
 47 }
 48 
 49 void bch2_io_timer_del(struct io_clock *clock, struct io_timer *timer)
 50 {
 51         const struct min_heap_callbacks callbacks = {
 52                 .less = io_timer_cmp,
 53                 .swp = io_timer_swp,
 54         };
 55 
 56         spin_lock(&clock->timer_lock);
 57 
 58         for (size_t i = 0; i < clock->timers.nr; i++)
 59                 if (clock->timers.data[i] == timer) {
 60                         min_heap_del(&clock->timers, i, &callbacks, NULL);
 61                         break;
 62                 }
 63 
 64         spin_unlock(&clock->timer_lock);
 65 }
 66 
 67 struct io_clock_wait {
 68         struct io_timer         io_timer;
 69         struct timer_list       cpu_timer;
 70         struct task_struct      *task;
 71         int                     expired;
 72 };
 73 
 74 static void io_clock_wait_fn(struct io_timer *timer)
 75 {
 76         struct io_clock_wait *wait = container_of(timer,
 77                                 struct io_clock_wait, io_timer);
 78 
 79         wait->expired = 1;
 80         wake_up_process(wait->task);
 81 }
 82 
 83 static void io_clock_cpu_timeout(struct timer_list *timer)
 84 {
 85         struct io_clock_wait *wait = container_of(timer,
 86                                 struct io_clock_wait, cpu_timer);
 87 
 88         wait->expired = 1;
 89         wake_up_process(wait->task);
 90 }
 91 
 92 void bch2_io_clock_schedule_timeout(struct io_clock *clock, u64 until)
 93 {
 94         struct io_clock_wait wait = {
 95                 .io_timer.expire        = until,
 96                 .io_timer.fn            = io_clock_wait_fn,
 97                 .io_timer.fn2           = (void *) _RET_IP_,
 98                 .task                   = current,
 99         };
100 
101         bch2_io_timer_add(clock, &wait.io_timer);
102         schedule();
103         bch2_io_timer_del(clock, &wait.io_timer);
104 }
105 
106 void bch2_kthread_io_clock_wait(struct io_clock *clock,
107                                 u64 io_until, unsigned long cpu_timeout)
108 {
109         bool kthread = (current->flags & PF_KTHREAD) != 0;
110         struct io_clock_wait wait = {
111                 .io_timer.expire        = io_until,
112                 .io_timer.fn            = io_clock_wait_fn,
113                 .io_timer.fn2           = (void *) _RET_IP_,
114                 .task                   = current,
115         };
116 
117         bch2_io_timer_add(clock, &wait.io_timer);
118 
119         timer_setup_on_stack(&wait.cpu_timer, io_clock_cpu_timeout, 0);
120 
121         if (cpu_timeout != MAX_SCHEDULE_TIMEOUT)
122                 mod_timer(&wait.cpu_timer, cpu_timeout + jiffies);
123 
124         do {
125                 set_current_state(TASK_INTERRUPTIBLE);
126                 if (kthread && kthread_should_stop())
127                         break;
128 
129                 if (wait.expired)
130                         break;
131 
132                 schedule();
133                 try_to_freeze();
134         } while (0);
135 
136         __set_current_state(TASK_RUNNING);
137         del_timer_sync(&wait.cpu_timer);
138         destroy_timer_on_stack(&wait.cpu_timer);
139         bch2_io_timer_del(clock, &wait.io_timer);
140 }
141 
142 static struct io_timer *get_expired_timer(struct io_clock *clock, u64 now)
143 {
144         struct io_timer *ret = NULL;
145         const struct min_heap_callbacks callbacks = {
146                 .less = io_timer_cmp,
147                 .swp = io_timer_swp,
148         };
149 
150         if (clock->timers.nr &&
151             time_after_eq64(now, clock->timers.data[0]->expire)) {
152                 ret = *min_heap_peek(&clock->timers);
153                 min_heap_pop(&clock->timers, &callbacks, NULL);
154         }
155 
156         return ret;
157 }
158 
159 void __bch2_increment_clock(struct io_clock *clock, u64 sectors)
160 {
161         struct io_timer *timer;
162         u64 now = atomic64_add_return(sectors, &clock->now);
163 
164         spin_lock(&clock->timer_lock);
165         while ((timer = get_expired_timer(clock, now)))
166                 timer->fn(timer);
167         spin_unlock(&clock->timer_lock);
168 }
169 
170 void bch2_io_timers_to_text(struct printbuf *out, struct io_clock *clock)
171 {
172         out->atomic++;
173         spin_lock(&clock->timer_lock);
174         u64 now = atomic64_read(&clock->now);
175 
176         printbuf_tabstop_push(out, 40);
177         prt_printf(out, "current time:\t%llu\n", now);
178 
179         for (unsigned i = 0; i < clock->timers.nr; i++)
180                 prt_printf(out, "%ps %ps:\t%llu\n",
181                        clock->timers.data[i]->fn,
182                        clock->timers.data[i]->fn2,
183                        clock->timers.data[i]->expire);
184         spin_unlock(&clock->timer_lock);
185         --out->atomic;
186 }
187 
188 void bch2_io_clock_exit(struct io_clock *clock)
189 {
190         free_heap(&clock->timers);
191         free_percpu(clock->pcpu_buf);
192 }
193 
194 int bch2_io_clock_init(struct io_clock *clock)
195 {
196         atomic64_set(&clock->now, 0);
197         spin_lock_init(&clock->timer_lock);
198 
199         clock->max_slop = IO_CLOCK_PCPU_SECTORS * num_possible_cpus();
200 
201         clock->pcpu_buf = alloc_percpu(*clock->pcpu_buf);
202         if (!clock->pcpu_buf)
203                 return -BCH_ERR_ENOMEM_io_clock_init;
204 
205         if (!init_heap(&clock->timers, NR_IO_TIMERS, GFP_KERNEL))
206                 return -BCH_ERR_ENOMEM_io_clock_init;
207 
208         return 0;
209 }
210 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php