diff options
| author | Artem Bityutskiy <artem.bityutskiy@linux.intel.com> | 2012-05-07 12:02:46 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-05-14 00:24:23 -0400 |
| commit | 208b14e507c00ff7f108e1a388dd3d8cc805a443 (patch) | |
| tree | 34ec5a82825cf87d2d9a2856bde10f722a22cd14 /fs | |
| parent | e832579fd100eb4f9658bdfefd61caf86a6cbff1 (diff) | |
jffs2: get rid of jffs2_sync_super
Currently JFFS2 file-system maps the VFS "superblock" abstraction to the
write-buffer. Namely, it uses VFS services to synchronize the write-buffer
periodically.
The whole "superblock write-out" VFS infrastructure is served by the
'sync_supers()' kernel thread, which wakes up every 5 (by default) seconds and
writes out all dirty superblock using the '->write_super()' call-back. But the
problem with this thread is that it wastes power by waking up the system every
5 seconds no matter what. So we want to kill it completely and thus, we need to
make file-systems to stop using the '->write_super' VFS service, and then
remove it together with the kernel thread.
This patch switches the JFFS2 write-buffer management from
'->write_super()'/'->s_dirt' to a delayed work. Instead of setting the 's_dirt'
flag we just schedule a delayed work for synchronizing the write-buffer.
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 4 | ||||
| -rw-r--r-- | fs/jffs2/os-linux.h | 7 | ||||
| -rw-r--r-- | fs/jffs2/super.c | 13 | ||||
| -rw-r--r-- | fs/jffs2/wbuf.c | 55 |
4 files changed, 58 insertions, 21 deletions
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 0d00bf26923b..413ef89c2d1b 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
| @@ -133,6 +133,10 @@ struct jffs2_sb_info { | |||
| 133 | struct jffs2_inodirty *wbuf_inodes; | 133 | struct jffs2_inodirty *wbuf_inodes; |
| 134 | struct rw_semaphore wbuf_sem; /* Protects the write buffer */ | 134 | struct rw_semaphore wbuf_sem; /* Protects the write buffer */ |
| 135 | 135 | ||
| 136 | struct delayed_work wbuf_dwork; /* write-buffer write-out work */ | ||
| 137 | int wbuf_queued; /* non-zero delayed work is queued */ | ||
| 138 | spinlock_t wbuf_dwork_lock; /* protects wbuf_dwork and and wbuf_queued */ | ||
| 139 | |||
| 136 | unsigned char *oobbuf; | 140 | unsigned char *oobbuf; |
| 137 | int oobavail; /* How many bytes are available for JFFS2 in OOB */ | 141 | int oobavail; /* How many bytes are available for JFFS2 in OOB */ |
| 138 | #endif | 142 | #endif |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 1cd3aec9d9ae..bcd983d7e7f9 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
| @@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
| 95 | #define jffs2_ubivol(c) (0) | 95 | #define jffs2_ubivol(c) (0) |
| 96 | #define jffs2_ubivol_setup(c) (0) | 96 | #define jffs2_ubivol_setup(c) (0) |
| 97 | #define jffs2_ubivol_cleanup(c) do {} while (0) | 97 | #define jffs2_ubivol_cleanup(c) do {} while (0) |
| 98 | #define jffs2_dirty_trigger(c) do {} while (0) | ||
| 98 | 99 | ||
| 99 | #else /* NAND and/or ECC'd NOR support present */ | 100 | #else /* NAND and/or ECC'd NOR support present */ |
| 100 | 101 | ||
| @@ -135,14 +136,10 @@ void jffs2_ubivol_cleanup(struct jffs2_sb_info *c); | |||
| 135 | #define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && ! (c->mtd->flags & MTD_BIT_WRITEABLE)) | 136 | #define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && ! (c->mtd->flags & MTD_BIT_WRITEABLE)) |
| 136 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c); | 137 | int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c); |
| 137 | void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c); | 138 | void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c); |
| 139 | void jffs2_dirty_trigger(struct jffs2_sb_info *c); | ||
| 138 | 140 | ||
| 139 | #endif /* WRITEBUFFER */ | 141 | #endif /* WRITEBUFFER */ |
| 140 | 142 | ||
| 141 | static inline void jffs2_dirty_trigger(struct jffs2_sb_info *c) | ||
| 142 | { | ||
| 143 | OFNI_BS_2SFFJ(c)->s_dirt = 1; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* background.c */ | 143 | /* background.c */ |
| 147 | int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); | 144 | int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); |
| 148 | void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); | 145 | void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index b36aa950d2a6..61ea41389f90 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
| @@ -63,18 +63,6 @@ static void jffs2_i_init_once(void *foo) | |||
| 63 | inode_init_once(&f->vfs_inode); | 63 | inode_init_once(&f->vfs_inode); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | static void jffs2_write_super(struct super_block *sb) | ||
| 67 | { | ||
| 68 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | ||
| 69 | |||
| 70 | sb->s_dirt = 0; | ||
| 71 | |||
| 72 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 73 | jffs2_dbg(1, "%s()\n", __func__); | ||
| 74 | jffs2_flush_wbuf_gc(c, 0); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | static const char *jffs2_compr_name(unsigned int compr) | 66 | static const char *jffs2_compr_name(unsigned int compr) |
| 79 | { | 67 | { |
| 80 | switch (compr) { | 68 | switch (compr) { |
| @@ -263,7 +251,6 @@ static const struct super_operations jffs2_super_operations = | |||
| 263 | .alloc_inode = jffs2_alloc_inode, | 251 | .alloc_inode = jffs2_alloc_inode, |
| 264 | .destroy_inode =jffs2_destroy_inode, | 252 | .destroy_inode =jffs2_destroy_inode, |
| 265 | .put_super = jffs2_put_super, | 253 | .put_super = jffs2_put_super, |
| 266 | .write_super = jffs2_write_super, | ||
| 267 | .statfs = jffs2_statfs, | 254 | .statfs = jffs2_statfs, |
| 268 | .remount_fs = jffs2_remount_fs, | 255 | .remount_fs = jffs2_remount_fs, |
| 269 | .evict_inode = jffs2_evict_inode, | 256 | .evict_inode = jffs2_evict_inode, |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 74d9be19df3f..6f4529d3697f 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/mtd/nand.h> | 20 | #include <linux/mtd/nand.h> |
| 21 | #include <linux/jiffies.h> | 21 | #include <linux/jiffies.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/writeback.h> | ||
| 23 | 24 | ||
| 24 | #include "nodelist.h" | 25 | #include "nodelist.h" |
| 25 | 26 | ||
| @@ -85,7 +86,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) | |||
| 85 | { | 86 | { |
| 86 | struct jffs2_inodirty *new; | 87 | struct jffs2_inodirty *new; |
| 87 | 88 | ||
| 88 | /* Mark the superblock dirty so that kupdated will flush... */ | 89 | /* Schedule delayed write-buffer write-out */ |
| 89 | jffs2_dirty_trigger(c); | 90 | jffs2_dirty_trigger(c); |
| 90 | 91 | ||
| 91 | if (jffs2_wbuf_pending_for_ino(c, ino)) | 92 | if (jffs2_wbuf_pending_for_ino(c, ino)) |
| @@ -1148,6 +1149,47 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * | |||
| 1148 | return 1; | 1149 | return 1; |
| 1149 | } | 1150 | } |
| 1150 | 1151 | ||
| 1152 | static struct jffs2_sb_info *work_to_sb(struct work_struct *work) | ||
| 1153 | { | ||
| 1154 | struct delayed_work *dwork; | ||
| 1155 | |||
| 1156 | dwork = container_of(work, struct delayed_work, work); | ||
| 1157 | return container_of(dwork, struct jffs2_sb_info, wbuf_dwork); | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static void delayed_wbuf_sync(struct work_struct *work) | ||
| 1161 | { | ||
| 1162 | struct jffs2_sb_info *c = work_to_sb(work); | ||
| 1163 | struct super_block *sb = OFNI_BS_2SFFJ(c); | ||
| 1164 | |||
| 1165 | spin_lock(&c->wbuf_dwork_lock); | ||
| 1166 | c->wbuf_queued = 0; | ||
| 1167 | spin_unlock(&c->wbuf_dwork_lock); | ||
| 1168 | |||
| 1169 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 1170 | jffs2_dbg(1, "%s()\n", __func__); | ||
| 1171 | jffs2_flush_wbuf_gc(c, 0); | ||
| 1172 | } | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | void jffs2_dirty_trigger(struct jffs2_sb_info *c) | ||
| 1176 | { | ||
| 1177 | struct super_block *sb = OFNI_BS_2SFFJ(c); | ||
| 1178 | unsigned long delay; | ||
| 1179 | |||
| 1180 | if (sb->s_flags & MS_RDONLY) | ||
| 1181 | return; | ||
| 1182 | |||
| 1183 | spin_lock(&c->wbuf_dwork_lock); | ||
| 1184 | if (!c->wbuf_queued) { | ||
| 1185 | jffs2_dbg(1, "%s()\n", __func__); | ||
| 1186 | delay = msecs_to_jiffies(dirty_writeback_interval * 10); | ||
| 1187 | queue_delayed_work(system_long_wq, &c->wbuf_dwork, delay); | ||
| 1188 | c->wbuf_queued = 1; | ||
| 1189 | } | ||
| 1190 | spin_unlock(&c->wbuf_dwork_lock); | ||
| 1191 | } | ||
| 1192 | |||
| 1151 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | 1193 | int jffs2_nand_flash_setup(struct jffs2_sb_info *c) |
| 1152 | { | 1194 | { |
| 1153 | struct nand_ecclayout *oinfo = c->mtd->ecclayout; | 1195 | struct nand_ecclayout *oinfo = c->mtd->ecclayout; |
| @@ -1169,6 +1211,8 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) | |||
| 1169 | 1211 | ||
| 1170 | /* Initialise write buffer */ | 1212 | /* Initialise write buffer */ |
| 1171 | init_rwsem(&c->wbuf_sem); | 1213 | init_rwsem(&c->wbuf_sem); |
| 1214 | spin_lock_init(&c->wbuf_dwork_lock); | ||
| 1215 | INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); | ||
| 1172 | c->wbuf_pagesize = c->mtd->writesize; | 1216 | c->wbuf_pagesize = c->mtd->writesize; |
| 1173 | c->wbuf_ofs = 0xFFFFFFFF; | 1217 | c->wbuf_ofs = 0xFFFFFFFF; |
| 1174 | 1218 | ||
| @@ -1207,8 +1251,8 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { | |||
| 1207 | 1251 | ||
| 1208 | /* Initialize write buffer */ | 1252 | /* Initialize write buffer */ |
| 1209 | init_rwsem(&c->wbuf_sem); | 1253 | init_rwsem(&c->wbuf_sem); |
| 1210 | 1254 | spin_lock_init(&c->wbuf_dwork_lock); | |
| 1211 | 1255 | INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); | |
| 1212 | c->wbuf_pagesize = c->mtd->erasesize; | 1256 | c->wbuf_pagesize = c->mtd->erasesize; |
| 1213 | 1257 | ||
| 1214 | /* Find a suitable c->sector_size | 1258 | /* Find a suitable c->sector_size |
| @@ -1267,6 +1311,9 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) { | |||
| 1267 | 1311 | ||
| 1268 | /* Initialize write buffer */ | 1312 | /* Initialize write buffer */ |
| 1269 | init_rwsem(&c->wbuf_sem); | 1313 | init_rwsem(&c->wbuf_sem); |
| 1314 | spin_lock_init(&c->wbuf_dwork_lock); | ||
| 1315 | INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); | ||
| 1316 | |||
| 1270 | c->wbuf_pagesize = c->mtd->writesize; | 1317 | c->wbuf_pagesize = c->mtd->writesize; |
| 1271 | c->wbuf_ofs = 0xFFFFFFFF; | 1318 | c->wbuf_ofs = 0xFFFFFFFF; |
| 1272 | 1319 | ||
| @@ -1299,6 +1346,8 @@ int jffs2_ubivol_setup(struct jffs2_sb_info *c) { | |||
| 1299 | return 0; | 1346 | return 0; |
| 1300 | 1347 | ||
| 1301 | init_rwsem(&c->wbuf_sem); | 1348 | init_rwsem(&c->wbuf_sem); |
| 1349 | spin_lock_init(&c->wbuf_dwork_lock); | ||
| 1350 | INIT_DELAYED_WORK(&c->wbuf_dwork, delayed_wbuf_sync); | ||
| 1302 | 1351 | ||
| 1303 | c->wbuf_pagesize = c->mtd->writesize; | 1352 | c->wbuf_pagesize = c->mtd->writesize; |
| 1304 | c->wbuf_ofs = 0xFFFFFFFF; | 1353 | c->wbuf_ofs = 0xFFFFFFFF; |
