/*
* fs/logfs/segment.c - Handling the Object Store
*
* As should be obvious for Linux kernel code, license is GPLv2
*
* Copyright (c) 2005-2008 Joern Engel <joern@logfs.org>
*
* Object store or ostore makes up the complete device with exception of
* the superblock and journal areas. Apart from its own metadata it stores
* three kinds of objects: inodes, dentries and blocks, both data and indirect.
*/
#include "logfs.h"
#include <linux/slab.h>
static int logfs_mark_segment_bad(struct super_block *sb, u32 segno)
{
struct logfs_super *super = logfs_super(sb);
struct btree_head32 *head = &super->s_reserved_segments;
int err;
err = btree_insert32(head, segno, (void *)1, GFP_NOFS);
if (err)
return err;
logfs_super(sb)->s_bad_segments++;
/* FIXME: write to journal */
return 0;
}
int logfs_erase_segment(struct super_block *sb, u32 segno, int ensure_erase)
{
struct logfs_super *super = logfs_super(sb);
super->s_gec++;
return super->s_devops->erase(sb, (u64)segno << super->s_segshift,
super->s_segsize, ensure_erase);
}
static s64 logfs_get_free_bytes(struct logfs_area *area, size_t bytes)
{
s32 ofs;
logfs_open_area(area, bytes);
ofs = area->a_used_bytes;
area->a_used_bytes += bytes;
BUG_ON(area->a_used_bytes >= logfs_super(area->a_sb)->s_segsize);
return dev_ofs(area->a_sb, area->a_segno, ofs);
}
static struct page *get_mapping_page(struct super_block *sb, pgoff_t index,
int use_filler)
{
struct logfs_super *super = logfs_super(sb);
struct address_space *mapping = super->s_mapping_inode->i_mapping;
filler_t *filler = super->s_devops->readpage;
struct page *page;
BUG_ON(mapping_gfp_mask(mapping) & __GFP_FS);
if (use_filler)
page = read_cache_page(mapping, index, filler, sb);
else {
page = find_or_create_page(mapping, index, GFP_NOFS);
unlock_page(page);
}
return page;
}
int __logfs_buf_write(struct logfs_area *area, u64 ofs, void *buf, size_t len,
int use_filler)
{
pgoff_t index = ofs >> PAGE_SHIFT;
struct page *page;
long offset = ofs & (PAGE_SIZE-1);
long copylen;
/* Only logfs_wbuf_recover may use len==0 */
BUG_ON(!len && !use_filler);
do {
copylen = min((ulong)len, PAGE_SIZE - offset);
page = get_mapping_page(area->a_sb, index, use_filler);
if (IS_ERR(page))
return PTR_ERR(page);
BUG_ON(!page); /* FIXME: reserve a pool */
SetPageUptodate(page);
memcpy(page_address(page) + offset, buf, copylen);
if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page);
buf += copylen;
len -= copylen;
offset = 0;
index++;
} while (len);
return 0;
}
static void pad_partial_page(struct logfs_area *area)
{
struct super_block *sb = area->a_sb;
struct page *page;
u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes);
pgoff_t index = ofs >> PAGE_SHIFT;
long offset = ofs & (PAGE_SIZE-1);
u32 len = PAGE_SIZE - offset;
if (len % PAGE_SIZE) {
page = get_mapping_page(sb, index, 0);
BUG_ON(!page); /* FIXME: reserve a pool */
memset(page_address(page) + offset, 0xff, len);
if (!PagePrivate(page)) {
SetPagePrivate(page);
page_cache_get(page);
}
page_cache_release(page);
}
}
static void pad_full_pages(struct logfs_area *area)
{
struct super_block *sb = area->a_sb;
struct logfs_super *super = logfs_super(sb);
u64 ofs = dev_ofs(sb, area->a_segno, area->a_used_bytes