Commit d3712b9d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://github.com/prasad-joshi/logfs_upstream

There are few important bug fixes for LogFS

* tag 'for-linus' of git://github.com/prasad-joshi/logfs_upstream:
  Logfs: Allow NULL block_isbad() methods
  logfs: Grow inode in delete path
  logfs: Free areas before calling generic_shutdown_super()
  logfs: remove useless BUG_ON
  MAINTAINERS: Add Prasad Joshi in LogFS maintiners
  logfs: Propagate page parameter to __logfs_write_inode
  logfs: set superblock shutdown flag after generic sb shutdown
  logfs: take write mutex lock during fsync and sync
  logfs: Prevent memory corruption
  logfs: update page reference count for pined pages

Fix up conflict in fs/logfs/dev_mtd.c due to semantic change in what
"mtd->block_isbad" means in commit f2933e86: "Logfs: Allow NULL
block_isbad() methods" clashing with the abstraction changes in the
commits 7086c19d: "mtd: introduce mtd_block_isbad interface" and
d58b27ed: "logfs: do not use 'mtd->block_isbad' directly".

This resolution takes the semantics from commit f2933e86, and just
makes mtd_block_isbad() return zero (false) if the 'block_isbad'
function is NULL.  But that also means that now "mtd_can_have_bb()"
always returns 0.

Now, "mtd_block_markbad()" will obviously return an error if the
low-level driver doesn't support bad blocks, so this is somewhat
non-symmetric, but it actually makes sense if a NULL "block_isbad"
function is considered to mean "I assume that all my blocks are always
good".
parents c5d2bc11 f2933e86
...@@ -4140,6 +4140,7 @@ F: fs/partitions/ldm.* ...@@ -4140,6 +4140,7 @@ F: fs/partitions/ldm.*
LogFS LogFS
M: Joern Engel <joern@logfs.org> M: Joern Engel <joern@logfs.org>
M: Prasad Joshi <prasadjoshi.linux@gmail.com>
L: logfs@logfs.org L: logfs@logfs.org
W: logfs.org W: logfs.org
S: Maintained S: Maintained
......
...@@ -71,7 +71,7 @@ static int write_dir(struct inode *dir, struct logfs_disk_dentry *dd, ...@@ -71,7 +71,7 @@ static int write_dir(struct inode *dir, struct logfs_disk_dentry *dd,
static int write_inode(struct inode *inode) static int write_inode(struct inode *inode)
{ {
return __logfs_write_inode(inode, WF_LOCK); return __logfs_write_inode(inode, NULL, WF_LOCK);
} }
static s64 dir_seek_data(struct inode *inode, s64 pos) static s64 dir_seek_data(struct inode *inode, s64 pos)
......
...@@ -230,7 +230,9 @@ int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -230,7 +230,9 @@ int logfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
return ret; return ret;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
logfs_get_wblocks(sb, NULL, WF_LOCK);
logfs_write_anchor(sb); logfs_write_anchor(sb);
logfs_put_wblocks(sb, NULL, WF_LOCK);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return 0; return 0;
......
...@@ -367,7 +367,7 @@ static struct gc_candidate *get_candidate(struct super_block *sb) ...@@ -367,7 +367,7 @@ static struct gc_candidate *get_candidate(struct super_block *sb)
int i, max_dist; int i, max_dist;
struct gc_candidate *cand = NULL, *this; struct gc_candidate *cand = NULL, *this;
max_dist = min(no_free_segments(sb), LOGFS_NO_AREAS); max_dist = min(no_free_segments(sb), LOGFS_NO_AREAS - 1);
for (i = max_dist; i >= 0; i--) { for (i = max_dist; i >= 0; i--) {
this = first_in_list(&super->s_low_list[i]); this = first_in_list(&super->s_low_list[i]);
......
...@@ -286,7 +286,7 @@ static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc) ...@@ -286,7 +286,7 @@ static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc)
if (logfs_inode(inode)->li_flags & LOGFS_IF_STILLBORN) if (logfs_inode(inode)->li_flags & LOGFS_IF_STILLBORN)
return 0; return 0;
ret = __logfs_write_inode(inode, flags); ret = __logfs_write_inode(inode, NULL, flags);
LOGFS_BUG_ON(ret, inode->i_sb); LOGFS_BUG_ON(ret, inode->i_sb);
return ret; return ret;
} }
...@@ -363,7 +363,9 @@ static void logfs_init_once(void *_li) ...@@ -363,7 +363,9 @@ static void logfs_init_once(void *_li)
static int logfs_sync_fs(struct super_block *sb, int wait) static int logfs_sync_fs(struct super_block *sb, int wait)
{ {
logfs_get_wblocks(sb, NULL, WF_LOCK);
logfs_write_anchor(sb); logfs_write_anchor(sb);
logfs_put_wblocks(sb, NULL, WF_LOCK);
return 0; return 0;
} }
......
...@@ -612,7 +612,6 @@ static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type, ...@@ -612,7 +612,6 @@ static size_t __logfs_write_je(struct super_block *sb, void *buf, u16 type,
if (len == 0) if (len == 0)
return logfs_write_header(super, header, 0, type); return logfs_write_header(super, header, 0, type);
BUG_ON(len > sb->s_blocksize);
compr_len = logfs_compress(buf, data, len, sb->s_blocksize); compr_len = logfs_compress(buf, data, len, sb->s_blocksize);
if (compr_len < 0 || type == JE_ANCHOR) { if (compr_len < 0 || type == JE_ANCHOR) {
memcpy(data, buf, len); memcpy(data, buf, len);
......
...@@ -528,7 +528,7 @@ void logfs_destroy_inode_cache(void); ...@@ -528,7 +528,7 @@ void logfs_destroy_inode_cache(void);
void logfs_set_blocks(struct inode *inode, u64 no); void logfs_set_blocks(struct inode *inode, u64 no);
/* these logically belong into inode.c but actually reside in readwrite.c */ /* these logically belong into inode.c but actually reside in readwrite.c */
int logfs_read_inode(struct inode *inode); int logfs_read_inode(struct inode *inode);
int __logfs_write_inode(struct inode *inode, long flags); int __logfs_write_inode(struct inode *inode, struct page *, long flags);
void logfs_evict_inode(struct inode *inode); void logfs_evict_inode(struct inode *inode);
/* journal.c */ /* journal.c */
...@@ -577,6 +577,8 @@ void initialize_block_counters(struct page *page, struct logfs_block *block, ...@@ -577,6 +577,8 @@ void initialize_block_counters(struct page *page, struct logfs_block *block,
__be64 *array, int page_is_empty); __be64 *array, int page_is_empty);
int logfs_exist_block(struct inode *inode, u64 bix); int logfs_exist_block(struct inode *inode, u64 bix);
int get_page_reserve(struct inode *inode, struct page *page); int get_page_reserve(struct inode *inode, struct page *page);
void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock);
void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock);
extern struct logfs_block_ops indirect_block_ops; extern struct logfs_block_ops indirect_block_ops;
/* segment.c */ /* segment.c */
...@@ -594,6 +596,7 @@ int logfs_init_mapping(struct super_block *sb); ...@@ -594,6 +596,7 @@ int logfs_init_mapping(struct super_block *sb);
void logfs_sync_area(struct logfs_area *area); void logfs_sync_area(struct logfs_area *area);
void logfs_sync_segments(struct super_block *sb); void logfs_sync_segments(struct super_block *sb);
void freeseg(struct super_block *sb, u32 segno); void freeseg(struct super_block *sb, u32 segno);
void free_areas(struct super_block *sb);
/* area handling */ /* area handling */
int logfs_init_areas(struct super_block *sb); int logfs_init_areas(struct super_block *sb);
......
...@@ -244,8 +244,7 @@ static void preunlock_page(struct super_block *sb, struct page *page, int lock) ...@@ -244,8 +244,7 @@ static void preunlock_page(struct super_block *sb, struct page *page, int lock)
* is waiting for s_write_mutex. We annotate this fact by setting PG_pre_locked * is waiting for s_write_mutex. We annotate this fact by setting PG_pre_locked
* in addition to PG_locked. * in addition to PG_locked.
*/ */
static void logfs_get_wblocks(struct super_block *sb, struct page *page, void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock)
int lock)
{ {
struct logfs_super *super = logfs_super(sb); struct logfs_super *super = logfs_super(sb);
...@@ -260,8 +259,7 @@ static void logfs_get_wblocks(struct super_block *sb, struct page *page, ...@@ -260,8 +259,7 @@ static void logfs_get_wblocks(struct super_block *sb, struct page *page,
} }
} }
static void logfs_put_wblocks(struct super_block *sb, struct page *page, void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock)
int lock)
{ {
struct logfs_super *super = logfs_super(sb); struct logfs_super *super = logfs_super(sb);
...@@ -424,7 +422,7 @@ static void inode_write_block(struct logfs_block *block) ...@@ -424,7 +422,7 @@ static void inode_write_block(struct logfs_block *block)
if (inode->i_ino == LOGFS_INO_MASTER) if (inode->i_ino == LOGFS_INO_MASTER)
logfs_write_anchor(inode->i_sb); logfs_write_anchor(inode->i_sb);
else { else {
ret = __logfs_write_inode(inode, 0); ret = __logfs_write_inode(inode, NULL, 0);
/* see indirect_write_block comment */ /* see indirect_write_block comment */
BUG_ON(ret); BUG_ON(ret);
} }
...@@ -560,8 +558,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block) ...@@ -560,8 +558,13 @@ static void inode_free_block(struct super_block *sb, struct logfs_block *block)
static void indirect_free_block(struct super_block *sb, static void indirect_free_block(struct super_block *sb,
struct logfs_block *block) struct logfs_block *block)
{ {
ClearPagePrivate(block->page); struct page *page = block->page;
block->page->private = 0;
if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
__free_block(sb, block); __free_block(sb, block);
} }
...@@ -650,8 +653,11 @@ static void alloc_data_block(struct inode *inode, struct page *page) ...@@ -650,8 +653,11 @@ static void alloc_data_block(struct inode *inode, struct page *page)
logfs_unpack_index(page->index, &bix, &level); logfs_unpack_index(page->index, &bix, &level);
block = __alloc_block(inode->i_sb, inode->i_ino, bix, level); block = __alloc_block(inode->i_sb, inode->i_ino, bix, level);
block->page = page; block->page = page;
SetPagePrivate(page); SetPagePrivate(page);
page->private = (unsigned long)block; page_cache_get(page);
set_page_private(page, (unsigned long) block);
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
} }
...@@ -1570,11 +1576,15 @@ int logfs_write_buf(struct inode *inode, struct page *page, long flags) ...@@ -1570,11 +1576,15 @@ int logfs_write_buf(struct inode *inode, struct page *page, long flags)
static int __logfs_delete(struct inode *inode, struct page *page) static int __logfs_delete(struct inode *inode, struct page *page)
{ {
long flags = WF_DELETE; long flags = WF_DELETE;
int err;
inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_ctime = inode->i_mtime = CURRENT_TIME;
if (page->index < I0_BLOCKS) if (page->index < I0_BLOCKS)
return logfs_write_direct(inode, page, flags); return logfs_write_direct(inode, page, flags);
err = grow_inode(inode, page->index, 0);
if (err)
return err;
return logfs_write_rec(inode, page, page->index, 0, flags); return logfs_write_rec(inode, page, page->index, 0, flags);
} }
...@@ -1623,7 +1633,7 @@ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, ...@@ -1623,7 +1633,7 @@ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs,
if (inode->i_ino == LOGFS_INO_MASTER) if (inode->i_ino == LOGFS_INO_MASTER)
logfs_write_anchor(inode->i_sb); logfs_write_anchor(inode->i_sb);
else { else {
err = __logfs_write_inode(inode, flags); err = __logfs_write_inode(inode, page, flags);
} }
} }
} }
...@@ -1873,7 +1883,7 @@ int logfs_truncate(struct inode *inode, u64 target) ...@@ -1873,7 +1883,7 @@ int logfs_truncate(struct inode *inode, u64 target)
logfs_get_wblocks(sb, NULL, 1); logfs_get_wblocks(sb, NULL, 1);
err = __logfs_truncate(inode, size); err = __logfs_truncate(inode, size);
if (!err) if (!err)
err = __logfs_write_inode(inode, 0); err = __logfs_write_inode(inode, NULL, 0);
logfs_put_wblocks(sb, NULL, 1); logfs_put_wblocks(sb, NULL, 1);
} }
...@@ -1901,8 +1911,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page) ...@@ -1901,8 +1911,11 @@ static void move_page_to_inode(struct inode *inode, struct page *page)
li->li_block = block; li->li_block = block;
block->page = NULL; block->page = NULL;
page->private = 0; if (PagePrivate(page)) {
ClearPagePrivate(page); ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
} }
static void move_inode_to_page(struct page *page, struct inode *inode) static void move_inode_to_page(struct page *page, struct inode *inode)
...@@ -1918,8 +1931,12 @@ static void move_inode_to_page(struct page *page, struct inode *inode) ...@@ -1918,8 +1931,12 @@ static void move_inode_to_page(struct page *page, struct inode *inode)
BUG_ON(PagePrivate(page)); BUG_ON(PagePrivate(page));
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
block->page = page; block->page = page;
page->private = (unsigned long)block;
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
set_page_private(page, (unsigned long) block);
}
block->inode = NULL; block->inode = NULL;
li->li_block = NULL; li->li_block = NULL;
...@@ -2106,14 +2123,14 @@ void logfs_set_segment_unreserved(struct super_block *sb, u32 segno, u32 ec) ...@@ -2106,14 +2123,14 @@ void logfs_set_segment_unreserved(struct super_block *sb, u32 segno, u32 ec)
ec_level); ec_level);
} }
int __logfs_write_inode(struct inode *inode, long flags) int __logfs_write_inode(struct inode *inode, struct page *page, long flags)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int ret; int ret;
logfs_get_wblocks(sb, NULL, flags & WF_LOCK); logfs_get_wblocks(sb, page, flags & WF_LOCK);
ret = do_write_inode(inode); ret = do_write_inode(inode);
logfs_put_wblocks(sb, NULL, flags & WF_LOCK); logfs_put_wblocks(sb, page, flags & WF_LOCK);
return ret; return ret;
} }
......
...@@ -86,7 +86,11 @@ int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len, ...@@ -86,7 +86,11 @@ int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len,
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
SetPageUptodate(page); SetPageUptodate(page);
memcpy(page_address(page) + offset, buf, copylen); memcpy(page_address(page) + offset, buf, copylen);
SetPagePrivate(page);
if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
buf += copylen; buf += copylen;
...@@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area) ...@@ -110,7 +114,10 @@ static void pad_partial_page(struct logfs_area *area)
page = get_mapping_page(sb, index, 0); page = get_mapping_page(sb, index, 0);
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
memset(page_address(page) + offset, 0xff, len); memset(page_address(page) + offset, 0xff, len);
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
} }
} }
...@@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area) ...@@ -130,7 +137,10 @@ static void pad_full_pages(struct logfs_area *area)
BUG_ON(!page); /* FIXME: reserve a pool */ BUG_ON(!page); /* FIXME: reserve a pool */
SetPageUptodate(page); SetPageUptodate(page);
memset(page_address(page), 0xff, PAGE_CACHE_SIZE); memset(page_address(page), 0xff, PAGE_CACHE_SIZE);
SetPagePrivate(page); if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page); page_cache_release(page);
index++; index++;
no_indizes--; no_indizes--;
...@@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page, ...@@ -485,8 +495,12 @@ static void move_btree_to_page(struct inode *inode, struct page *page,
mempool_free(item, super->s_alias_pool); mempool_free(item, super->s_alias_pool);
} }
block->page = page; block->page = page;
SetPagePrivate(page);
page->private = (unsigned long)block; if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
set_page_private(page, (unsigned long) block);
}
block->ops = &indirect_block_ops; block->ops = &indirect_block_ops;
initialize_block_counters(page, block, data, 0); initialize_block_counters(page, block, data, 0);
} }
...@@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page) ...@@ -536,8 +550,12 @@ void move_page_to_btree(struct page *page)
list_add(&item->list, &block->item_list); list_add(&item->list, &block->item_list);
} }
block->page = NULL; block->page = NULL;
ClearPagePrivate(page);
page->private = 0; if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
set_page_private(page, 0);
}
block->ops = &btree_block_ops; block->ops = &btree_block_ops;
err = alias_tree_insert(block->sb, block->ino, block->bix, block->level, err = alias_tree_insert(block->sb, block->ino, block->bix, block->level,
block); block);
...@@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno) ...@@ -702,7 +720,10 @@ void freeseg(struct super_block *sb, u32 segno)
page = find_get_page(mapping, ofs >> PAGE_SHIFT); page = find_get_page(mapping, ofs >> PAGE_SHIFT);
if (!page) if (!page)
continue; continue;
ClearPagePrivate(page); if (PagePrivate(page)) {
ClearPagePrivate(page);
page_cache_release(page);
}
page_cache_release(page); page_cache_release(page);
} }
} }
...@@ -841,6 +862,16 @@ static void free_area(struct logfs_area *area) ...@@ -841,6 +862,16 @@ static void free_area(struct logfs_area *area)
kfree(area); kfree(area);
} }
void free_areas(struct super_block *sb)
{
struct logfs_super *super = logfs_super(sb);
int i;
for_each_area(i)
free_area(super->s_area[i]);
free_area(super->s_journal_area);
}
static struct logfs_area *alloc_area(struct super_block *sb) static struct logfs_area *alloc_area(struct super_block *sb)
{ {
struct logfs_area *area; struct logfs_area *area;
...@@ -923,10 +954,6 @@ int logfs_init_areas(struct super_block *sb) ...@@ -923,10 +954,6 @@ int logfs_init_areas(struct super_block *sb)
void logfs_cleanup_areas(struct super_block *sb) void logfs_cleanup_areas(struct super_block *sb)
{ {
struct logfs_super *super = logfs_super(sb); struct logfs_super *super = logfs_super(sb);
int i;
btree_grim_visitor128(&super->s_object_alias_tree, 0, kill_alias); btree_grim_visitor128(&super->s_object_alias_tree, 0, kill_alias);
for_each_area(i)
free_area(super->s_area[i]);
free_area(super->s_journal_area);
} }
...@@ -486,14 +486,15 @@ static void logfs_kill_sb(struct super_block *sb) ...@@ -486,14 +486,15 @@ static void logfs_kill_sb(struct super_block *sb)
/* Alias entries slow down mount, so evict as many as possible */ /* Alias entries slow down mount, so evict as many as possible */
sync_filesystem(sb); sync_filesystem(sb);
logfs_write_anchor(sb); logfs_write_anchor(sb);
free_areas(sb);
/* /*
* From this point on alias entries are simply dropped - and any * From this point on alias entries are simply dropped - and any
* writes to the object store are considered bugs. * writes to the object store are considered bugs.
*/ */
super->s_flags |= LOGFS_SB_FLAG_SHUTDOWN;
log_super("LogFS: Now in shutdown\n"); log_super("LogFS: Now in shutdown\n");
generic_shutdown_super(sb); generic_shutdown_super(sb);
super->s_flags |= LOGFS_SB_FLAG_SHUTDOWN;
BUG_ON(super->s_dirty_used_bytes || super->s_dirty_free_bytes); BUG_ON(super->s_dirty_used_bytes || super->s_dirty_free_bytes);
......
...@@ -441,7 +441,7 @@ static inline void mtd_resume(struct mtd_info *mtd) ...@@ -441,7 +441,7 @@ static inline void mtd_resume(struct mtd_info *mtd)
static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) static inline int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs)
{ {
if (!mtd->block_isbad) if (!mtd->block_isbad)
return -EOPNOTSUPP; return 0;
return mtd->block_isbad(mtd, ofs); return mtd->block_isbad(mtd, ofs);
} }
...@@ -489,7 +489,7 @@ static inline int mtd_has_oob(const struct mtd_info *mtd) ...@@ -489,7 +489,7 @@ static inline int mtd_has_oob(const struct mtd_info *mtd)
static inline int mtd_can_have_bb(const struct mtd_info *mtd) static inline int mtd_can_have_bb(const struct mtd_info *mtd)
{ {
return !!mtd->block_isbad; return 0;
} }
/* Kernel-side ioctl definitions */ /* Kernel-side ioctl definitions */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment