diff options
Diffstat (limited to 'fs/logfs')
| -rw-r--r-- | fs/logfs/Kconfig | 4 | ||||
| -rw-r--r-- | fs/logfs/dev_bdev.c | 73 | ||||
| -rw-r--r-- | fs/logfs/dir.c | 51 | ||||
| -rw-r--r-- | fs/logfs/file.c | 13 | ||||
| -rw-r--r-- | fs/logfs/inode.c | 29 | ||||
| -rw-r--r-- | fs/logfs/journal.c | 2 | ||||
| -rw-r--r-- | fs/logfs/readwrite.c | 21 | ||||
| -rw-r--r-- | fs/logfs/segment.c | 8 | ||||
| -rw-r--r-- | fs/logfs/super.c | 1 |
9 files changed, 96 insertions, 106 deletions
diff --git a/fs/logfs/Kconfig b/fs/logfs/Kconfig index daf9a9b32dd..09ed066c022 100644 --- a/fs/logfs/Kconfig +++ b/fs/logfs/Kconfig @@ -1,6 +1,6 @@ config LOGFS - tristate "LogFS file system (EXPERIMENTAL)" - depends on (MTD || BLOCK) && EXPERIMENTAL + tristate "LogFS file system" + depends on (MTD || BLOCK) select ZLIB_INFLATE select ZLIB_DEFLATE select CRC32 diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index df0de27c273..76279e11982 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -14,34 +14,23 @@ #define PAGE_OFS(ofs) ((ofs) & (PAGE_SIZE-1)) -static void request_complete(struct bio *bio, int err) -{ - complete((struct completion *)bio->bi_private); -} - static int sync_request(struct page *page, struct block_device *bdev, int rw) { struct bio bio; struct bio_vec bio_vec; - struct completion complete; bio_init(&bio); + bio.bi_max_vecs = 1; bio.bi_io_vec = &bio_vec; bio_vec.bv_page = page; bio_vec.bv_len = PAGE_SIZE; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_idx = 0; - bio.bi_size = PAGE_SIZE; bio.bi_bdev = bdev; - bio.bi_sector = page->index * (PAGE_SIZE >> 9); - init_completion(&complete); - bio.bi_private = &complete; - bio.bi_end_io = request_complete; - - submit_bio(rw, &bio); - wait_for_completion(&complete); - return test_bit(BIO_UPTODATE, &bio.bi_flags) ? 0 : -EIO; + bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9); + bio.bi_iter.bi_size = PAGE_SIZE; + + return submit_bio_wait(rw, &bio); } static int bdev_readpage(void *_sb, struct page *page) @@ -67,22 +56,18 @@ static DECLARE_WAIT_QUEUE_HEAD(wq); static void writeseg_end_io(struct bio *bio, int err) { const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; + struct bio_vec *bvec; + int i; struct super_block *sb = bio->bi_private; struct logfs_super *super = logfs_super(sb); - struct page *page; BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */ BUG_ON(err); - BUG_ON(bio->bi_vcnt == 0); - do { - page = bvec->bv_page; - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); - - end_page_writeback(page); - page_cache_release(page); - } while (bvec >= bio->bi_io_vec); + + bio_for_each_segment_all(bvec, bio, i) { + end_page_writeback(bvec->bv_page); + page_cache_release(bvec->bv_page); + } bio_put(bio); if (atomic_dec_and_test(&super->s_pending_writes)) wake_up(&wq); @@ -95,12 +80,11 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, struct address_space *mapping = super->s_mapping_inode->i_mapping; struct bio *bio; struct page *page; - struct request_queue *q = bdev_get_queue(sb->s_bdev); - unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); + unsigned int max_pages; int i; - if (max_pages > BIO_MAX_PAGES) - max_pages = BIO_MAX_PAGES; + max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev)); + bio = bio_alloc(GFP_NOFS, max_pages); BUG_ON(!bio); @@ -108,10 +92,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_idx = 0; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -136,10 +119,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, unlock_page(page); } bio->bi_vcnt = nr_pages; - bio->bi_idx = 0; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -190,12 +172,11 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, { struct logfs_super *super = logfs_super(sb); struct bio *bio; - struct request_queue *q = bdev_get_queue(sb->s_bdev); - unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9); + unsigned int max_pages; int i; - if (max_pages > BIO_MAX_PAGES) - max_pages = BIO_MAX_PAGES; + max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev)); + bio = bio_alloc(GFP_NOFS, max_pages); BUG_ON(!bio); @@ -203,10 +184,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_idx = 0; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); @@ -225,10 +205,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_io_vec[i].bv_offset = 0; } bio->bi_vcnt = nr_pages; - bio->bi_idx = 0; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 26e4a941532..6bdc347008f 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -281,17 +281,23 @@ static int logfs_rmdir(struct inode *dir, struct dentry *dentry) /* FIXME: readdir currently has it's own dir_walk code. I don't see a good * way to combine the two copies */ -#define IMPLICIT_NODES 2 -static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir) +static int logfs_readdir(struct file *file, struct dir_context *ctx) { - struct inode *dir = file->f_dentry->d_inode; - loff_t pos = file->f_pos - IMPLICIT_NODES; + struct inode *dir = file_inode(file); + loff_t pos; struct page *page; struct logfs_disk_dentry *dd; - int full; + if (ctx->pos < 0) + return -EINVAL; + + if (!dir_emit_dots(file, ctx)) + return 0; + + pos = ctx->pos - 2; BUG_ON(pos < 0); - for (;; pos++) { + for (;; pos++, ctx->pos++) { + bool full; if (beyond_eof(dir, pos)) break; if (!logfs_exist_block(dir, pos)) { @@ -306,42 +312,17 @@ static int __logfs_readdir(struct file *file, void *buf, filldir_t filldir) dd = kmap(page); BUG_ON(dd->namelen == 0); - full = filldir(buf, (char *)dd->name, be16_to_cpu(dd->namelen), - pos, be64_to_cpu(dd->ino), dd->type); + full = !dir_emit(ctx, (char *)dd->name, + be16_to_cpu(dd->namelen), + be64_to_cpu(dd->ino), dd->type); kunmap(page); page_cache_release(page); if (full) break; } - - file->f_pos = pos + IMPLICIT_NODES; return 0; } -static int logfs_readdir(struct file *file, void *buf, filldir_t filldir) -{ - struct inode *inode = file->f_dentry->d_inode; - ino_t pino = parent_ino(file->f_dentry); - int err; - - if (file->f_pos < 0) - return -EINVAL; - - if (file->f_pos == 0) { - if (filldir(buf, ".", 1, 1, inode->i_ino, DT_DIR) < 0) - return 0; - file->f_pos++; - } - if (file->f_pos == 1) { - if (filldir(buf, "..", 2, 2, pino, DT_DIR) < 0) - return 0; - file->f_pos++; - } - - err = __logfs_readdir(file, buf, filldir); - return err; -} - static void logfs_set_name(struct logfs_disk_dentry *dd, struct qstr *name) { dd->namelen = cpu_to_be16(name->len); @@ -814,7 +795,7 @@ const struct inode_operations logfs_dir_iops = { const struct file_operations logfs_dir_fops = { .fsync = logfs_fsync, .unlocked_ioctl = logfs_ioctl, - .readdir = logfs_readdir, + .iterate = logfs_readdir, .read = generic_read_dir, .llseek = default_llseek, }; diff --git a/fs/logfs/file.c b/fs/logfs/file.c index 3886cded283..8538752df2f 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -159,7 +159,8 @@ static int logfs_writepage(struct page *page, struct writeback_control *wbc) return __logfs_writepage(page); } -static void logfs_invalidatepage(struct page *page, unsigned long offset) +static void logfs_invalidatepage(struct page *page, unsigned int offset, + unsigned int length) { struct logfs_block *block = logfs_block(page); @@ -183,7 +184,7 @@ static int logfs_releasepage(struct page *page, gfp_t only_xfs_uses_this) long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); struct logfs_inode *li = logfs_inode(inode); unsigned int oldflags, flags; int err; @@ -263,15 +264,15 @@ const struct inode_operations logfs_reg_iops = { }; const struct file_operations logfs_reg_fops = { - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, .fsync = logfs_fsync, .unlocked_ioctl = logfs_ioctl, .llseek = generic_file_llseek, .mmap = generic_file_readonly_mmap, .open = generic_file_open, - .read = do_sync_read, - .write = do_sync_write, + .read = new_sync_read, + .write = new_sync_write, }; const struct address_space_operations logfs_reg_aops = { diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index a422f42238b..af49e2d6941 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c @@ -33,7 +33,7 @@ * are being written out - and waiting for GC to make progress, naturally. * * So we cannot just call iget() or some variant of it, but first have to check - * wether the inode in question might be in I_FREEING state. Therefore we + * whether the inode in question might be in I_FREEING state. Therefore we * maintain our own per-sb list of "almost deleted" inodes and check against * that list first. Normally this should be at most 1-2 entries long. * @@ -156,10 +156,26 @@ static void __logfs_destroy_inode(struct inode *inode) call_rcu(&inode->i_rcu, logfs_i_callback); } +static void __logfs_destroy_meta_inode(struct inode *inode) +{ + struct logfs_inode *li = logfs_inode(inode); + BUG_ON(li->li_block); + call_rcu(&inode->i_rcu, logfs_i_callback); +} + static void logfs_destroy_inode(struct inode *inode) { struct logfs_inode *li = logfs_inode(inode); + if (inode->i_ino < LOGFS_RESERVED_INOS) { + /* + * The reserved inodes are never destroyed unless we are in + * unmont path. + */ + __logfs_destroy_meta_inode(inode); + return; + } + BUG_ON(list_empty(&li->li_freeing_list)); spin_lock(&logfs_inode_lock); li->li_refcount--; @@ -192,8 +208,8 @@ static void logfs_init_inode(struct super_block *sb, struct inode *inode) li->li_height = 0; li->li_used_bytes = 0; li->li_block = NULL; - inode->i_uid = 0; - inode->i_gid = 0; + i_uid_write(inode, 0); + i_gid_write(inode, 0); inode->i_size = 0; inode->i_blocks = 0; inode->i_ctime = CURRENT_TIME; @@ -373,8 +389,8 @@ static void logfs_put_super(struct super_block *sb) { struct logfs_super *super = logfs_super(sb); /* kill the meta-inodes */ - iput(super->s_master_inode); iput(super->s_segfile_inode); + iput(super->s_master_inode); iput(super->s_mapping_inode); } @@ -401,5 +417,10 @@ int logfs_init_inode_cache(void) void logfs_destroy_inode_cache(void) { + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); kmem_cache_destroy(logfs_inode_cache); } diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 1e1c369df22..2a09b8d7398 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c @@ -565,7 +565,7 @@ static void write_wbuf(struct super_block *sb, struct logfs_area *area, index = ofs >> PAGE_SHIFT; page_ofs = ofs & (PAGE_SIZE - 1); - page = find_lock_page(mapping, index); + page = find_or_create_page(mapping, index, GFP_NOFS); BUG_ON(!page); memcpy(wbuf, page_address(page) + page_ofs, super->s_writesize); unlock_page(page); diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index f1cb512c501..48140315f62 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c @@ -119,8 +119,8 @@ static void logfs_disk_to_inode(struct logfs_disk_inode *di, struct inode*inode) inode->i_mode = be16_to_cpu(di->di_mode); li->li_height = di->di_height; li->li_flags = be32_to_cpu(di->di_flags); - inode->i_uid = be32_to_cpu(di->di_uid); - inode->i_gid = be32_to_cpu(di->di_gid); + i_uid_write(inode, be32_to_cpu(di->di_uid)); + i_gid_write(inode, be32_to_cpu(di->di_gid)); inode->i_size = be64_to_cpu(di->di_size); logfs_set_blocks(inode, be64_to_cpu(di->di_used_bytes)); inode->i_atime = be64_to_timespec(di->di_atime); @@ -156,8 +156,8 @@ static void logfs_inode_to_disk(struct inode *inode, struct logfs_disk_inode*di) di->di_height = li->li_height; di->di_pad = 0; di->di_flags = cpu_to_be32(li->li_flags); - di->di_uid = cpu_to_be32(inode->i_uid); - di->di_gid = cpu_to_be32(inode->i_gid); + di->di_uid = cpu_to_be32(i_uid_read(inode)); + di->di_gid = cpu_to_be32(i_gid_read(inode)); di->di_size = cpu_to_be64(i_size_read(inode)); di->di_used_bytes = cpu_to_be64(li->li_used_bytes); di->di_atime = timespec_to_be64(inode->i_atime); @@ -1887,9 +1887,15 @@ int logfs_truncate(struct inode *inode, u64 target) logfs_put_wblocks(sb, NULL, 1); } - if (!err) - err = vmtruncate(inode, target); + if (!err) { + err = inode_newsize_ok(inode, target); + if (err) + goto out; + + truncate_setsize(inode, target); + } + out: /* I don't trust error recovery yet. */ WARN_ON(err); return err; @@ -2174,7 +2180,7 @@ void logfs_evict_inode(struct inode *inode) do_delete_inode(inode); } } - truncate_inode_pages(&inode->i_data, 0); + truncate_inode_pages_final(&inode->i_data); clear_inode(inode); /* Cheaper version of write_inode. All changes are concealed in @@ -2189,7 +2195,6 @@ void logfs_evict_inode(struct inode *inode) return; } - BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS); page = inode_to_page(inode); BUG_ON(!page); /* FIXME: Use emergency page */ logfs_put_write_page(page); diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index e28d090c98d..7f9b096d8d5 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c @@ -62,7 +62,8 @@ static struct page *get_mapping_page(struct super_block *sb, pgoff_t index, page = read_cache_page(mapping, index, filler, sb); else { page = find_or_create_page(mapping, index, GFP_NOFS); - unlock_page(page); + if (page) + unlock_page(page); } return page; } @@ -884,9 +885,10 @@ static struct logfs_area *alloc_area(struct super_block *sb) return area; } -static void map_invalidatepage(struct page *page, unsigned long l) +static void map_invalidatepage(struct page *page, unsigned int o, + unsigned int l) { - BUG(); + return; } static int map_releasepage(struct page *page, gfp_t g) diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 345c24b8a6f..54360293bcb 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -608,6 +608,7 @@ static struct file_system_type logfs_fs_type = { .fs_flags = FS_REQUIRES_DEV, }; +MODULE_ALIAS_FS("logfs"); static int __init logfs_init(void) { |
