aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-05-28 09:24:15 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2009-06-08 04:14:58 -0400
commitf2c5dbd7b7396457efc114f825acfdd4db4608f8 (patch)
tree9c65570230dfc05b8580c86db0154b6b2a98515c
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>
-rw-r--r--fs/ubifs/io.c34
-rw-r--r--fs/ubifs/super.c6
-rw-r--r--fs/ubifs/ubifs.h13
3 files changed, 32 insertions, 21 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)
293 * 293 *
294 * This function is called when the write-buffer timer expires. 294 * This function is called when the write-buffer timer expires.
295 */ 295 */
296static void wbuf_timer_callback_nolock(unsigned long data) 296static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
297{ 297{
298 struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data; 298 struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
299 299
300 wbuf->need_sync = 1; 300 wbuf->need_sync = 1;
301 wbuf->c->need_wbuf_sync = 1; 301 wbuf->c->need_wbuf_sync = 1;
302 ubifs_wake_up_bgt(wbuf->c); 302 ubifs_wake_up_bgt(wbuf->c);
303 return HRTIMER_NORESTART;
303} 304}
304 305
305/** 306/**
@@ -308,13 +309,12 @@ static void wbuf_timer_callback_nolock(unsigned long data)
308 */ 309 */
309static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) 310static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
310{ 311{
311 ubifs_assert(!timer_pending(&wbuf->timer)); 312 ubifs_assert(!hrtimer_active(&wbuf->timer));
312 313
313 if (!wbuf->timeout) 314 if (!ktime_to_ns(wbuf->softlimit))
314 return; 315 return;
315 316 hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
316 wbuf->timer.expires = jiffies + wbuf->timeout; 317 HRTIMER_MODE_REL);
317 add_timer(&wbuf->timer);
318} 318}
319 319
320/** 320/**
@@ -329,7 +329,7 @@ static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
329 * should be canceled. 329 * should be canceled.
330 */ 330 */
331 wbuf->need_sync = 0; 331 wbuf->need_sync = 0;
332 del_timer(&wbuf->timer); 332 hrtimer_cancel(&wbuf->timer);
333} 333}
334 334
335/** 335/**
@@ -825,6 +825,7 @@ out:
825int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) 825int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
826{ 826{
827 size_t size; 827 size_t size;
828 ktime_t hardlimit;
828 829
829 wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL); 830 wbuf->buf = kmalloc(c->min_io_size, GFP_KERNEL);
830 if (!wbuf->buf) 831 if (!wbuf->buf)
@@ -845,14 +846,21 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
845 wbuf->sync_callback = NULL; 846 wbuf->sync_callback = NULL;
846 mutex_init(&wbuf->io_mutex); 847 mutex_init(&wbuf->io_mutex);
847 spin_lock_init(&wbuf->lock); 848 spin_lock_init(&wbuf->lock);
848
849 wbuf->c = c; 849 wbuf->c = c;
850 init_timer(&wbuf->timer);
851 wbuf->timer.function = wbuf_timer_callback_nolock;
852 wbuf->timer.data = (unsigned long)wbuf;
853 wbuf->timeout = DEFAULT_WBUF_TIMEOUT;
854 wbuf->next_ino = 0; 850 wbuf->next_ino = 0;
855 851
852 hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
853 wbuf->timer.function = wbuf_timer_callback_nolock;
854 /*
855 * Make write-buffer soft limit to be 20% of the hard limit. The
856 * write-buffer timer is allowed to expire any time between the soft
857 * and hard limits.
858 */
859 hardlimit = ktime_set(DEFAULT_WBUF_TIMEOUT_SECS, 0);
860 wbuf->delta = (DEFAULT_WBUF_TIMEOUT_SECS * NSEC_PER_SEC) * 2 / 10;
861 wbuf->softlimit = ktime_sub_ns(hardlimit, wbuf->delta);
862 hrtimer_set_expires_range_ns(&wbuf->timer, wbuf->softlimit,
863 wbuf->delta);
856 return 0; 864 return 0;
857} 865}
858 866
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b9b051a4c01e..91c91cb7a599 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -799,7 +799,7 @@ static int alloc_wbufs(struct ubifs_info *c)
799 * does not need to be synchronized by timer. 799 * does not need to be synchronized by timer.
800 */ 800 */
801 c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; 801 c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
802 c->jheads[GCHD].wbuf.timeout = 0; 802 c->jheads[GCHD].wbuf.softlimit = ktime_set(0, 0);
803 803
804 return 0; 804 return 0;
805} 805}
@@ -1695,7 +1695,7 @@ static void ubifs_remount_ro(struct ubifs_info *c)
1695 1695
1696 for (i = 0; i < c->jhead_cnt; i++) { 1696 for (i = 0; i < c->jhead_cnt; i++) {
1697 ubifs_wbuf_sync(&c->jheads[i].wbuf); 1697 ubifs_wbuf_sync(&c->jheads[i].wbuf);
1698 del_timer_sync(&c->jheads[i].wbuf.timer); 1698 hrtimer_cancel(&c->jheads[i].wbuf.timer);
1699 } 1699 }
1700 1700
1701 c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); 1701 c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
@@ -1755,7 +1755,7 @@ static void ubifs_put_super(struct super_block *sb)
1755 if (c->jheads) 1755 if (c->jheads)
1756 for (i = 0; i < c->jhead_cnt; i++) { 1756 for (i = 0; i < c->jhead_cnt; i++) {
1757 ubifs_wbuf_sync(&c->jheads[i].wbuf); 1757 ubifs_wbuf_sync(&c->jheads[i].wbuf);
1758 del_timer_sync(&c->jheads[i].wbuf.timer); 1758 hrtimer_cancel(&c->jheads[i].wbuf.timer);
1759 } 1759 }
1760 1760
1761 /* 1761 /*
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 0a8341e14088..1bf01d820066 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -95,8 +95,8 @@
95 */ 95 */
96#define BGT_NAME_PATTERN "ubifs_bgt%d_%d" 96#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
97 97
98/* Default write-buffer synchronization timeout (5 secs) */ 98/* Default write-buffer synchronization timeout in seconds */
99#define DEFAULT_WBUF_TIMEOUT (5 * HZ) 99#define DEFAULT_WBUF_TIMEOUT_SECS 5
100 100
101/* Maximum possible inode number (only 32-bit inodes are supported now) */ 101/* Maximum possible inode number (only 32-bit inodes are supported now) */
102#define MAX_INUM 0xFFFFFFFF 102#define MAX_INUM 0xFFFFFFFF
@@ -650,8 +650,10 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
650 * @io_mutex: serializes write-buffer I/O 650 * @io_mutex: serializes write-buffer I/O
651 * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes 651 * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
652 * fields 652 * fields
653 * @softlimit: soft write-buffer timeout interval
654 * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit
655 * and @softlimit + @delta)
653 * @timer: write-buffer timer 656 * @timer: write-buffer timer
654 * @timeout: timer expire interval in jiffies
655 * @need_sync: it is set if its timer expired and needs sync 657 * @need_sync: it is set if its timer expired and needs sync
656 * @next_ino: points to the next position of the following inode number 658 * @next_ino: points to the next position of the following inode number
657 * @inodes: stores the inode numbers of the nodes which are in wbuf 659 * @inodes: stores the inode numbers of the nodes which are in wbuf
@@ -678,8 +680,9 @@ struct ubifs_wbuf {
678 int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); 680 int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
679 struct mutex io_mutex; 681 struct mutex io_mutex;
680 spinlock_t lock; 682 spinlock_t lock;
681 struct timer_list timer; 683 ktime_t softlimit;
682 int timeout; 684 unsigned long long delta;
685 struct hrtimer timer;
683 int need_sync; 686 int need_sync;
684 int next_ino; 687 int next_ino;
685 ino_t *inodes; 688 ino_t *inodes;