Skip to content

Commit

Permalink
UBIFS: start using hrtimers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Artem Bityutskiy authored and Artem Bityutskiy committed Jun 8, 2009
1 parent 8daa21e commit f2c5dbd
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 21 deletions.
34 changes: 21 additions & 13 deletions fs/ubifs/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -825,6 +825,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
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)
Expand All @@ -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;
}

Expand Down
6 changes: 3 additions & 3 deletions fs/ubifs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ static int alloc_wbufs(struct ubifs_info *c)
* does not need to be synchronized by timer.
*/
c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
c->jheads[GCHD].wbuf.timeout = 0;
c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0);

return 0;
}
Expand Down Expand Up @@ -1695,7 +1695,7 @@ static void ubifs_remount_ro(struct ubifs_info *c)

for (i = 0; i < c->jhead_cnt; i++) {
ubifs_wbuf_sync(&c->jheads[i].wbuf);
del_timer_sync(&c->jheads[i].wbuf.timer);
hrtimer_cancel(&c->jheads[i].wbuf.timer);
}

c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
Expand Down Expand Up @@ -1755,7 +1755,7 @@ static void ubifs_put_super(struct super_block *sb)
if (c->jheads)
for (i = 0; i < c->jhead_cnt; i++) {
ubifs_wbuf_sync(&c->jheads[i].wbuf);
del_timer_sync(&c->jheads[i].wbuf.timer);
hrtimer_cancel(&c->jheads[i].wbuf.timer);
}

/*
Expand Down
13 changes: 8 additions & 5 deletions fs/ubifs/ubifs.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@
*/
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"

/* Default write-buffer synchronization timeout (5 secs) */
#define DEFAULT_WBUF_TIMEOUT (5 * HZ)
/* Default write-buffer synchronization timeout in seconds */
#define DEFAULT_WBUF_TIMEOUT_SECS 5

/* Maximum possible inode number (only 32-bit inodes are supported now) */
#define MAX_INUM 0xFFFFFFFF
Expand Down Expand Up @@ -650,8 +650,10 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @io_mutex: serializes write-buffer I/O
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
* fields
* @softlimit: soft write-buffer timeout interval
* @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
* and @softlimit + @delta)
* @timer: write-buffer timer
* @timeout: timer expire interval in jiffies
* @need_sync: it is set if its timer expired and needs sync
* @next_ino: points to the next position of the following inode number
* @inodes: stores the inode numbers of the nodes which are in wbuf
Expand All @@ -678,8 +680,9 @@ struct ubifs_wbuf {
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
struct mutex io_mutex;
spinlock_t lock;
struct timer_list timer;
int timeout;
ktime_t softlimit;
unsigned long long delta;
struct hrtimer timer;
int need_sync;
int next_ino;
ino_t *inodes;
Expand Down

0 comments on commit f2c5dbd

Please sign in to comment.