super.c 4.9 KB
Newer Older
W
wangchenyang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/*
 * JFFS2 -- Journalling Flash File System, Version 2.
 *
 * Copyright © 2001-2007 Red Hat, Inc.
 *
 * Created by David Woodhouse <dwmw2@infradead.org>
 *
 * For licensing information, see the file 'LICENCE' in this directory.
 *
 */


#include "jffs2.h"
#include "nodelist.h"
#include "jffs2_fs_sb.h"
#include "mtd_dev.h"
#include "mtd_partition.h"
#include "compr.h"
#include "jffs2_hash.h"

static unsigned char jffs2_mounted_number = 0; /* a counter to track the number of jffs2 instances mounted */
struct MtdNorDev jffs2_dev_list[CONFIG_MTD_PATTITION_NUM];

/*
 * fill in the superblock
 */
int jffs2_fill_super(struct super_block *sb)
{
	int ret;
	struct jffs2_sb_info *c;
	struct MtdNorDev *device;

	c = JFFS2_SB_INFO(sb);
	device = (struct MtdNorDev*)(sb->s_dev);

	(void)mutex_init(&c->alloc_sem);
	(void)mutex_init(&c->erase_free_sem);
	spin_lock_init(&c->erase_completion_lock);
	spin_lock_init(&c->inocache_lock);

	/* sector size is the erase block size */
	c->sector_size = device->blockSize;
	c->flash_size  = (device->blockEnd - device->blockStart + 1) * device->blockSize;
	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);

	ret = jffs2_do_mount_fs(c);
	if (ret) {
		(void)mutex_destroy(&c->alloc_sem);
		(void)mutex_destroy(&c->erase_free_sem);
		return ret;
	}
	D1(printk(KERN_DEBUG "jffs2_fill_super(): Getting root inode\n"));

	sb->s_root = jffs2_iget(sb, 1);

	if (IS_ERR(sb->s_root)) {
		D1(printk(KERN_WARNING "get root inode failed\n"));
		ret = PTR_ERR(sb->s_root);
		sb->s_root = NULL;
		jffs2_free_ino_caches(c);
		jffs2_free_raw_node_refs(c);
		free(c->blocks);
		(void)mutex_destroy(&c->alloc_sem);
		(void)mutex_destroy(&c->erase_free_sem);

		return ret;
	}
	return 0;
}

int jffs2_mount(int part_no, struct jffs2_inode **root_node)
{
	struct super_block *sb = NULL;
	struct jffs2_sb_info *c = NULL;
	LOS_DL_LIST *part_head = NULL;
	struct MtdDev *spinor_mtd = NULL;
	mtd_partition *mtd_part = GetSpinorPartitionHead();
	int ret;

	jffs2_dbg(1, "begin los_jffs2_mount:%d\n", part_no);

	sb = zalloc(sizeof(struct super_block));
	if (sb == NULL) {
		return -ENOMEM;
	}

	ret = Jffs2HashInit(&sb->s_node_hash_lock, &sb->s_node_hash[0]);
	if (ret) {
		free(sb);
		return ret;
	}
	part_head = &(GetSpinorPartitionHead()->node_info);
	LOS_DL_LIST_FOR_EACH_ENTRY(mtd_part,part_head, mtd_partition, node_info) {
		if (mtd_part->patitionnum == part_no)
			break;
	}
97
#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
W
wangchenyang 已提交
98
	spinor_mtd = GetMtd("spinor");
99 100 101
#else
	spinor_mtd = (struct MtdDev *)LOS_DL_LIST_ENTRY(part_head->pstNext, mtd_partition, node_info)->mtd_info;
#endif
W
wangchenyang 已提交
102 103 104 105 106 107 108
	if (spinor_mtd == NULL) {
		free(sb);
		return -EPERM;
	}
	jffs2_dev_list[part_no].blockEnd = mtd_part->end_block;
	jffs2_dev_list[part_no].blockSize = spinor_mtd->eraseSize;
	jffs2_dev_list[part_no].blockStart = mtd_part->start_block;
109
#ifndef LOSCFG_PLATFORM_QEMU_ARM_VIRT_CA7
W
wangchenyang 已提交
110
	(void)FreeMtd(spinor_mtd);
111
#endif
W
wangchenyang 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	sb->jffs2_sb.mtd = mtd_part->mtd_info;
	sb->s_dev = &jffs2_dev_list[part_no];

	c = JFFS2_SB_INFO(sb);
	c->flash_size  = (mtd_part->end_block - mtd_part->start_block + 1) * spinor_mtd->eraseSize;
	c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size);
	c->sector_size = spinor_mtd->eraseSize;

	jffs2_dbg(1, "C mtd_size:%d,mtd-erase:%d,blocks:%d,hashsize:%d\n",
		c->flash_size, c->sector_size, c->flash_size / c->sector_size, c->inocache_hashsize);

	c->inocache_list = zalloc(sizeof(struct jffs2_inode_cache *) * c->inocache_hashsize);
	if (c->inocache_list == NULL) {
		free(sb);
		return -ENOMEM;
	}
	if (jffs2_mounted_number++ == 0) {
		(void)jffs2_create_slab_caches(); // No error check, cannot fail
		(void)jffs2_compressors_init();
	}

	ret = jffs2_fill_super(sb);
	if (ret) {
		if (--jffs2_mounted_number == 0) {
			jffs2_destroy_slab_caches();
			(void)jffs2_compressors_exit();
		}

		free(sb);
		free(c->inocache_list);
		c->inocache_list = NULL;
		return ret;
	}

	jffs2_start_garbage_collect_thread(c);

	sb->s_mount_count++;
	*root_node = sb->s_root;
	return 0;
}

int jffs2_umount(struct jffs2_inode *root_node)
{
	struct super_block *sb = root_node->i_sb;
	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
	struct jffs2_full_dirent *fd, *next;

	D2(PRINTK("Jffs2Umount\n"));

	// Only really umount if this is the only mount
	if (sb->s_mount_count == 1) {
		jffs2_stop_garbage_collect_thread(c);

		// free directory entries
		for (fd = root_node->jffs2_i.dents; fd; fd = next) {
			next = fd->next;
			jffs2_free_full_dirent(fd);
		}

		free(root_node);

		// Clean up the super block and root_node inode
		jffs2_free_ino_caches(c);
		jffs2_free_raw_node_refs(c);
		free(c->blocks);
		c->blocks = NULL;
		free(c->inocache_list);
		c->inocache_list = NULL;
		(void)Jffs2HashDeinit(&sb->s_node_hash_lock);

		(void)mutex_destroy(&c->alloc_sem);
		(void)mutex_destroy(&c->erase_free_sem);
		free(sb);
		// That's all folks.
		D2(PRINTK("Jffs2Umount No current mounts\n"));
	} else {
		sb->s_mount_count--;
	}
	if (--jffs2_mounted_number == 0) {
		jffs2_destroy_slab_caches();
		(void)jffs2_compressors_exit();
	}
	return 0;
}