aboutsummaryrefslogtreecommitdiff
path: root/fs/ubifs/io.c
diff options
context:
space:
mode:
authorArtem Bityutskiy2009-05-28 16:24:15 +0300
committerArtem Bityutskiy2009-06-08 11:14:58 +0300
commitf2c5dbd7b7396457efc114f825acfdd4db4608f8 (patch)
tree9c65570230dfc05b8580c86db0154b6b2a98515c /fs/ubifs/io.c
parent8daa21e61be47a5b136c4ee1be82e391a5788696 (diff)
UBIFS: start using hrtimers
UBIFS uses timers for write-buffer write-back. It is not crucial for us to write-back exactly on time. We are fine to write-back a little earlier or later. And this means we may optimize UBIFS timer so that it could be groped with a close timer event, so that the CPU would not be waken up just to do the write back. This is optimization to lessen power consumption, which is important in embedded devices UBIFS is used for. hrtimers have a nice feature: they are effectively range timers, and we may defind the soft and hard limits for it. Standard timers do not have these feature. They may only be made deferrable, but this means there is effectively no hard limit. So, we will better use hrtimers. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'fs/ubifs/io.c')
-rw-r--r--fs/ubifs/io.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index e8e632a1dcdf..bc5857199ec2 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -293,13 +293,14 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
*
* This function is called when the write-buffer timer expires.
*/
-static void wbuf_timer_callback_nolock(unsigned long data)
+static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
{
- struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data;
+ struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
wbuf->need_sync = 1;
wbuf->c->need_wbuf_sync = 1;
ubifs_wake_up_bgt(wbuf->c);
+ return HRTIMER_NORESTART;
}
/**
@@ -308,13 +309,12 @@ static void wbuf_timer_callback_nolock(unsigned long data)
*/
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
{
- ubifs_assert(!timer_pending(&wbuf->timer));
+ ubifs_assert(!hrtimer_active(&wbuf->timer));
- if (!wbuf->timeout)
+ if (!ktime_to_ns(wbuf->softlimit))
return;
-
- wbuf->timer.expires = jiffies + wbuf->timeout;
- add_timer(&wbuf->timer);
+ hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
+ HRTIMER_MODE_REL);
}
/**
@@ -329,7 +329,7 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
* should be canceled.
*/
wbuf->need_sync = 0;
- del_timer(&wbuf->timer);
+ hrtimer_cancel(&wbuf->timer);
}
/**
@@ -825,6 +825,7 @@ out:
int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
{
size_t size;
+ ktime_t hardlimit;
wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
if (!wbuf->buf)
@@ -845,14 +846,21 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
wbuf->sync_callback = NULL;
mutex_init(&wbuf->io_mutex);
spin_lock_init(&wbuf->lock);
-
wbuf->c = c;
- init_timer(&wbuf->timer);
- wbuf->timer.function = wbuf_timer_callback_nolock;
- wbuf->timer.data = (unsigned long)wbuf;
- wbuf->timeout = DEFAULT_WBUF_TIMEOUT;
wbuf->next_ino = 0;
+ hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ wbuf->timer.function = wbuf_timer_callback_nolock;
+ /*
+ * Make write-buffer soft limit to be 20% of the hard limit. The
+ * write-buffer timer is allowed to expire any time between the soft
+ * and hard limits.
+ */
+ hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
+ wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
+ wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
+ hrtimer_set_expires_range_ns(&wbuf->timer, wbuf->softlimit,
+ wbuf->delta);
return 0;
}