Commit b3c0460f authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

Copies PMFS into test-mods folder for isolation.

Simple boot code in place to load PMFS module in LCD. It all boots,
but nothing in the original PMFS is executed yet.

Ensure you do not build the non-isolated PMFS (in fs/pmfs) at the
same time. If you do, the build system will complain about symbol
redefinitions, etc.

Now for the painful decomposition...
parent 96f1da56
......@@ -12,7 +12,7 @@ if BLOCK
config FS_IOMAP
bool
depends on EXT2_FS_XIP || PMFS_XIP
depends on EXT2_FS_XIP || PMFS_XIP || LCD_TEST_MOD_PMFS
default y
source "fs/ext2/Kconfig"
......
......@@ -142,5 +142,26 @@ config LCD_TEST_MOD_CREATE_KLCD_KLCD
# --------------------------------------------------
config LCD_TEST_MOD_PMFS
bool "Persistent Memory File System (PMFS) Example"
depends on LCD_DOMAINS
depends on HAS_IOMEM
select CRC16
default y
select LCD_TEST_MOD_PMFS_BOOT
select LCD_TEST_MOD_PMFS_LCD
---help---
Isolation of PMFS file system.
config LCD_TEST_MOD_PMFS_BOOT
tristate
depends on LCD_TEST_MOD_PMFS
default m
config LCD_TEST_MOD_PMFS_LCD
tristate
depends on LCD_TEST_MOD_PMFS
default m
endif
......@@ -13,3 +13,5 @@ obj-$(CONFIG_LCD_TEST_MOD_IPC2) += ipc2/
obj-$(CONFIG_LCD_TEST_MOD_LIBLCD_TESTS) += liblcd-tests/
obj-$(CONFIG_LCD_TEST_MOD_CREATE_KLCD) += create-klcd/
obj-$(CONFIG_LCD_TEST_MOD_PMFS) += pmfs/
#---------- PMFS LCD ----------
# The original code
obj-$(CONFIG_LCD_TEST_MOD_PMFS_LCD) += lcd-test-mod-pmfs-lcd.o
lcd-test-mod-pmfs-lcd-y += $(addprefix pmfs/, bbuild.o \
balloc.o \
dir.o \
file.o \
inode.o \
namei.o \
super.o \
symlink.o \
ioctl.o \
journal.o \
xip.o \
wprotect.o)
lcd-test-mod-pmfs-lcd-y += $(addprefix lcd/, main.o)
lcd-test-mod-pmfs-lcd-y += $(LIBLCD)
#---------- BOOT ----------
obj-$(CONFIG_LCD_TEST_MOD_PMFS_BOOT) += lcd-test-mod-pmfs-boot.o
lcd-test-mod-pmfs-boot-y += $(addprefix boot/, main.o)
/**
* main.c - non-isolated kernel module, does setup
*
*/
#include <lcd-domains/kliblcd.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int boot_main(void)
{
int ret;
struct lcd_info *mi;
cptr_t lcd;
/*
* Enter lcd mode
*/
ret = lcd_enter();
if (ret) {
LIBLCD_ERR("enter");
goto fail1;
}
/*
* Create a new lcd
*/
ret = lcd_create_module_lcd(&lcd, "lcd_test_mod_pmfs_lcd",
LCD_CPTR_NULL, &mi);
if (ret) {
LIBLCD_ERR("create module lcd");
goto fail2;
}
/*
* Set up boot info
*/
ret = lcd_dump_boot_info(mi);
if (ret) {
LIBLCD_ERR("dump boot info");
goto fail3;
}
/*
* Run it
*/
ret = lcd_run(lcd);
if (ret) {
LIBLCD_ERR("run lcd");
goto fail4;
}
/*
* Wait for 1 second
*/
msleep(1000);
/*
* Tear everything down
*/
ret = 0;
goto out;
out:
fail4:
fail3:
lcd_destroy_module_lcd(lcd, mi, LCD_CPTR_NULL);
fail2:
lcd_exit(0);
fail1:
return ret;
}
static void boot_exit(void)
{
/* nothing to do */
}
module_init(boot_main);
module_exit(boot_exit);
/*
* main.c - runs when pmfs lcd boots
*/
#include <lcd-domains/liblcd-config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <lcd-domains/liblcd.h>
#include <lcd-domains/liblcd-hacks.h>
static int __noreturn __init pmfs_lcd_init(void)
{
int r;
r = lcd_enter();
if (r)
goto fail1;
fail1:
lcd_exit(r);
}
static void __exit pmfs_lcd_exit(void)
{
return;
}
module_init(pmfs_lcd_init);
module_exit(pmfs_lcd_exit);
config PMFS
tristate "Persistent and Protected PM file system support"
depends on HAS_IOMEM
select CRC16
help
If your system has a block of fast (comparable in access speed to
system memory) and non-volatile byte-addressable memory and you wish to
mount a light-weight, full-featured, and space-efficient filesystem over
it, say Y here, and read <file:Documentation/filesystems/pmfs.txt>.
To compile this as a module, choose M here: the module will be
called pmfs.
config PMFS_XIP
bool "Execute-in-place in PMFS"
depends on PMFS && BLOCK
help
Say Y here to enable XIP feature of PMFS.
config PMFS_WRITE_PROTECT
bool "PMFS write protection"
depends on PMFS && MMU && HAVE_SET_MEMORY_RO
default y
help
Say Y here to enable the write protect feature of PMFS.
config PMFS_TEST
boolean
depends on PMFS
config PMFS_TEST_MODULE
tristate "PMFS Test"
depends on PMFS && PMFS_WRITE_PROTECT && m
select PMFS_TEST
help
Say Y here to build a simple module to test the protection of
PMFS. The module will be called pmfs_test.
#
# Makefile for the linux pmfs-filesystem routines.
#
obj-$(CONFIG_PMFS) += pmfs.o
obj-$(CONFIG_PMFS_TEST_MODULE) += pmfs_test.o
pmfs-y := bbuild.o balloc.o dir.o file.o inode.o namei.o super.o symlink.o ioctl.o journal.o
pmfs-$(CONFIG_PMFS_WRITE_PROTECT) += wprotect.o
pmfs-$(CONFIG_PMFS_XIP) += xip.o
/*
* PMFS emulated persistence. This file contains code to
* handle data blocks of various sizes efficiently.
*
* Persistent Memory File System
* Copyright (c) 2012-2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/fs.h>
#include <linux/bitops.h>
#include "pmfs.h"
void pmfs_init_blockmap(struct super_block *sb, unsigned long init_used_size)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
unsigned long num_used_block;
struct pmfs_blocknode *blknode;
num_used_block = (init_used_size + sb->s_blocksize - 1) >>
sb->s_blocksize_bits;
blknode = pmfs_alloc_blocknode(sb);
if (blknode == NULL)
PMFS_ASSERT(0);
blknode->block_low = sbi->block_start;
blknode->block_high = sbi->block_start + num_used_block - 1;
sbi->num_free_blocks -= num_used_block;
list_add(&blknode->link, &sbi->block_inuse_head);
}
static struct pmfs_blocknode *pmfs_next_blocknode(struct pmfs_blocknode *i,
struct list_head *head)
{
if (list_is_last(&i->link, head))
return NULL;
return list_first_entry(&i->link, typeof(*i), link);
}
/* Caller must hold the super_block lock. If start_hint is provided, it is
* only valid until the caller releases the super_block lock. */
void __pmfs_free_block(struct super_block *sb, unsigned long blocknr,
unsigned short btype, struct pmfs_blocknode **start_hint)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
struct list_head *head = &(sbi->block_inuse_head);
unsigned long new_block_low;
unsigned long new_block_high;
unsigned long num_blocks = 0;
struct pmfs_blocknode *i;
struct pmfs_blocknode *free_blocknode= NULL;
struct pmfs_blocknode *curr_node;
num_blocks = pmfs_get_numblocks(btype);
new_block_low = blocknr;
new_block_high = blocknr + num_blocks - 1;
BUG_ON(list_empty(head));
if (start_hint && *start_hint &&
new_block_low >= (*start_hint)->block_low)
i = *start_hint;
else
i = list_first_entry(head, typeof(*i), link);
list_for_each_entry_from(i, head, link) {
if (new_block_low > i->block_high) {
/* skip to next blocknode */
continue;
}
if ((new_block_low == i->block_low) &&
(new_block_high == i->block_high)) {
/* fits entire datablock */
if (start_hint)
*start_hint = pmfs_next_blocknode(i, head);
list_del(&i->link);
free_blocknode = i;
sbi->num_blocknode_allocated--;
sbi->num_free_blocks += num_blocks;
goto block_found;
}
if ((new_block_low == i->block_low) &&
(new_block_high < i->block_high)) {
/* Aligns left */
i->block_low = new_block_high + 1;
sbi->num_free_blocks += num_blocks;
if (start_hint)
*start_hint = i;
goto block_found;
}
if ((new_block_low > i->block_low) &&
(new_block_high == i->block_high)) {
/* Aligns right */
i->block_high = new_block_low - 1;
sbi->num_free_blocks += num_blocks;
if (start_hint)
*start_hint = pmfs_next_blocknode(i, head);
goto block_found;
}
if ((new_block_low > i->block_low) &&
(new_block_high < i->block_high)) {
/* Aligns somewhere in the middle */
curr_node = pmfs_alloc_blocknode(sb);
PMFS_ASSERT(curr_node);
if (curr_node == NULL) {
/* returning without freeing the block*/
goto block_found;
}
curr_node->block_low = new_block_high + 1;
curr_node->block_high = i->block_high;
i->block_high = new_block_low - 1;
list_add(&curr_node->link, &i->link);
sbi->num_free_blocks += num_blocks;
if (start_hint)
*start_hint = curr_node;
goto block_found;
}
}
pmfs_error_mng(sb, "Unable to free block %ld\n", blocknr);
block_found:
if (free_blocknode)
__pmfs_free_blocknode(free_blocknode);
}
void pmfs_free_block(struct super_block *sb, unsigned long blocknr,
unsigned short btype)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
mutex_lock(&sbi->s_lock);
__pmfs_free_block(sb, blocknr, btype, NULL);
mutex_unlock(&sbi->s_lock);
}
int pmfs_new_block(struct super_block *sb, unsigned long *blocknr,
unsigned short btype, int zero)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
struct list_head *head = &(sbi->block_inuse_head);
struct pmfs_blocknode *i, *next_i;
struct pmfs_blocknode *free_blocknode= NULL;
void *bp;
unsigned long num_blocks = 0;
struct pmfs_blocknode *curr_node;
int errval = 0;
bool found = 0;
unsigned long next_block_low;
unsigned long new_block_low;
unsigned long new_block_high;
num_blocks = pmfs_get_numblocks(btype);
mutex_lock(&sbi->s_lock);
list_for_each_entry(i, head, link) {
if (i->link.next == head) {
next_i = NULL;
next_block_low = sbi->block_end;
} else {
next_i = list_entry(i->link.next, typeof(*i), link);
next_block_low = next_i->block_low;
}
new_block_low = (i->block_high + num_blocks) & ~(num_blocks - 1);
new_block_high = new_block_low + num_blocks - 1;
if (new_block_high >= next_block_low) {
/* Does not fit - skip to next blocknode */
continue;
}
if ((new_block_low == (i->block_high + 1)) &&
(new_block_high == (next_block_low - 1)))
{
/* Fill the gap completely */
if (next_i) {
i->block_high = next_i->block_high;
list_del(&next_i->link);
free_blocknode = next_i;
sbi->num_blocknode_allocated--;
} else {
i->block_high = new_block_high;
}
found = 1;
break;
}
if ((new_block_low == (i->block_high + 1)) &&
(new_block_high < (next_block_low - 1))) {
/* Aligns to left */
i->block_high = new_block_high;
found = 1;
break;
}
if ((new_block_low > (i->block_high + 1)) &&
(new_block_high == (next_block_low - 1))) {
/* Aligns to right */
if (next_i) {
/* right node exist */
next_i->block_low = new_block_low;
} else {
/* right node does NOT exist */
curr_node = pmfs_alloc_blocknode(sb);
PMFS_ASSERT(curr_node);
if (curr_node == NULL) {
errval = -ENOSPC;
break;
}
curr_node->block_low = new_block_low;
curr_node->block_high = new_block_high;
list_add(&curr_node->link, &i->link);
}
found = 1;
break;
}
if ((new_block_low > (i->block_high + 1)) &&
(new_block_high < (next_block_low - 1))) {
/* Aligns somewhere in the middle */
curr_node = pmfs_alloc_blocknode(sb);
PMFS_ASSERT(curr_node);
if (curr_node == NULL) {
errval = -ENOSPC;
break;
}
curr_node->block_low = new_block_low;
curr_node->block_high = new_block_high;
list_add(&curr_node->link, &i->link);
found = 1;
break;
}
}
if (found == 1) {
sbi->num_free_blocks -= num_blocks;
}
mutex_unlock(&sbi->s_lock);
if (free_blocknode)
__pmfs_free_blocknode(free_blocknode);
if (found == 0) {
return -ENOSPC;
}
if (zero) {
size_t size;
bp = pmfs_get_block(sb, pmfs_get_block_off(sb, new_block_low, btype));
pmfs_memunlock_block(sb, bp); //TBDTBD: Need to fix this
if (btype == PMFS_BLOCK_TYPE_4K)
size = 0x1 << 12;
else if (btype == PMFS_BLOCK_TYPE_2M)
size = 0x1 << 21;
else
size = 0x1 << 30;
memset_nt(bp, 0, size);
pmfs_memlock_block(sb, bp);
}
*blocknr = new_block_low;
return errval;
}
unsigned long pmfs_count_free_blocks(struct super_block *sb)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
return sbi->num_free_blocks;
}
/*
* PMFS emulated persistence. This file contains code to
* handle data blocks of various sizes efficiently.
*
* Persistent Memory File System
* Copyright (c) 2012-2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/fs.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include "pmfs.h"
struct scan_bitmap {
unsigned long bitmap_4k_size;
unsigned long bitmap_2M_size;
unsigned long bitmap_1G_size;
unsigned long *bitmap_4k;
unsigned long *bitmap_2M;
unsigned long *bitmap_1G;
};
static void pmfs_clear_datablock_inode(struct super_block *sb)
{
struct pmfs_inode *pi = pmfs_get_inode(sb, PMFS_BLOCKNODE_IN0);
pmfs_transaction_t *trans;
/* 2 log entry for inode */
trans = pmfs_new_transaction(sb, MAX_INODE_LENTRIES);
if (IS_ERR(trans))
return;
pmfs_add_logentry(sb, trans, pi, MAX_DATA_PER_LENTRY, LE_DATA);
pmfs_memunlock_inode(sb, pi);
memset(pi, 0, MAX_DATA_PER_LENTRY);
pmfs_memlock_inode(sb, pi);
/* commit the transaction */
pmfs_commit_transaction(sb, trans);
}
static void pmfs_init_blockmap_from_inode(struct super_block *sb)
{
struct pmfs_sb_info *sbi = PMFS_SB(sb);
struct pmfs_inode *pi = pmfs_get_inode(sb, PMFS_BLOCKNODE_IN0);
struct pmfs_blocknode_lowhigh *p = NULL;
struct pmfs_blocknode *blknode;
unsigned long index;
unsigned long blocknr;
unsigned long i;
unsigned long num_blocknode;
u64 bp;
num_blocknode = sbi->num_blocknode_allocated;
sbi->num_blocknode_allocated = 0;
for (i=0; i<num_blocknode; i++) {
index = i & 0xFF;
if (index == 0) {
/* Find and get new data block */
blocknr = i >> 8; /* 256 Entries in a block */
bp = __pmfs_find_data_block(sb, pi, blocknr);
p = pmfs_get_block(sb, bp);
}
PMFS_ASSERT(p);
blknode = pmfs_alloc_blocknode(sb);
if (blknode == NULL)
PMFS_ASSERT(0);
blknode->block_low = le64_to_cpu(p[index].block_low);
blknode->block_high = le64_to_cpu(p[index].block_high);
list_add_tail(&blknode->link, &sbi->block_inuse_head);
}
}
static bool pmfs_can_skip_full_scan(struct super_block *sb)
{
struct pmfs_inode *pi = pmfs_get_inode(sb, PMFS_BLOCKNODE_IN0);
struct pmfs_super_block *super = pmfs_get_super(sb);
struct pmfs_sb_info *sbi = PMFS_SB(sb);
__le64 root;
unsigned int height, btype;
unsigned long last_blocknr;
if (!pi->root)
return false;
sbi->num_blocknode_allocated =
le64_to_cpu(super->s_num_blocknode_allocated);
sbi->num_free_blocks = le64_to_cpu(super->s_num_free_blocks);
sbi->s_inodes_count = le32_to_cpu(super->s_inodes_count);
sbi->s_free_inodes_count = le32_to_cpu(super->s_free_inodes_count);
sbi->s_inodes_used_count = le32_to_cpu(super->s_inodes_used_count);
sbi->s_free_inode_hint = le32_to_cpu(super->s_free_inode_hint);
pmfs_init_blockmap_from_inode(sb);
root = pi->