* [PATCH] a new filessytem module for nilfs2
@ 2010-02-03 9:41 Jiro SEKIBA
2010-02-05 16:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-10 0:31 ` [PATCH] a new filessytem " Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 2 replies; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-03 9:41 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 751 bytes --]
Hi,
This is a patch to support nilfs2 filesystem.
I would like you to review the patch.
I've checked with revno 2153 and kvm(qemu) environment.
Also the patch has already an ability to boot the kernel from
the nilfs partition, I have a following ToDo list to improve the module.
1. revision check for future disk layout changes
2. CRC check for superblock to ensure the partition is a nilfs2 partition
3. CRC check latest log block to ensure valid log
4. search the latest log in case unclean unmount happened
nilfs2 stands for New Implementation of Log Filesystem version2.
nilfs2 has been merged into linux main line kernel since 2.6.30.
Please give me any comments or advice.
thank you very much in advance
--
Jiro SEKIBA <jir@unicus.jp>
[-- Attachment #2: nilfs2.patch --]
[-- Type: application/octet-stream, Size: 34341 bytes --]
=== modified file 'conf/any-emu.rmk'
--- conf/any-emu.rmk 2010-01-20 20:31:39 +0000
+++ conf/any-emu.rmk 2010-01-29 15:30:19 +0000
@@ -38,7 +38,7 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
fs/befs.c fs/befs_be.c fs/tar.c \
\
=== modified file 'conf/common.rmk'
--- conf/common.rmk 2010-01-20 20:31:39 +0000
+++ conf/common.rmk 2010-01-29 16:03:16 +0000
@@ -28,9 +28,9 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
kern/fs.c kern/env.c fs/fshelp.c \
@@ -65,7 +65,7 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
fs/befs_be.c fs/tar.c \
\
@@ -224,8 +224,8 @@
CLEANFILES += grub-reboot
# Filing systems.
-pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod ntfs.mod \
- ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod \
+pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod nilfs2.mod \
+ ntfs.mod ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod xfs.mod \
affs.mod sfs.mod hfsplus.mod reiserfs.mod cpio.mod tar.mod \
udf.mod afs.mod afs_be.mod befs.mod befs_be.mod
@@ -269,6 +269,11 @@
minix_mod_CFLAGS = $(COMMON_CFLAGS)
minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For nilfs2.mod.
+nilfs2_mod_SOURCES = fs/nilfs2.c
+nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
+nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For hfs.mod.
hfs_mod_SOURCES = fs/hfs.c
hfs_mod_CFLAGS = $(COMMON_CFLAGS)
=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk 2010-01-20 20:31:39 +0000
+++ conf/i386-pc.rmk 2010-01-29 14:16:59 +0000
@@ -100,9 +100,9 @@
\
fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/msdos.c partmap/gpt.c \
\
=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
+++ conf/sparc64-ieee1275.rmk 2010-01-29 15:31:38 +0000
@@ -74,9 +74,9 @@
\
fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/amiga.c partmap/apple.c partmap/msdos.c \
partmap/sun.c partmap/acorn.c \
=== added file 'fs/nilfs2.c'
--- fs/nilfs2.c 1970-01-01 00:00:00 +0000
+++ fs/nilfs2.c 2010-01-31 08:56:27 +0000
@@ -0,0 +1,1115 @@
+/* nilfs2.c - New Implementation of Log filesystem */
+/* Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
+
+*/
+/* ext2.c - Second Extended filesystem */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* Filetype information as used in inodes. */
+#define FILETYPE_INO_MASK 0170000
+#define FILETYPE_INO_REG 0100000
+#define FILETYPE_INO_DIRECTORY 0040000
+#define FILETYPE_INO_SYMLINK 0120000
+
+#include <grub/err.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/dl.h>
+#include <grub/types.h>
+#include <grub/fshelp.h>
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+/** nilfs_fs.h **/
+#define NILFS_INODE_BMAP_SIZE 7
+
+/* Magic value used to identify an nilfs2 filesystem. */
+#define NILFS2_SUPER_MAGIC 0x3434
+/* nilfs btree node flag */
+#define NILFS_BTREE_NODE_ROOT 0x01
+
+/* nilfs btree node level */
+#define NILFS_BTREE_LEVEL_DATA 0
+#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
+#define NILFS_BTREE_LEVEL_MAX 14
+
+struct grub_nilfs2_inode
+{
+ grub_uint64_t i_blocks;
+ grub_uint64_t i_size;
+ grub_uint64_t i_ctime;
+ grub_uint64_t i_mtime;
+ grub_uint32_t i_ctime_nsec;
+ grub_uint32_t i_mtime_nsec;
+ grub_uint32_t i_uid;
+ grub_uint32_t i_gid;
+ grub_uint16_t i_mode;
+ grub_uint16_t i_links_count;
+ grub_uint32_t i_flags;
+ grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
+#define i_device_code i_bmap[0]
+ grub_uint64_t i_xattr;
+ grub_uint32_t i_generation;
+ grub_uint32_t i_pad;
+};
+
+struct grub_nilfs2_super_root
+{
+ grub_uint32_t sr_sum;
+ grub_uint16_t sr_bytes;
+ grub_uint16_t sr_flags;
+ grub_uint64_t sr_nongc_ctime;
+ struct grub_nilfs2_inode sr_dat;
+ struct grub_nilfs2_inode sr_cpfile;
+ struct grub_nilfs2_inode sr_sufile;
+};
+
+struct grub_nilfs2_super_block
+{
+ grub_uint32_t s_rev_level;
+ grub_uint16_t s_minor_rev_level;
+ grub_uint16_t s_magic;
+ grub_uint16_t s_bytes;
+ grub_uint16_t s_flags;
+ grub_uint32_t s_crc_seed;
+ grub_uint32_t s_sum;
+ grub_uint32_t s_log_block_size;
+ grub_uint64_t s_nsegments;
+ grub_uint64_t s_dev_size;
+ grub_uint64_t s_first_data_block;
+ grub_uint32_t s_blocks_per_segment;
+ grub_uint32_t s_r_segments_percentage;
+ grub_uint64_t s_last_cno;
+ grub_uint64_t s_last_pseg;
+ grub_uint64_t s_last_seq;
+ grub_uint64_t s_free_blocks_count;
+ grub_uint64_t s_ctime;
+ grub_uint64_t s_mtime;
+ grub_uint64_t s_wtime;
+ grub_uint16_t s_mnt_count;
+ grub_uint16_t s_max_mnt_count;
+ grub_uint16_t s_state;
+ grub_uint16_t s_errors;
+ grub_uint64_t s_lastcheck;
+ grub_uint32_t s_checkinterval;
+ grub_uint32_t s_creator_os;
+ grub_uint16_t s_def_resuid;
+ grub_uint16_t s_def_resgid;
+ grub_uint32_t s_first_ino;
+ grub_uint16_t s_inode_size;
+ grub_uint16_t s_dat_entry_size;
+ grub_uint16_t s_checkpoint_size;
+ grub_uint16_t s_segment_usage_size;
+ grub_uint8_t s_uuid[16];
+ char s_volume_name[16];
+ char s_last_mounted[64];
+ grub_uint32_t s_c_interval;
+ grub_uint32_t s_c_block_max;
+ grub_uint32_t s_reserved[192];
+};
+
+struct grub_nilfs2_dir_entry
+{
+ grub_uint64_t inode;
+ grub_uint16_t rec_len;
+ grub_uint8_t name_len;
+ grub_uint8_t file_type;
+#if 0 /* followed by file name */
+ char name[NILFS_NAME_LEN];
+ char pad;
+#endif
+};
+
+enum
+{
+ NILFS_FT_UNKNOWN,
+ NILFS_FT_REG_FILE,
+ NILFS_FT_DIR,
+ NILFS_FT_CHRDEV,
+ NILFS_FT_BLKDEV,
+ NILFS_FT_FIFO,
+ NILFS_FT_SOCK,
+ NILFS_FT_SYMLINK,
+ NILFS_FT_MAX
+};
+
+struct grub_nilfs2_finfo
+{
+ grub_uint64_t fi_ino;
+ grub_uint64_t fi_cno;
+ grub_uint32_t fi_nblocks;
+ grub_uint32_t fi_ndatablk;
+};
+
+struct grub_nilfs2_binfo_v
+{
+ grub_uint64_t bi_vblocknr;
+ grub_uint64_t bi_blkoff;
+};
+
+struct grub_nilfs2_binfo_dat
+{
+ grub_uint64_t bi_blkoff;
+ grub_uint8_t bi_level;
+ grub_uint8_t bi_pad[7];
+};
+
+union grub_nilfs2_binfo
+{
+ struct grub_nilfs2_binfo_v bi_v;
+ struct grub_nilfs2_binfo_dat bi_dat;
+};
+
+struct grub_nilfs2_segment_summary
+{
+ grub_uint32_t ss_datasum;
+ grub_uint32_t ss_sumsum;
+ grub_uint32_t ss_magic;
+ grub_uint16_t ss_bytes;
+ grub_uint16_t ss_flags;
+ grub_uint64_t ss_seq;
+ grub_uint64_t ss_create;
+ grub_uint64_t ss_next;
+ grub_uint32_t ss_nblocks;
+ grub_uint32_t ss_nfinfo;
+ grub_uint32_t ss_sumbytes;
+ grub_uint32_t ss_pad;
+};
+
+struct grub_nilfs2_btree_node
+{
+ grub_uint8_t bn_flags;
+ grub_uint8_t bn_level;
+ grub_uint16_t bn_nchildren;
+ grub_uint32_t bn_pad;
+};
+
+struct grub_nilfs2_palloc_group_desc
+{
+ grub_uint32_t pg_nfrees;
+};
+
+struct grub_nilfs2_dat_entry
+{
+ grub_uint64_t de_blocknr;
+ grub_uint64_t de_start;
+ grub_uint64_t de_end;
+ grub_uint64_t de_rsv;
+};
+
+struct grub_nilfs2_snapshot_list {
+ grub_uint64_t ssl_next;
+ grub_uint64_t ssl_prev;
+};
+
+struct grub_nilfs2_cpfile_header
+{
+ grub_uint64_t ch_ncheckpoints;
+ grub_uint64_t ch_nsnapshots;
+ struct grub_nilfs2_snapshot_list ch_snapshot_list;
+};
+
+struct grub_nilfs2_checkpoint
+{
+ grub_uint32_t cp_flags;
+ grub_uint32_t cp_checkpoints_count;
+ struct grub_nilfs2_snapshot_list cp_snapshot_list;
+ grub_uint64_t cp_cno;
+ grub_uint64_t cp_create;
+ grub_uint64_t cp_nblk_inc;
+ grub_uint64_t cp_inodes_count;
+ grub_uint64_t cp_blocks_count;
+ struct grub_nilfs2_inode cp_ifile_inode;
+};
+
+/** nilfs_fs.h **/
+
+/** bmap.h **/
+#define NILFS_BMAP_LARGE 0x1
+#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
+/** bmap.h **/
+
+/** btree.h **/
+/* nilfs extra padding for nonroot btree node */
+#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
+#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
+#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
+ ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
+ (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
+/** btree.h **/
+
+
+struct grub_fshelp_node
+{
+ struct grub_nilfs2_data *data;
+ struct grub_nilfs2_inode inode;
+ grub_uint64_t ino;
+ int inode_read;
+};
+
+struct grub_nilfs2_data
+{
+ struct grub_nilfs2_super_block sblock;
+ struct grub_nilfs2_super_root sroot;
+ struct grub_nilfs2_inode ifile;
+ grub_disk_t disk;
+ struct grub_nilfs2_inode *inode;
+ struct grub_fshelp_node diropen;
+};
+
+/* Log2 size of nilfs2 block in 512 blocks. */
+#define LOG2_NILFS2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
+
+/* Log2 size of nilfs2 block in bytes. */
+#define LOG2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
+
+/* The size of an nilfs2 block in bytes. */
+#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
+
+static grub_uint64_t
+grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
+static grub_dl_t my_mod;
+
+\f
+
+static inline unsigned long
+grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
+{
+ return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
+}
+
+static inline grub_uint64_t
+grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
+ grub_uint64_t nr, grub_uint32_t *offset)
+{
+ return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
+{
+ return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return NILFS2_BLOCK_SIZE(data) / entry_size;
+}
+
+
+static inline grub_uint32_t
+grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
+ grub_nilfs2_entries_per_block(data,entry_size)) + 1;
+}
+
+static inline grub_uint32_t
+grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return grub_nilfs2_palloc_groups_per_desc_block(data) *
+ grub_nilfs2_blocks_per_group(data,entry_size) + 1;
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
+ unsigned long group,
+ unsigned long entry_size)
+{
+ grub_uint32_t desc_block =
+ group / grub_nilfs2_palloc_groups_per_desc_block(data);
+ return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
+ unsigned long group,
+ unsigned long entry_size)
+{
+ unsigned long desc_offset = group %
+ grub_nilfs2_palloc_groups_per_desc_block(data);
+
+ return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
+ desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
+ grub_uint64_t nr, unsigned long entry_size)
+{
+ unsigned long group;
+ grub_uint32_t group_offset;
+
+ group = grub_nilfs2_palloc_group(data, nr, &group_offset);
+
+ return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
+ group_offset / grub_nilfs2_entries_per_block(data, entry_size);
+
+}
+
+static inline struct grub_nilfs2_btree_node *
+grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
+{
+ return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
+}
+
+static inline int
+grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
+{
+ return node->bn_level;
+}
+
+static inline grub_uint64_t *
+grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
+{
+ return (grub_uint64_t *)((char *)(node + 1) +
+ ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
+ 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
+}
+
+static inline grub_uint64_t
+grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
+{
+ return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
+}
+
+static inline int
+grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
+ grub_uint64_t key, int *indexp)
+{
+ grub_uint64_t nkey;
+ int index, low, high, s;
+
+ low = 0;
+ high = grub_le_to_cpu16(node->bn_nchildren) - 1;
+ index = 0;
+ s = 0;
+ while(low <= high)
+ {
+ index = (low+high)/2;
+ nkey = grub_nilfs2_btree_node_get_key(node, index);
+ if(nkey == key)
+ {
+ s = 0;
+ goto out;
+ }
+ else if (nkey < key)
+ {
+ low = index +1;
+ s = -1;
+ }
+ else
+ {
+ high = index - 1;
+ s = 1;
+ }
+ }
+
+ if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
+ {
+ if (s > 0 && index > 0)
+ index--;
+ }
+ else if (s < 0)
+ index++;
+
+ out:
+ *indexp = index;
+ return s == 0;
+}
+
+static inline int
+grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node)
+{
+ int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
+ sizeof(struct grub_nilfs2_btree_node) -
+ NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
+ (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
+
+ return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
+}
+
+static inline grub_uint64_t *
+grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node)
+{
+ return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
+ grub_nilfs2_btree_node_nchildren_max(data,node));
+}
+
+static inline grub_uint64_t
+grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node, int index)
+{
+ return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
+}
+
+static inline int
+grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
+ grub_uint64_t ptr, void *block)
+{
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
+ NILFS2_BLOCK_SIZE(data), block);
+}
+
+static grub_uint64_t
+grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_inode *inode,
+ grub_uint64_t key, int need_translate)
+{
+ struct grub_nilfs2_btree_node *node;
+ unsigned char block[NILFS2_BLOCK_SIZE(data)];
+ grub_uint64_t ptr;
+ int level, found, index;
+
+ node = grub_nilfs2_btree_get_root(inode);
+ level = grub_nilfs2_btree_get_level(node);
+
+ found = grub_nilfs2_btree_node_lookup(node, key, &index);
+ ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+
+ for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
+ {
+ grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
+ if(grub_errno)
+ {
+ grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
+ return -1;
+ }
+ node = (struct grub_nilfs2_btree_node *)block;
+
+ if(node->bn_level != level)
+ {
+ grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
+ return -1;
+ }
+
+ if(!found)
+ found = grub_nilfs2_btree_node_lookup(node, key, &index);
+ else
+ index = 0;
+
+ if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
+ {
+ ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+ }
+ else
+ {
+ grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
+ return -1;
+ }
+ }
+
+ if(!found)
+ return -1;
+
+ return ptr;
+}
+
+static inline grub_uint64_t
+grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
+{
+ return grub_le_to_cpu64(inode->i_bmap[1+key]);
+}
+
+static inline grub_uint64_t
+grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_inode *inode,
+ grub_uint64_t key, int need_translate)
+{
+ struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
+ if(root->bn_flags & NILFS_BMAP_LARGE)
+ return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
+ else
+ {
+ grub_uint64_t ptr;
+ ptr = grub_nilfs2_direct_lookup(inode, key);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+ return ptr;
+ }
+}
+
+static grub_uint64_t
+grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
+{
+ struct grub_nilfs2_dat_entry entry;
+ grub_disk_t disk = data->disk;
+ grub_uint64_t pptr;
+ grub_uint32_t blockno, offset;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ blockno = grub_nilfs2_palloc_entry_offset(data, key,
+ sizeof(struct grub_nilfs2_dat_entry));
+
+ grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
+ NILFS2_BLOCK_SIZE(data), &offset);
+
+ pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return -1;
+ }
+
+ grub_disk_read (disk, pptr * nilfs2_block_count, offset,
+ sizeof (struct grub_nilfs2_dat_entry), &entry);
+
+ return entry.de_blocknr;
+}
+
+
+static grub_disk_addr_t
+grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+{
+ struct grub_nilfs2_data *data = node->data;
+ struct grub_nilfs2_inode *inode = &node->inode;
+ grub_uint64_t pptr = -1;
+
+ pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return -1;
+ }
+
+ return pptr;
+}
+
+/* Read LEN bytes from the file described by DATA starting with byte
+ POS. Return the amount of read bytes in READ. */
+static grub_ssize_t
+grub_nilfs2_read_file (grub_fshelp_node_t node,
+ void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
+ unsigned offset, unsigned length),
+ int pos, grub_size_t len, char *buf)
+{
+ return grub_fshelp_read_file (node->data->disk, node, read_hook,
+ pos, len, buf, grub_nilfs2_read_block,
+ grub_le_to_cpu64(node->inode.i_size),
+ LOG2_NILFS2_BLOCK_SIZE (node->data));
+
+}
+
+static grub_err_t
+grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
+ grub_uint64_t cpno,
+ struct grub_nilfs2_checkpoint *cpp)
+{
+ grub_uint64_t blockno;
+ grub_uint32_t offset;
+ grub_uint64_t pptr;
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ /* assume sizeof(struct grub_nilfs2_cpfile_header) <
+ sizeof(struct grub_nilfs2_checkpoint)
+ */
+ blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
+ sizeof(struct grub_nilfs2_checkpoint) , &offset);
+
+ pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return GRUB_ERR_BAD_FS;
+ }
+
+ return grub_disk_read (disk, pptr * nilfs2_block_count,
+ offset * sizeof(struct grub_nilfs2_checkpoint),
+ sizeof (struct grub_nilfs2_checkpoint),
+ cpp);
+}
+
+static inline grub_err_t
+grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_checkpoint *cpp)
+{
+ return grub_nilfs2_read_checkpoint(data,
+ grub_le_to_cpu64(data->sblock.s_last_cno),
+ cpp);
+}
+
+/* Read the inode INO for the file described by DATA into INODE. */
+static grub_err_t
+grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
+ grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
+{
+ grub_uint64_t blockno;
+ unsigned int offset;
+ grub_uint64_t pptr;
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ blockno = grub_nilfs2_palloc_entry_offset(data, ino,
+ sizeof(struct grub_nilfs2_inode));
+
+ grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
+ NILFS2_BLOCK_SIZE(data), &offset);
+ pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return GRUB_ERR_BAD_FS;
+ }
+
+ return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
+ sizeof (struct grub_nilfs2_inode),
+ inodep);
+}
+
+static struct grub_nilfs2_data *
+grub_nilfs2_mount (grub_disk_t disk)
+{
+ struct grub_nilfs2_data *data;
+ struct grub_nilfs2_segment_summary ss;
+ struct grub_nilfs2_checkpoint last_checkpoint;
+ grub_uint64_t last_pseg;
+ grub_uint32_t nblocks;
+ unsigned int nilfs2_block_count;
+
+ data = grub_malloc (sizeof (struct grub_nilfs2_data));
+ if (!data)
+ return 0;
+
+ /* Read the superblock. */
+ grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
+ &data->sblock);
+ if (grub_errno)
+ goto fail;
+
+ /* Make sure this is an nilfs2 filesystem. */
+ if (grub_le_to_cpu16 (data->sblock.s_magic) != NILFS2_SUPER_MAGIC)
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
+ goto fail;
+ }
+
+ nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ /* Read the last segment summary */
+ last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
+ grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
+ sizeof (struct grub_nilfs2_segment_summary), &ss);
+
+ if (grub_errno)
+ goto fail;
+
+ /* Read the super root block */
+ nblocks = grub_le_to_cpu32(ss.ss_nblocks);
+ grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
+ sizeof (struct grub_nilfs2_super_root), &data->sroot);
+
+ if (grub_errno)
+ goto fail;
+
+ data->disk = disk;
+
+ grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
+
+ if (grub_errno)
+ goto fail;
+
+ grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
+ sizeof(struct grub_nilfs2_inode));
+
+ data->diropen.data = data;
+ data->diropen.ino = 2;
+ data->diropen.inode_read = 1;
+ data->inode = &data->diropen.inode;
+
+ grub_nilfs2_read_inode(data, 2, data->inode);
+
+ return data;
+
+ fail:
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
+
+ grub_free (data);
+ return 0;
+}
+
+static char *
+grub_nilfs2_read_symlink (grub_fshelp_node_t node)
+{
+ char *symlink;
+ struct grub_fshelp_node *diro = node;
+
+ if (! diro->inode_read)
+ {
+ grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+ }
+
+ symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
+ if (! symlink)
+ return 0;
+
+ grub_nilfs2_read_file (diro, 0, 0,
+ grub_le_to_cpu64 (diro->inode.i_size),
+ symlink);
+ if (grub_errno)
+ {
+ grub_free (symlink);
+ return 0;
+ }
+
+ symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
+ return symlink;
+}
+
+static int
+grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
+ int NESTED_FUNC_ATTR
+ (*hook) (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node))
+{
+ unsigned int fpos = 0;
+ struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
+
+ if (! diro->inode_read)
+ {
+ grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+ }
+
+ /* Search the file. */
+ while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
+ {
+ struct grub_nilfs2_dir_entry dirent;
+
+ grub_nilfs2_read_file (diro, 0, fpos,
+ sizeof (struct grub_nilfs2_dir_entry),
+ (char *) &dirent);
+ if (grub_errno)
+ return 0;
+
+ if (dirent.rec_len == 0)
+ return 0;
+
+ if (dirent.name_len != 0)
+ {
+ char filename[dirent.name_len + 1];
+ struct grub_fshelp_node *fdiro;
+ enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
+
+ grub_nilfs2_read_file (diro, 0,
+ fpos + sizeof (struct grub_nilfs2_dir_entry),
+ dirent.name_len, filename);
+ if (grub_errno)
+ return 0;
+
+ fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (! fdiro)
+ return 0;
+
+ fdiro->data = diro->data;
+ fdiro->ino = grub_le_to_cpu64 (dirent.inode);
+
+ filename[dirent.name_len] = '\0';
+
+ if (dirent.file_type != NILFS_FT_UNKNOWN)
+ {
+ fdiro->inode_read = 0;
+
+ if (dirent.file_type == NILFS_FT_DIR)
+ type = GRUB_FSHELP_DIR;
+ else if (dirent.file_type == NILFS_FT_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if (dirent.file_type == NILFS_FT_REG_FILE)
+ type = GRUB_FSHELP_REG;
+ }
+ else
+ {
+ /* The filetype can not be read from the dirent, read
+ the inode to get more information. */
+ grub_nilfs2_read_inode (diro->data,
+ grub_le_to_cpu64 (dirent.inode),
+ &fdiro->inode);
+ if (grub_errno)
+ {
+ grub_free (fdiro);
+ return 0;
+ }
+
+ fdiro->inode_read = 1;
+
+ if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
+ type = GRUB_FSHELP_DIR;
+ else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
+ type = GRUB_FSHELP_REG;
+ }
+
+ if (hook (filename, type, fdiro))
+ return 1;
+ }
+
+ fpos += grub_le_to_cpu16 (dirent.rec_len);
+ }
+
+ return 0;
+}
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_nilfs2_open (struct grub_file *file, const char *name)
+{
+ struct grub_nilfs2_data *data = NULL;
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (file->device->disk);
+ if (! data)
+ goto fail;
+
+ grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
+ grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
+ if (grub_errno)
+ goto fail;
+
+ if (! fdiro->inode_read)
+ {
+ grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
+ if (grub_errno)
+ goto fail;
+ }
+
+ grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
+ grub_free (fdiro);
+
+ file->size = grub_le_to_cpu64 (data->inode->i_size);
+ file->data = data;
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_close (grub_file_t file)
+{
+ grub_free (file->data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+/* Read LEN bytes data from FILE into BUF. */
+static grub_ssize_t
+grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
+
+ return grub_nilfs2_read_file (&data->diropen, file->read_hook,
+ file->offset, len, buf);
+}
+
+static grub_err_t
+grub_nilfs2_dir (grub_device_t device, const char *path,
+ int (*hook) (const char *filename,
+ const struct grub_dirhook_info *info))
+{
+ struct grub_nilfs2_data *data = 0;
+ struct grub_fshelp_node *fdiro = 0;
+
+ auto int NESTED_FUNC_ATTR iterate (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node);
+
+ int NESTED_FUNC_ATTR iterate (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node)
+ {
+ struct grub_dirhook_info info;
+ grub_memset (&info, 0, sizeof (info));
+ if (! node->inode_read)
+ {
+ grub_nilfs2_read_inode (data, node->ino, &node->inode);
+ if (!grub_errno)
+ node->inode_read = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (node->inode_read)
+ {
+ info.mtimeset = 1;
+ info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
+ }
+
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ grub_free (node);
+ return hook (filename, &info);
+ }
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (device->disk);
+ if (! data)
+ goto fail;
+
+ grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
+ grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
+ if (grub_errno)
+ goto fail;
+
+ grub_nilfs2_iterate_dir (fdiro, iterate);
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_label (grub_device_t device, char **label)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (data)
+ *label = grub_strndup (data->sblock.s_volume_name, 14);
+ else
+ *label = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (data)
+ {
+ *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
+ data->sblock.s_uuid[0], data->sblock.s_uuid[1],
+ data->sblock.s_uuid[2], data->sblock.s_uuid[3],
+ data->sblock.s_uuid[4], data->sblock.s_uuid[5],
+ data->sblock.s_uuid[6], data->sblock.s_uuid[7],
+ data->sblock.s_uuid[8], data->sblock.s_uuid[9],
+ data->sblock.s_uuid[10], data->sblock.s_uuid[11],
+ data->sblock.s_uuid[12], data->sblock.s_uuid[13],
+ data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+/* Get mtime. */
+static grub_err_t
+grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (!data)
+ *tm = 0;
+ else
+ *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+
+\f
+static struct grub_fs grub_nilfs2_fs=
+ {
+ .name = "nilfs2",
+ .dir = grub_nilfs2_dir,
+ .open = grub_nilfs2_open,
+ .read = grub_nilfs2_read,
+ .close = grub_nilfs2_close,
+ .label = grub_nilfs2_label,
+ .uuid = grub_nilfs2_uuid,
+ .mtime = grub_nilfs2_mtime,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(nilfs2)
+{
+ grub_fs_register (&grub_nilfs2_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(nilfs2)
+{
+ grub_fs_unregister (&grub_nilfs2_fs);
+}
[-- Attachment #3: Type: text/plain, Size: 2 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] a new filessytem module for nilfs2
2010-02-03 9:41 [PATCH] a new filessytem module for nilfs2 Jiro SEKIBA
@ 2010-02-05 16:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-06 5:02 ` Jiro SEKIBA
2010-02-10 0:31 ` [PATCH] a new filessytem " Vladimir 'φ-coder/phcoder' Serbinenko
1 sibling, 1 reply; 10+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-02-05 16:36 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 1344 bytes --]
Hello
Jiro SEKIBA wrote:
> Hi,
>
> This is a patch to support nilfs2 filesystem.
> I would like you to review the patch.
>
> I've checked with revno 2153 and kvm(qemu) environment.
>
> Also the patch has already an ability to boot the kernel from
> the nilfs partition, I have a following ToDo list to improve the module.
>
Is your code written from scratch or is it based on some other code? If
later can you tell exactly which so we can verify license compatibility?
> 1. revision check for future disk layout changes
> 2. CRC check for superblock to ensure the partition is a nilfs2 partition
> 3. CRC check latest log block to ensure valid log
> 4. search the latest log in case unclean unmount happened
>
> nilfs2 stands for New Implementation of Log Filesystem version2.
> nilfs2 has been merged into linux main line kernel since 2.6.30.
>
> Please give me any comments or advice.
>
> thank you very much in advance
>
> ------------------------------------------------------------------------
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] a new filessytem module for nilfs2
2010-02-05 16:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-02-06 5:02 ` Jiro SEKIBA
2010-02-24 11:25 ` [PATCHv2] a new filesystem " Jiro SEKIBA
0 siblings, 1 reply; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-06 5:02 UTC (permalink / raw)
To: The development of GNU GRUB
Hi,
At Fri, 05 Feb 2010 17:36:43 +0100,
Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>
> Hello
> Jiro SEKIBA wrote:
> > Hi,
> >
> > This is a patch to support nilfs2 filesystem.
> > I would like you to review the patch.
> >
> > I've checked with revno 2153 and kvm(qemu) environment.
> >
> > Also the patch has already an ability to boot the kernel from
> > the nilfs partition, I have a following ToDo list to improve the module.
> >
> Is your code written from scratch or is it based on some other code? If
> later can you tell exactly which so we can verify license compatibility?
Thank you for the attention. That is very important issue,
sorry that I didn't describe it explicitly.
The code is based on fs/ext2.c in grub-1.97.1 release.
I reused the file/directory iteration code from it.
Other nilfs2 specific code is writte by me from scratch.
I referred the original implementation, but have never borrowed
any code from it.
So I'm thinking the license would be gpl3, for it is derived
from gpl3(fs/ext2.c) code.
thanks,
regards,
> > 1. revision check for future disk layout changes
> > 2. CRC check for superblock to ensure the partition is a nilfs2 partition
> > 3. CRC check latest log block to ensure valid log
> > 4. search the latest log in case unclean unmount happened
> >
> > nilfs2 stands for New Implementation of Log Filesystem version2.
> > nilfs2 has been merged into linux main line kernel since 2.6.30.
> >
> > Please give me any comments or advice.
> >
> > thank you very much in advance
> >
> > ------------------------------------------------------------------------
> >
> >
> >
> > ------------------------------------------------------------------------
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > http://lists.gnu.org/mailman/listinfo/grub-devel
> >
>
>
> --
> Regards
> Vladimir 'φ-coder/phcoder' Serbinenko
>
>
--
Jiro SEKIBA <jir@unicus.jp>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] a new filessytem module for nilfs2
2010-02-03 9:41 [PATCH] a new filessytem module for nilfs2 Jiro SEKIBA
2010-02-05 16:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-02-10 0:31 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-11 14:25 ` Jiro SEKIBA
1 sibling, 1 reply; 10+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-02-10 0:31 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 1934 bytes --]
Jiro SEKIBA wrote:
> Hi,
>
> This is a patch to support nilfs2 filesystem.
> I would like you to review the patch.
>
> I've checked with revno 2153 and kvm(qemu) environment.
>
> Also the patch has already an ability to boot the kernel from
> the nilfs partition, I have a following ToDo list to improve the module.
>
> 1. revision check for future disk layout changes
> 2. CRC check for superblock to ensure the partition is a nilfs2 partition
> 3. CRC check latest log block to ensure valid log
> 4. search the latest log in case unclean unmount happened
>
> nilfs2 stands for New Implementation of Log Filesystem version2.
> nilfs2 has been merged into linux main line kernel since 2.6.30.
>
> Please give me any comments or advice.
>
> thank you very much in advance
>
+pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod
nilfs2.mod \
+ ntfs.mod ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod
xfs.mod \
For new modules we prefer to add pkglib_MODULES+= directly before the
module itself
+/* ext2.c - Second Extended filesystem */
+/*
Leftover
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
This can go into misc.h
iterate_dir:
+ /* Search the file. */
+ while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
+ {
Another leftover
I'm no nilfs2 expert but assuming that it works it's a good patch. Have
you tested it on big-endian system? If no nd you have no access to such
send me testing instructions, I have a powerpc machine (or one can use
qemu).
Nice job
> ------------------------------------------------------------------------
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] a new filessytem module for nilfs2
2010-02-10 0:31 ` [PATCH] a new filessytem " Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-02-11 14:25 ` Jiro SEKIBA
0 siblings, 0 replies; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-11 14:25 UTC (permalink / raw)
To: The development of GNU GRUB
Hi,
At Wed, 10 Feb 2010 01:31:35 +0100,
Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>
> Jiro SEKIBA wrote:
> > Hi,
> >
> > This is a patch to support nilfs2 filesystem.
> > I would like you to review the patch.
> >
> > I've checked with revno 2153 and kvm(qemu) environment.
> >
> > Also the patch has already an ability to boot the kernel from
> > the nilfs partition, I have a following ToDo list to improve the module.
> >
> > 1. revision check for future disk layout changes
> > 2. CRC check for superblock to ensure the partition is a nilfs2 partition
> > 3. CRC check latest log block to ensure valid log
> > 4. search the latest log in case unclean unmount happened
> >
> > nilfs2 stands for New Implementation of Log Filesystem version2.
> > nilfs2 has been merged into linux main line kernel since 2.6.30.
> >
> > Please give me any comments or advice.
> >
> > thank you very much in advance
> >
>
> +pkglib_MODULES += fshelp.mod fat.mod ufs1.mod ufs2.mod ext2.mod
> nilfs2.mod \
> + ntfs.mod ntfscomp.mod minix.mod hfs.mod jfs.mod iso9660.mod
> xfs.mod \
>
> For new modules we prefer to add pkglib_MODULES+= directly before the
> module itself
> +/* ext2.c - Second Extended filesystem */
> +/*
> Leftover
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> This can go into misc.h
> iterate_dir:
> + /* Search the file. */
> + while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
> + {
> Another leftover
> I'm no nilfs2 expert but assuming that it works it's a good patch. Have
> you tested it on big-endian system? If no nd you have no access to such
> send me testing instructions, I have a powerpc machine (or one can use
> qemu).
> Nice job
Thank you very much for the reviews and comments!
I'll revise the patch.
Also, I'll try the patch on qemu to check for big-endian system.
Thank you very much again!
regards,
> > ------------------------------------------------------------------------
> >
> >
> >
> > ------------------------------------------------------------------------
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > http://lists.gnu.org/mailman/listinfo/grub-devel
> >
>
>
> --
> Regards
> Vladimir 'φ-coder/phcoder' Serbinenko
>
>
--
Jiro SEKIBA <jir@unicus.jp>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCHv2] a new filesystem module for nilfs2
@ 2010-02-18 9:13 Jiro SEKIBA
2010-02-20 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-24 10:57 ` Vladimir 'φ-coder/phcoder' Serbinenko
0 siblings, 2 replies; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-18 9:13 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 900 bytes --]
Hi,
This is a revised patch to support nilfs2, a log file system.
I've checked it the first one on qemu-system-ppc and found a few bugs.
Thank you for encouraging me to test it on qemu-system-ppc!
This is a bug fixed version. I've checked it by grub-fstest on PPC
and by installing and booting it to boot sector of nilfs2 partition on i386.
Here are the change logs from the first one
- big endian bug fixes
* add "packed" attribute for all structs
* swap physical block number bytes
- separate pkglib_MODULES addition
- leftover removal
- moved DIV_ROUND_UP macro into misc.h
- add separate function to check super block
* add major version checking
ToDo:
1. CRC check for superblock to ensure the partition is a nilfs2 partition
2. CRC check latest log block to ensure valid log
3. search the latest log in case unclean unmount happened
thanks
regards
--
Jiro SEKIBA <jir@unicus.jp>
[-- Attachment #2: Type: text/plain, Size: 33845 bytes --]
=== modified file 'conf/any-emu.rmk'
--- conf/any-emu.rmk 2010-02-03 00:24:07 +0000
+++ conf/any-emu.rmk 2010-02-18 13:57:40 +0000
@@ -38,7 +38,7 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
fs/befs.c fs/befs_be.c fs/tar.c \
\
=== modified file 'conf/common.rmk'
--- conf/common.rmk 2010-02-06 14:37:23 +0000
+++ conf/common.rmk 2010-02-18 13:57:40 +0000
@@ -28,9 +28,9 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
kern/fs.c kern/env.c fs/fshelp.c \
@@ -65,7 +65,7 @@
\
fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
fs/befs_be.c fs/tar.c \
\
@@ -270,6 +270,12 @@
minix_mod_CFLAGS = $(COMMON_CFLAGS)
minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For nilfs2.mod.
+pkglib_MODULES += nilfs2.mod
+nilfs2_mod_SOURCES = fs/nilfs2.c
+nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
+nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# For hfs.mod.
hfs_mod_SOURCES = fs/hfs.c
hfs_mod_CFLAGS = $(COMMON_CFLAGS)
=== modified file 'conf/i386-pc.rmk'
--- conf/i386-pc.rmk 2010-02-03 00:24:07 +0000
+++ conf/i386-pc.rmk 2010-02-18 13:57:40 +0000
@@ -100,9 +100,9 @@
\
fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/msdos.c partmap/gpt.c \
\
=== modified file 'conf/sparc64-ieee1275.rmk'
--- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
+++ conf/sparc64-ieee1275.rmk 2010-02-18 13:57:40 +0000
@@ -74,9 +74,9 @@
\
fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
- fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
- fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
- fs/befs.c fs/befs_be.c fs/tar.c \
+ fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
+ fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
+ fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
\
partmap/amiga.c partmap/apple.c partmap/msdos.c \
partmap/sun.c partmap/acorn.c \
=== added file 'fs/nilfs2.c'
--- fs/nilfs2.c 1970-01-01 00:00:00 +0000
+++ fs/nilfs2.c 2010-02-18 13:57:40 +0000
@@ -0,0 +1,1126 @@
+/*
+ * nilfs2.c - New Implementation of Log filesystem
+ * Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
+ */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/* Filetype information as used in inodes. */
+#define FILETYPE_INO_MASK 0170000
+#define FILETYPE_INO_REG 0100000
+#define FILETYPE_INO_DIRECTORY 0040000
+#define FILETYPE_INO_SYMLINK 0120000
+
+#include <grub/err.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/disk.h>
+#include <grub/dl.h>
+#include <grub/types.h>
+#include <grub/fshelp.h>
+
+/** nilfs_fs.h **/
+#define NILFS_INODE_BMAP_SIZE 7
+
+#define NILFS_SUPORT_REV 2
+#define NILFS_MINOR_REV 0
+
+/* Magic value used to identify an nilfs2 filesystem. */
+#define NILFS2_SUPER_MAGIC 0x3434
+/* nilfs btree node flag */
+#define NILFS_BTREE_NODE_ROOT 0x01
+
+/* nilfs btree node level */
+#define NILFS_BTREE_LEVEL_DATA 0
+#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
+#define NILFS_BTREE_LEVEL_MAX 14
+
+struct grub_nilfs2_inode
+{
+ grub_uint64_t i_blocks;
+ grub_uint64_t i_size;
+ grub_uint64_t i_ctime;
+ grub_uint64_t i_mtime;
+ grub_uint32_t i_ctime_nsec;
+ grub_uint32_t i_mtime_nsec;
+ grub_uint32_t i_uid;
+ grub_uint32_t i_gid;
+ grub_uint16_t i_mode;
+ grub_uint16_t i_links_count;
+ grub_uint32_t i_flags;
+ grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
+#define i_device_code i_bmap[0]
+ grub_uint64_t i_xattr;
+ grub_uint32_t i_generation;
+ grub_uint32_t i_pad;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_super_root
+{
+ grub_uint32_t sr_sum;
+ grub_uint16_t sr_bytes;
+ grub_uint16_t sr_flags;
+ grub_uint64_t sr_nongc_ctime;
+ struct grub_nilfs2_inode sr_dat;
+ struct grub_nilfs2_inode sr_cpfile;
+ struct grub_nilfs2_inode sr_sufile;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_super_block
+{
+ grub_uint32_t s_rev_level;
+ grub_uint16_t s_minor_rev_level;
+ grub_uint16_t s_magic;
+ grub_uint16_t s_bytes;
+ grub_uint16_t s_flags;
+ grub_uint32_t s_crc_seed;
+ grub_uint32_t s_sum;
+ grub_uint32_t s_log_block_size;
+ grub_uint64_t s_nsegments;
+ grub_uint64_t s_dev_size;
+ grub_uint64_t s_first_data_block;
+ grub_uint32_t s_blocks_per_segment;
+ grub_uint32_t s_r_segments_percentage;
+ grub_uint64_t s_last_cno;
+ grub_uint64_t s_last_pseg;
+ grub_uint64_t s_last_seq;
+ grub_uint64_t s_free_blocks_count;
+ grub_uint64_t s_ctime;
+ grub_uint64_t s_mtime;
+ grub_uint64_t s_wtime;
+ grub_uint16_t s_mnt_count;
+ grub_uint16_t s_max_mnt_count;
+ grub_uint16_t s_state;
+ grub_uint16_t s_errors;
+ grub_uint64_t s_lastcheck;
+ grub_uint32_t s_checkinterval;
+ grub_uint32_t s_creator_os;
+ grub_uint16_t s_def_resuid;
+ grub_uint16_t s_def_resgid;
+ grub_uint32_t s_first_ino;
+ grub_uint16_t s_inode_size;
+ grub_uint16_t s_dat_entry_size;
+ grub_uint16_t s_checkpoint_size;
+ grub_uint16_t s_segment_usage_size;
+ grub_uint8_t s_uuid[16];
+ char s_volume_name[16];
+ char s_last_mounted[64];
+ grub_uint32_t s_c_interval;
+ grub_uint32_t s_c_block_max;
+ grub_uint32_t s_reserved[192];
+} __attribute__ ((packed));
+
+struct grub_nilfs2_dir_entry
+{
+ grub_uint64_t inode;
+ grub_uint16_t rec_len;
+ grub_uint8_t name_len;
+ grub_uint8_t file_type;
+#if 0 /* followed by file name */
+ char name[NILFS_NAME_LEN];
+ char pad;
+#endif
+} __attribute__ ((packed));
+
+enum
+{
+ NILFS_FT_UNKNOWN,
+ NILFS_FT_REG_FILE,
+ NILFS_FT_DIR,
+ NILFS_FT_CHRDEV,
+ NILFS_FT_BLKDEV,
+ NILFS_FT_FIFO,
+ NILFS_FT_SOCK,
+ NILFS_FT_SYMLINK,
+ NILFS_FT_MAX
+};
+
+struct grub_nilfs2_finfo
+{
+ grub_uint64_t fi_ino;
+ grub_uint64_t fi_cno;
+ grub_uint32_t fi_nblocks;
+ grub_uint32_t fi_ndatablk;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_binfo_v
+{
+ grub_uint64_t bi_vblocknr;
+ grub_uint64_t bi_blkoff;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_binfo_dat
+{
+ grub_uint64_t bi_blkoff;
+ grub_uint8_t bi_level;
+ grub_uint8_t bi_pad[7];
+} __attribute__ ((packed));
+
+union grub_nilfs2_binfo
+{
+ struct grub_nilfs2_binfo_v bi_v;
+ struct grub_nilfs2_binfo_dat bi_dat;
+};
+
+struct grub_nilfs2_segment_summary
+{
+ grub_uint32_t ss_datasum;
+ grub_uint32_t ss_sumsum;
+ grub_uint32_t ss_magic;
+ grub_uint16_t ss_bytes;
+ grub_uint16_t ss_flags;
+ grub_uint64_t ss_seq;
+ grub_uint64_t ss_create;
+ grub_uint64_t ss_next;
+ grub_uint32_t ss_nblocks;
+ grub_uint32_t ss_nfinfo;
+ grub_uint32_t ss_sumbytes;
+ grub_uint32_t ss_pad;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_btree_node
+{
+ grub_uint8_t bn_flags;
+ grub_uint8_t bn_level;
+ grub_uint16_t bn_nchildren;
+ grub_uint32_t bn_pad;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_palloc_group_desc
+{
+ grub_uint32_t pg_nfrees;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_dat_entry
+{
+ grub_uint64_t de_blocknr;
+ grub_uint64_t de_start;
+ grub_uint64_t de_end;
+ grub_uint64_t de_rsv;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_snapshot_list {
+ grub_uint64_t ssl_next;
+ grub_uint64_t ssl_prev;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_cpfile_header
+{
+ grub_uint64_t ch_ncheckpoints;
+ grub_uint64_t ch_nsnapshots;
+ struct grub_nilfs2_snapshot_list ch_snapshot_list;
+} __attribute__ ((packed));
+
+struct grub_nilfs2_checkpoint
+{
+ grub_uint32_t cp_flags;
+ grub_uint32_t cp_checkpoints_count;
+ struct grub_nilfs2_snapshot_list cp_snapshot_list;
+ grub_uint64_t cp_cno;
+ grub_uint64_t cp_create;
+ grub_uint64_t cp_nblk_inc;
+ grub_uint64_t cp_inodes_count;
+ grub_uint64_t cp_blocks_count;
+ struct grub_nilfs2_inode cp_ifile_inode;
+} __attribute__ ((packed));
+
+/** nilfs_fs.h **/
+
+/** bmap.h **/
+#define NILFS_BMAP_LARGE 0x1
+#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
+/** bmap.h **/
+
+/** btree.h **/
+/* nilfs extra padding for nonroot btree node */
+#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
+#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
+#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
+ ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
+ (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
+/** btree.h **/
+
+
+struct grub_fshelp_node
+{
+ struct grub_nilfs2_data *data;
+ struct grub_nilfs2_inode inode;
+ grub_uint64_t ino;
+ int inode_read;
+};
+
+struct grub_nilfs2_data
+{
+ struct grub_nilfs2_super_block sblock;
+ struct grub_nilfs2_super_root sroot;
+ struct grub_nilfs2_inode ifile;
+ grub_disk_t disk;
+ struct grub_nilfs2_inode *inode;
+ struct grub_fshelp_node diropen;
+};
+
+/* Log2 size of nilfs2 block in 512 blocks. */
+#define LOG2_NILFS2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
+
+/* Log2 size of nilfs2 block in bytes. */
+#define LOG2_BLOCK_SIZE(data) \
+ (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
+
+/* The size of an nilfs2 block in bytes. */
+#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
+
+static grub_uint64_t
+grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
+static grub_dl_t my_mod;
+
+\f
+
+static inline unsigned long
+grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
+{
+ return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
+}
+
+static inline grub_uint64_t
+grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
+ grub_uint64_t nr, grub_uint32_t *offset)
+{
+ return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
+{
+ return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return NILFS2_BLOCK_SIZE(data) / entry_size;
+}
+
+
+static inline grub_uint32_t
+grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
+ grub_nilfs2_entries_per_block(data,entry_size)) + 1;
+}
+
+static inline grub_uint32_t
+grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
+ unsigned long entry_size)
+{
+ return grub_nilfs2_palloc_groups_per_desc_block(data) *
+ grub_nilfs2_blocks_per_group(data,entry_size) + 1;
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
+ unsigned long group,
+ unsigned long entry_size)
+{
+ grub_uint32_t desc_block =
+ group / grub_nilfs2_palloc_groups_per_desc_block(data);
+ return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
+ unsigned long group,
+ unsigned long entry_size)
+{
+ unsigned long desc_offset = group %
+ grub_nilfs2_palloc_groups_per_desc_block(data);
+
+ return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
+ desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
+}
+
+static inline grub_uint32_t
+grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
+ grub_uint64_t nr, unsigned long entry_size)
+{
+ unsigned long group;
+ grub_uint32_t group_offset;
+
+ group = grub_nilfs2_palloc_group(data, nr, &group_offset);
+
+ return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
+ group_offset / grub_nilfs2_entries_per_block(data, entry_size);
+
+}
+
+static inline struct grub_nilfs2_btree_node *
+grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
+{
+ return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
+}
+
+static inline int
+grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
+{
+ return node->bn_level;
+}
+
+static inline grub_uint64_t *
+grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
+{
+ return (grub_uint64_t *)((char *)(node + 1) +
+ ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
+ 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
+}
+
+static inline grub_uint64_t
+grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
+{
+ return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
+}
+
+static inline int
+grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
+ grub_uint64_t key, int *indexp)
+{
+ grub_uint64_t nkey;
+ int index, low, high, s;
+
+ low = 0;
+ high = grub_le_to_cpu16(node->bn_nchildren) - 1;
+ index = 0;
+ s = 0;
+ while(low <= high)
+ {
+ index = (low+high)/2;
+ nkey = grub_nilfs2_btree_node_get_key(node, index);
+ if(nkey == key)
+ {
+ s = 0;
+ goto out;
+ }
+ else if (nkey < key)
+ {
+ low = index +1;
+ s = -1;
+ }
+ else
+ {
+ high = index - 1;
+ s = 1;
+ }
+ }
+
+ if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
+ {
+ if (s > 0 && index > 0)
+ index--;
+ }
+ else if (s < 0)
+ index++;
+
+ out:
+ *indexp = index;
+ return s == 0;
+}
+
+static inline int
+grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node)
+{
+ int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
+ sizeof(struct grub_nilfs2_btree_node) -
+ NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
+ (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
+
+ return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
+}
+
+static inline grub_uint64_t *
+grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node)
+{
+ return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
+ grub_nilfs2_btree_node_nchildren_max(data,node));
+}
+
+static inline grub_uint64_t
+grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_btree_node *node, int index)
+{
+ return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
+}
+
+static inline int
+grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
+ grub_uint64_t ptr, void *block)
+{
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
+ NILFS2_BLOCK_SIZE(data), block);
+}
+
+static grub_uint64_t
+grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_inode *inode,
+ grub_uint64_t key, int need_translate)
+{
+ struct grub_nilfs2_btree_node *node;
+ unsigned char block[NILFS2_BLOCK_SIZE(data)];
+ grub_uint64_t ptr;
+ int level, found, index;
+
+ node = grub_nilfs2_btree_get_root(inode);
+ level = grub_nilfs2_btree_get_level(node);
+
+ found = grub_nilfs2_btree_node_lookup(node, key, &index);
+ ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+
+ for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
+ {
+ grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
+ if(grub_errno)
+ {
+ grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
+ return -1;
+ }
+ node = (struct grub_nilfs2_btree_node *)block;
+
+ if(node->bn_level != level)
+ {
+ grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
+ return -1;
+ }
+
+ if(!found)
+ found = grub_nilfs2_btree_node_lookup(node, key, &index);
+ else
+ index = 0;
+
+ if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
+ {
+ ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+ }
+ else
+ {
+ grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
+ return -1;
+ }
+ }
+
+ if(!found)
+ return -1;
+
+ return ptr;
+}
+
+static inline grub_uint64_t
+grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
+{
+ return grub_le_to_cpu64(inode->i_bmap[1+key]);
+}
+
+static inline grub_uint64_t
+grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_inode *inode,
+ grub_uint64_t key, int need_translate)
+{
+ struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
+ if(root->bn_flags & NILFS_BMAP_LARGE)
+ return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
+ else
+ {
+ grub_uint64_t ptr;
+ ptr = grub_nilfs2_direct_lookup(inode, key);
+ if(need_translate)
+ ptr = grub_nilfs2_dat_translate(data, ptr);
+ return ptr;
+ }
+}
+
+static grub_uint64_t
+grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
+{
+ struct grub_nilfs2_dat_entry entry;
+ grub_disk_t disk = data->disk;
+ grub_uint64_t pptr;
+ grub_uint32_t blockno, offset;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ blockno = grub_nilfs2_palloc_entry_offset(data, key,
+ sizeof(struct grub_nilfs2_dat_entry));
+
+ grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
+ NILFS2_BLOCK_SIZE(data), &offset);
+
+ pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return -1;
+ }
+
+ grub_disk_read (disk, pptr * nilfs2_block_count, offset,
+ sizeof (struct grub_nilfs2_dat_entry), &entry);
+
+ return grub_le_to_cpu64(entry.de_blocknr);
+}
+
+
+static grub_disk_addr_t
+grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+{
+ struct grub_nilfs2_data *data = node->data;
+ struct grub_nilfs2_inode *inode = &node->inode;
+ grub_uint64_t pptr = -1;
+
+ pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return -1;
+ }
+
+ return pptr;
+}
+
+/* Read LEN bytes from the file described by DATA starting with byte
+ POS. Return the amount of read bytes in READ. */
+static grub_ssize_t
+grub_nilfs2_read_file (grub_fshelp_node_t node,
+ void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
+ unsigned offset, unsigned length),
+ int pos, grub_size_t len, char *buf)
+{
+ return grub_fshelp_read_file (node->data->disk, node, read_hook,
+ pos, len, buf, grub_nilfs2_read_block,
+ grub_le_to_cpu64(node->inode.i_size),
+ LOG2_NILFS2_BLOCK_SIZE (node->data));
+
+}
+
+static grub_err_t
+grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
+ grub_uint64_t cpno,
+ struct grub_nilfs2_checkpoint *cpp)
+{
+ grub_uint64_t blockno;
+ grub_uint32_t offset;
+ grub_uint64_t pptr;
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ /* assume sizeof(struct grub_nilfs2_cpfile_header) <
+ sizeof(struct grub_nilfs2_checkpoint)
+ */
+ blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
+ sizeof(struct grub_nilfs2_checkpoint) , &offset);
+
+ pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return GRUB_ERR_BAD_FS;
+ }
+
+ return grub_disk_read (disk, pptr * nilfs2_block_count,
+ offset * sizeof(struct grub_nilfs2_checkpoint),
+ sizeof (struct grub_nilfs2_checkpoint),
+ cpp);
+}
+
+static inline grub_err_t
+grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
+ struct grub_nilfs2_checkpoint *cpp)
+{
+ return grub_nilfs2_read_checkpoint(data,
+ grub_le_to_cpu64(data->sblock.s_last_cno),
+ cpp);
+}
+
+/* Read the inode INO for the file described by DATA into INODE. */
+static grub_err_t
+grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
+ grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
+{
+ grub_uint64_t blockno;
+ unsigned int offset;
+ grub_uint64_t pptr;
+ grub_disk_t disk = data->disk;
+ unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ blockno = grub_nilfs2_palloc_entry_offset(data, ino,
+ sizeof(struct grub_nilfs2_inode));
+
+ grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
+ NILFS2_BLOCK_SIZE(data), &offset);
+ pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
+ if(pptr == (grub_uint64_t)-1) {
+ grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
+ return GRUB_ERR_BAD_FS;
+ }
+
+ return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
+ sizeof (struct grub_nilfs2_inode),
+ inodep);
+}
+
+static int grub_nilfs2_valid_sb(struct grub_nilfs2_super_block *sbp)
+{
+ if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
+ return 0;
+
+ if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
+ return 0;
+
+ return 1;
+}
+
+static struct grub_nilfs2_data *
+grub_nilfs2_mount (grub_disk_t disk)
+{
+ struct grub_nilfs2_data *data;
+ struct grub_nilfs2_segment_summary ss;
+ struct grub_nilfs2_checkpoint last_checkpoint;
+ grub_uint64_t last_pseg;
+ grub_uint32_t nblocks;
+ unsigned int nilfs2_block_count;
+
+ data = grub_malloc (sizeof (struct grub_nilfs2_data));
+ if (!data)
+ return 0;
+
+ /* Read the superblock. */
+ grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
+ &data->sblock);
+ if (grub_errno)
+ goto fail;
+
+ /* Make sure this is an nilfs2 filesystem. */
+ if (!grub_nilfs2_valid_sb(&data->sblock))
+ {
+ grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
+ goto fail;
+ }
+
+ nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
+
+ /* Read the last segment summary */
+ last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
+ grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
+ sizeof (struct grub_nilfs2_segment_summary), &ss);
+
+ if (grub_errno)
+ goto fail;
+
+ /* Read the super root block */
+ nblocks = grub_le_to_cpu32(ss.ss_nblocks);
+ grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
+ sizeof (struct grub_nilfs2_super_root), &data->sroot);
+
+ if (grub_errno)
+ goto fail;
+
+ data->disk = disk;
+
+ grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
+
+ if (grub_errno)
+ goto fail;
+
+ grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
+ sizeof(struct grub_nilfs2_inode));
+
+ data->diropen.data = data;
+ data->diropen.ino = 2;
+ data->diropen.inode_read = 1;
+ data->inode = &data->diropen.inode;
+
+ grub_nilfs2_read_inode(data, 2, data->inode);
+
+ return data;
+
+ fail:
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
+
+ grub_free (data);
+ return 0;
+}
+
+static char *
+grub_nilfs2_read_symlink (grub_fshelp_node_t node)
+{
+ char *symlink;
+ struct grub_fshelp_node *diro = node;
+
+ if (! diro->inode_read)
+ {
+ grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+ }
+
+ symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
+ if (! symlink)
+ return 0;
+
+ grub_nilfs2_read_file (diro, 0, 0,
+ grub_le_to_cpu64 (diro->inode.i_size),
+ symlink);
+ if (grub_errno)
+ {
+ grub_free (symlink);
+ return 0;
+ }
+
+ symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
+ return symlink;
+}
+
+static int
+grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
+ int NESTED_FUNC_ATTR
+ (*hook) (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node))
+{
+ unsigned int fpos = 0;
+ struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
+
+ if (! diro->inode_read)
+ {
+ grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
+ if (grub_errno)
+ return 0;
+ }
+
+ /* Iterate files. */
+ while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
+ {
+ struct grub_nilfs2_dir_entry dirent;
+
+ grub_nilfs2_read_file (diro, 0, fpos,
+ sizeof (struct grub_nilfs2_dir_entry),
+ (char *) &dirent);
+ if (grub_errno)
+ return 0;
+
+ if (dirent.rec_len == 0)
+ return 0;
+
+ if (dirent.name_len != 0)
+ {
+ char filename[dirent.name_len + 1];
+ struct grub_fshelp_node *fdiro;
+ enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
+
+ grub_nilfs2_read_file (diro, 0,
+ fpos + sizeof (struct grub_nilfs2_dir_entry),
+ dirent.name_len, filename);
+ if (grub_errno)
+ return 0;
+
+ fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
+ if (! fdiro)
+ return 0;
+
+ fdiro->data = diro->data;
+ fdiro->ino = grub_le_to_cpu64 (dirent.inode);
+
+ filename[dirent.name_len] = '\0';
+
+ if (dirent.file_type != NILFS_FT_UNKNOWN)
+ {
+ fdiro->inode_read = 0;
+
+ if (dirent.file_type == NILFS_FT_DIR)
+ type = GRUB_FSHELP_DIR;
+ else if (dirent.file_type == NILFS_FT_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if (dirent.file_type == NILFS_FT_REG_FILE)
+ type = GRUB_FSHELP_REG;
+ }
+ else
+ {
+ /* The filetype can not be read from the dirent, read
+ the inode to get more information. */
+ grub_nilfs2_read_inode (diro->data,
+ grub_le_to_cpu64 (dirent.inode),
+ &fdiro->inode);
+ if (grub_errno)
+ {
+ grub_free (fdiro);
+ return 0;
+ }
+
+ fdiro->inode_read = 1;
+
+ if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
+ type = GRUB_FSHELP_DIR;
+ else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
+ type = GRUB_FSHELP_SYMLINK;
+ else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
+ & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
+ type = GRUB_FSHELP_REG;
+ }
+
+ if (hook (filename, type, fdiro))
+ return 1;
+ }
+
+ fpos += grub_le_to_cpu16 (dirent.rec_len);
+ }
+
+ return 0;
+}
+
+/* Open a file named NAME and initialize FILE. */
+static grub_err_t
+grub_nilfs2_open (struct grub_file *file, const char *name)
+{
+ struct grub_nilfs2_data *data = NULL;
+ struct grub_fshelp_node *fdiro = 0;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (file->device->disk);
+ if (! data)
+ goto fail;
+
+ grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
+ grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
+ if (grub_errno)
+ goto fail;
+
+ if (! fdiro->inode_read)
+ {
+ grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
+ if (grub_errno)
+ goto fail;
+ }
+
+ grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
+ grub_free (fdiro);
+
+ file->size = grub_le_to_cpu64 (data->inode->i_size);
+ file->data = data;
+ file->offset = 0;
+
+ return 0;
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_close (grub_file_t file)
+{
+ grub_free (file->data);
+
+ grub_dl_unref (my_mod);
+
+ return GRUB_ERR_NONE;
+}
+
+/* Read LEN bytes data from FILE into BUF. */
+static grub_ssize_t
+grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
+{
+ struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
+
+ return grub_nilfs2_read_file (&data->diropen, file->read_hook,
+ file->offset, len, buf);
+}
+
+static grub_err_t
+grub_nilfs2_dir (grub_device_t device, const char *path,
+ int (*hook) (const char *filename,
+ const struct grub_dirhook_info *info))
+{
+ struct grub_nilfs2_data *data = 0;
+ struct grub_fshelp_node *fdiro = 0;
+
+ auto int NESTED_FUNC_ATTR iterate (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node);
+
+ int NESTED_FUNC_ATTR iterate (const char *filename,
+ enum grub_fshelp_filetype filetype,
+ grub_fshelp_node_t node)
+ {
+ struct grub_dirhook_info info;
+ grub_memset (&info, 0, sizeof (info));
+ if (! node->inode_read)
+ {
+ grub_nilfs2_read_inode (data, node->ino, &node->inode);
+ if (!grub_errno)
+ node->inode_read = 1;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (node->inode_read)
+ {
+ info.mtimeset = 1;
+ info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
+ }
+
+ info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+ grub_free (node);
+ return hook (filename, &info);
+ }
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (device->disk);
+ if (! data)
+ goto fail;
+
+ grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
+ grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
+ if (grub_errno)
+ goto fail;
+
+ grub_nilfs2_iterate_dir (fdiro, iterate);
+
+ fail:
+ if (fdiro != &data->diropen)
+ grub_free (fdiro);
+ grub_free (data);
+
+ grub_dl_unref (my_mod);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_label (grub_device_t device, char **label)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (data)
+ *label = grub_strndup (data->sblock.s_volume_name, 14);
+ else
+ *label = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_nilfs2_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (data)
+ {
+ *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
+ data->sblock.s_uuid[0], data->sblock.s_uuid[1],
+ data->sblock.s_uuid[2], data->sblock.s_uuid[3],
+ data->sblock.s_uuid[4], data->sblock.s_uuid[5],
+ data->sblock.s_uuid[6], data->sblock.s_uuid[7],
+ data->sblock.s_uuid[8], data->sblock.s_uuid[9],
+ data->sblock.s_uuid[10], data->sblock.s_uuid[11],
+ data->sblock.s_uuid[12], data->sblock.s_uuid[13],
+ data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
+ }
+ else
+ *uuid = NULL;
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+/* Get mtime. */
+static grub_err_t
+grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+ struct grub_nilfs2_data *data;
+ grub_disk_t disk = device->disk;
+
+ grub_dl_ref (my_mod);
+
+ data = grub_nilfs2_mount (disk);
+ if (!data)
+ *tm = 0;
+ else
+ *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
+
+ grub_dl_unref (my_mod);
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
+
+\f
+static struct grub_fs grub_nilfs2_fs=
+ {
+ .name = "nilfs2",
+ .dir = grub_nilfs2_dir,
+ .open = grub_nilfs2_open,
+ .read = grub_nilfs2_read,
+ .close = grub_nilfs2_close,
+ .label = grub_nilfs2_label,
+ .uuid = grub_nilfs2_uuid,
+ .mtime = grub_nilfs2_mtime,
+#ifdef GRUB_UTIL
+ .reserved_first_sector = 1,
+#endif
+ .next = 0
+ };
+
+GRUB_MOD_INIT(nilfs2)
+{
+ grub_fs_register (&grub_nilfs2_fs);
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(nilfs2)
+{
+ grub_fs_unregister (&grub_nilfs2_fs);
+}
=== modified file 'include/grub/misc.h'
--- include/grub/misc.h 2010-02-03 00:24:07 +0000
+++ include/grub/misc.h 2010-02-18 13:57:40 +0000
@@ -45,6 +45,7 @@
((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
#define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
#define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] a new filesystem module for nilfs2
2010-02-18 9:13 [PATCHv2] a new filesystem " Jiro SEKIBA
@ 2010-02-20 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-20 11:00 ` Jiro SEKIBA
2010-02-24 10:57 ` Vladimir 'φ-coder/phcoder' Serbinenko
1 sibling, 1 reply; 10+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-02-20 10:36 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 39069 bytes --]
Jiro SEKIBA wrote:
> Hi,
>
> This is a revised patch to support nilfs2, a log file system.
>
> I've checked it the first one on qemu-system-ppc and found a few bugs.
> Thank you for encouraging me to test it on qemu-system-ppc!
>
> This is a bug fixed version. I've checked it by grub-fstest on PPC
> and by installing and booting it to boot sector of nilfs2 partition on i386.
>
> Here are the change logs from the first one
>
> - big endian bug fixes
> * add "packed" attribute for all structs
>
Are you sure about this? It greatly impacts the performance on non-x86.
At first glance no structure in your patch should need this attribute.
Which structures were a problem?
> * swap physical block number bytes
> - separate pkglib_MODULES addition
> - leftover removal
> - moved DIV_ROUND_UP macro into misc.h
> - add separate function to check super block
> * add major version checking
>
> ToDo:
> 1. CRC check for superblock to ensure the partition is a nilfs2 partition
> 2. CRC check latest log block to ensure valid log
> 3. search the latest log in case unclean unmount happened
>
> thanks
>
> regards
>
> ------------------------------------------------------------------------
>
> === modified file 'conf/any-emu.rmk'
> --- conf/any-emu.rmk 2010-02-03 00:24:07 +0000
> +++ conf/any-emu.rmk 2010-02-18 13:57:40 +0000
> @@ -38,7 +38,7 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> fs/befs.c fs/befs_be.c fs/tar.c \
> \
>
> === modified file 'conf/common.rmk'
> --- conf/common.rmk 2010-02-06 14:37:23 +0000
> +++ conf/common.rmk 2010-02-18 13:57:40 +0000
> @@ -28,9 +28,9 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
> kern/fs.c kern/env.c fs/fshelp.c \
> @@ -65,7 +65,7 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
> fs/befs_be.c fs/tar.c \
> \
> @@ -270,6 +270,12 @@
> minix_mod_CFLAGS = $(COMMON_CFLAGS)
> minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
>
> +# For nilfs2.mod.
> +pkglib_MODULES += nilfs2.mod
> +nilfs2_mod_SOURCES = fs/nilfs2.c
> +nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
> +nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> # For hfs.mod.
> hfs_mod_SOURCES = fs/hfs.c
> hfs_mod_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/i386-pc.rmk'
> --- conf/i386-pc.rmk 2010-02-03 00:24:07 +0000
> +++ conf/i386-pc.rmk 2010-02-18 13:57:40 +0000
> @@ -100,9 +100,9 @@
> \
> fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/msdos.c partmap/gpt.c \
> \
>
> === modified file 'conf/sparc64-ieee1275.rmk'
> --- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
> +++ conf/sparc64-ieee1275.rmk 2010-02-18 13:57:40 +0000
> @@ -74,9 +74,9 @@
> \
> fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/amiga.c partmap/apple.c partmap/msdos.c \
> partmap/sun.c partmap/acorn.c \
>
> === added file 'fs/nilfs2.c'
> --- fs/nilfs2.c 1970-01-01 00:00:00 +0000
> +++ fs/nilfs2.c 2010-02-18 13:57:40 +0000
> @@ -0,0 +1,1126 @@
> +/*
> + * nilfs2.c - New Implementation of Log filesystem
> + * Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
> + */
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
> + *
> + * GRUB is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +
> +/* Filetype information as used in inodes. */
> +#define FILETYPE_INO_MASK 0170000
> +#define FILETYPE_INO_REG 0100000
> +#define FILETYPE_INO_DIRECTORY 0040000
> +#define FILETYPE_INO_SYMLINK 0120000
> +
> +#include <grub/err.h>
> +#include <grub/file.h>
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/disk.h>
> +#include <grub/dl.h>
> +#include <grub/types.h>
> +#include <grub/fshelp.h>
> +
> +/** nilfs_fs.h **/
> +#define NILFS_INODE_BMAP_SIZE 7
> +
> +#define NILFS_SUPORT_REV 2
> +#define NILFS_MINOR_REV 0
> +
> +/* Magic value used to identify an nilfs2 filesystem. */
> +#define NILFS2_SUPER_MAGIC 0x3434
> +/* nilfs btree node flag */
> +#define NILFS_BTREE_NODE_ROOT 0x01
> +
> +/* nilfs btree node level */
> +#define NILFS_BTREE_LEVEL_DATA 0
> +#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
> +#define NILFS_BTREE_LEVEL_MAX 14
> +
> +struct grub_nilfs2_inode
> +{
> + grub_uint64_t i_blocks;
> + grub_uint64_t i_size;
> + grub_uint64_t i_ctime;
> + grub_uint64_t i_mtime;
> + grub_uint32_t i_ctime_nsec;
> + grub_uint32_t i_mtime_nsec;
> + grub_uint32_t i_uid;
> + grub_uint32_t i_gid;
> + grub_uint16_t i_mode;
> + grub_uint16_t i_links_count;
> + grub_uint32_t i_flags;
> + grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
> +#define i_device_code i_bmap[0]
> + grub_uint64_t i_xattr;
> + grub_uint32_t i_generation;
> + grub_uint32_t i_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_super_root
> +{
> + grub_uint32_t sr_sum;
> + grub_uint16_t sr_bytes;
> + grub_uint16_t sr_flags;
> + grub_uint64_t sr_nongc_ctime;
> + struct grub_nilfs2_inode sr_dat;
> + struct grub_nilfs2_inode sr_cpfile;
> + struct grub_nilfs2_inode sr_sufile;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_super_block
> +{
> + grub_uint32_t s_rev_level;
> + grub_uint16_t s_minor_rev_level;
> + grub_uint16_t s_magic;
> + grub_uint16_t s_bytes;
> + grub_uint16_t s_flags;
> + grub_uint32_t s_crc_seed;
> + grub_uint32_t s_sum;
> + grub_uint32_t s_log_block_size;
> + grub_uint64_t s_nsegments;
> + grub_uint64_t s_dev_size;
> + grub_uint64_t s_first_data_block;
> + grub_uint32_t s_blocks_per_segment;
> + grub_uint32_t s_r_segments_percentage;
> + grub_uint64_t s_last_cno;
> + grub_uint64_t s_last_pseg;
> + grub_uint64_t s_last_seq;
> + grub_uint64_t s_free_blocks_count;
> + grub_uint64_t s_ctime;
> + grub_uint64_t s_mtime;
> + grub_uint64_t s_wtime;
> + grub_uint16_t s_mnt_count;
> + grub_uint16_t s_max_mnt_count;
> + grub_uint16_t s_state;
> + grub_uint16_t s_errors;
> + grub_uint64_t s_lastcheck;
> + grub_uint32_t s_checkinterval;
> + grub_uint32_t s_creator_os;
> + grub_uint16_t s_def_resuid;
> + grub_uint16_t s_def_resgid;
> + grub_uint32_t s_first_ino;
> + grub_uint16_t s_inode_size;
> + grub_uint16_t s_dat_entry_size;
> + grub_uint16_t s_checkpoint_size;
> + grub_uint16_t s_segment_usage_size;
> + grub_uint8_t s_uuid[16];
> + char s_volume_name[16];
> + char s_last_mounted[64];
> + grub_uint32_t s_c_interval;
> + grub_uint32_t s_c_block_max;
> + grub_uint32_t s_reserved[192];
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_dir_entry
> +{
> + grub_uint64_t inode;
> + grub_uint16_t rec_len;
> + grub_uint8_t name_len;
> + grub_uint8_t file_type;
> +#if 0 /* followed by file name */
> + char name[NILFS_NAME_LEN];
> + char pad;
> +#endif
> +} __attribute__ ((packed));
> +
> +enum
> +{
> + NILFS_FT_UNKNOWN,
> + NILFS_FT_REG_FILE,
> + NILFS_FT_DIR,
> + NILFS_FT_CHRDEV,
> + NILFS_FT_BLKDEV,
> + NILFS_FT_FIFO,
> + NILFS_FT_SOCK,
> + NILFS_FT_SYMLINK,
> + NILFS_FT_MAX
> +};
> +
> +struct grub_nilfs2_finfo
> +{
> + grub_uint64_t fi_ino;
> + grub_uint64_t fi_cno;
> + grub_uint32_t fi_nblocks;
> + grub_uint32_t fi_ndatablk;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_binfo_v
> +{
> + grub_uint64_t bi_vblocknr;
> + grub_uint64_t bi_blkoff;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_binfo_dat
> +{
> + grub_uint64_t bi_blkoff;
> + grub_uint8_t bi_level;
> + grub_uint8_t bi_pad[7];
> +} __attribute__ ((packed));
> +
> +union grub_nilfs2_binfo
> +{
> + struct grub_nilfs2_binfo_v bi_v;
> + struct grub_nilfs2_binfo_dat bi_dat;
> +};
> +
> +struct grub_nilfs2_segment_summary
> +{
> + grub_uint32_t ss_datasum;
> + grub_uint32_t ss_sumsum;
> + grub_uint32_t ss_magic;
> + grub_uint16_t ss_bytes;
> + grub_uint16_t ss_flags;
> + grub_uint64_t ss_seq;
> + grub_uint64_t ss_create;
> + grub_uint64_t ss_next;
> + grub_uint32_t ss_nblocks;
> + grub_uint32_t ss_nfinfo;
> + grub_uint32_t ss_sumbytes;
> + grub_uint32_t ss_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_btree_node
> +{
> + grub_uint8_t bn_flags;
> + grub_uint8_t bn_level;
> + grub_uint16_t bn_nchildren;
> + grub_uint32_t bn_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_palloc_group_desc
> +{
> + grub_uint32_t pg_nfrees;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_dat_entry
> +{
> + grub_uint64_t de_blocknr;
> + grub_uint64_t de_start;
> + grub_uint64_t de_end;
> + grub_uint64_t de_rsv;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_snapshot_list {
> + grub_uint64_t ssl_next;
> + grub_uint64_t ssl_prev;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_cpfile_header
> +{
> + grub_uint64_t ch_ncheckpoints;
> + grub_uint64_t ch_nsnapshots;
> + struct grub_nilfs2_snapshot_list ch_snapshot_list;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_checkpoint
> +{
> + grub_uint32_t cp_flags;
> + grub_uint32_t cp_checkpoints_count;
> + struct grub_nilfs2_snapshot_list cp_snapshot_list;
> + grub_uint64_t cp_cno;
> + grub_uint64_t cp_create;
> + grub_uint64_t cp_nblk_inc;
> + grub_uint64_t cp_inodes_count;
> + grub_uint64_t cp_blocks_count;
> + struct grub_nilfs2_inode cp_ifile_inode;
> +} __attribute__ ((packed));
> +
> +/** nilfs_fs.h **/
> +
> +/** bmap.h **/
> +#define NILFS_BMAP_LARGE 0x1
> +#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
> +/** bmap.h **/
> +
> +/** btree.h **/
> +/* nilfs extra padding for nonroot btree node */
> +#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
> +#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
> +#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
> + ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
> + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
> +/** btree.h **/
> +
> +
> +struct grub_fshelp_node
> +{
> + struct grub_nilfs2_data *data;
> + struct grub_nilfs2_inode inode;
> + grub_uint64_t ino;
> + int inode_read;
> +};
> +
> +struct grub_nilfs2_data
> +{
> + struct grub_nilfs2_super_block sblock;
> + struct grub_nilfs2_super_root sroot;
> + struct grub_nilfs2_inode ifile;
> + grub_disk_t disk;
> + struct grub_nilfs2_inode *inode;
> + struct grub_fshelp_node diropen;
> +};
> +
> +/* Log2 size of nilfs2 block in 512 blocks. */
> +#define LOG2_NILFS2_BLOCK_SIZE(data) \
> + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
> +
> +/* Log2 size of nilfs2 block in bytes. */
> +#define LOG2_BLOCK_SIZE(data) \
> + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
> +
> +/* The size of an nilfs2 block in bytes. */
> +#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
> +
> +static grub_uint64_t
> +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
> +static grub_dl_t my_mod;
> +
> +\f
> +
> +static inline unsigned long
> +grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
> +{
> + return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
> + grub_uint64_t nr, grub_uint32_t *offset)
> +{
> + return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
> +{
> + return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return NILFS2_BLOCK_SIZE(data) / entry_size;
> +}
> +
> +
> +static inline grub_uint32_t
> +grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
> + grub_nilfs2_entries_per_block(data,entry_size)) + 1;
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return grub_nilfs2_palloc_groups_per_desc_block(data) *
> + grub_nilfs2_blocks_per_group(data,entry_size) + 1;
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
> + unsigned long group,
> + unsigned long entry_size)
> +{
> + grub_uint32_t desc_block =
> + group / grub_nilfs2_palloc_groups_per_desc_block(data);
> + return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
> + unsigned long group,
> + unsigned long entry_size)
> +{
> + unsigned long desc_offset = group %
> + grub_nilfs2_palloc_groups_per_desc_block(data);
> +
> + return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
> + desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
> + grub_uint64_t nr, unsigned long entry_size)
> +{
> + unsigned long group;
> + grub_uint32_t group_offset;
> +
> + group = grub_nilfs2_palloc_group(data, nr, &group_offset);
> +
> + return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
> + group_offset / grub_nilfs2_entries_per_block(data, entry_size);
> +
> +}
> +
> +static inline struct grub_nilfs2_btree_node *
> +grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
> +{
> + return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
> +}
> +
> +static inline int
> +grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
> +{
> + return node->bn_level;
> +}
> +
> +static inline grub_uint64_t *
> +grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
> +{
> + return (grub_uint64_t *)((char *)(node + 1) +
> + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
> + 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
> +{
> + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
> +}
> +
> +static inline int
> +grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
> + grub_uint64_t key, int *indexp)
> +{
> + grub_uint64_t nkey;
> + int index, low, high, s;
> +
> + low = 0;
> + high = grub_le_to_cpu16(node->bn_nchildren) - 1;
> + index = 0;
> + s = 0;
> + while(low <= high)
> + {
> + index = (low+high)/2;
> + nkey = grub_nilfs2_btree_node_get_key(node, index);
> + if(nkey == key)
> + {
> + s = 0;
> + goto out;
> + }
> + else if (nkey < key)
> + {
> + low = index +1;
> + s = -1;
> + }
> + else
> + {
> + high = index - 1;
> + s = 1;
> + }
> + }
> +
> + if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
> + {
> + if (s > 0 && index > 0)
> + index--;
> + }
> + else if (s < 0)
> + index++;
> +
> + out:
> + *indexp = index;
> + return s == 0;
> +}
> +
> +static inline int
> +grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node)
> +{
> + int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
> + sizeof(struct grub_nilfs2_btree_node) -
> + NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
> + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
> +
> + return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
> +}
> +
> +static inline grub_uint64_t *
> +grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node)
> +{
> + return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
> + grub_nilfs2_btree_node_nchildren_max(data,node));
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node, int index)
> +{
> + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
> +}
> +
> +static inline int
> +grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
> + grub_uint64_t ptr, void *block)
> +{
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
> + NILFS2_BLOCK_SIZE(data), block);
> +}
> +
> +static grub_uint64_t
> +grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_inode *inode,
> + grub_uint64_t key, int need_translate)
> +{
> + struct grub_nilfs2_btree_node *node;
> + unsigned char block[NILFS2_BLOCK_SIZE(data)];
> + grub_uint64_t ptr;
> + int level, found, index;
> +
> + node = grub_nilfs2_btree_get_root(inode);
> + level = grub_nilfs2_btree_get_level(node);
> +
> + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> +
> + for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
> + {
> + grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
> + if(grub_errno)
> + {
> + grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
> + return -1;
> + }
> + node = (struct grub_nilfs2_btree_node *)block;
> +
> + if(node->bn_level != level)
> + {
> + grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
> + return -1;
> + }
> +
> + if(!found)
> + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> + else
> + index = 0;
> +
> + if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
> + {
> + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> + }
> + else
> + {
> + grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
> + return -1;
> + }
> + }
> +
> + if(!found)
> + return -1;
> +
> + return ptr;
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
> +{
> + return grub_le_to_cpu64(inode->i_bmap[1+key]);
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_inode *inode,
> + grub_uint64_t key, int need_translate)
> +{
> + struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
> + if(root->bn_flags & NILFS_BMAP_LARGE)
> + return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
> + else
> + {
> + grub_uint64_t ptr;
> + ptr = grub_nilfs2_direct_lookup(inode, key);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> + return ptr;
> + }
> +}
> +
> +static grub_uint64_t
> +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
> +{
> + struct grub_nilfs2_dat_entry entry;
> + grub_disk_t disk = data->disk;
> + grub_uint64_t pptr;
> + grub_uint32_t blockno, offset;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + blockno = grub_nilfs2_palloc_entry_offset(data, key,
> + sizeof(struct grub_nilfs2_dat_entry));
> +
> + grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
> + NILFS2_BLOCK_SIZE(data), &offset);
> +
> + pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return -1;
> + }
> +
> + grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> + sizeof (struct grub_nilfs2_dat_entry), &entry);
> +
> + return grub_le_to_cpu64(entry.de_blocknr);
> +}
> +
> +
> +static grub_disk_addr_t
> +grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
> +{
> + struct grub_nilfs2_data *data = node->data;
> + struct grub_nilfs2_inode *inode = &node->inode;
> + grub_uint64_t pptr = -1;
> +
> + pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return -1;
> + }
> +
> + return pptr;
> +}
> +
> +/* Read LEN bytes from the file described by DATA starting with byte
> + POS. Return the amount of read bytes in READ. */
> +static grub_ssize_t
> +grub_nilfs2_read_file (grub_fshelp_node_t node,
> + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
> + unsigned offset, unsigned length),
> + int pos, grub_size_t len, char *buf)
> +{
> + return grub_fshelp_read_file (node->data->disk, node, read_hook,
> + pos, len, buf, grub_nilfs2_read_block,
> + grub_le_to_cpu64(node->inode.i_size),
> + LOG2_NILFS2_BLOCK_SIZE (node->data));
> +
> +}
> +
> +static grub_err_t
> +grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
> + grub_uint64_t cpno,
> + struct grub_nilfs2_checkpoint *cpp)
> +{
> + grub_uint64_t blockno;
> + grub_uint32_t offset;
> + grub_uint64_t pptr;
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + /* assume sizeof(struct grub_nilfs2_cpfile_header) <
> + sizeof(struct grub_nilfs2_checkpoint)
> + */
> + blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
> + sizeof(struct grub_nilfs2_checkpoint) , &offset);
> +
> + pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return GRUB_ERR_BAD_FS;
> + }
> +
> + return grub_disk_read (disk, pptr * nilfs2_block_count,
> + offset * sizeof(struct grub_nilfs2_checkpoint),
> + sizeof (struct grub_nilfs2_checkpoint),
> + cpp);
> +}
> +
> +static inline grub_err_t
> +grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_checkpoint *cpp)
> +{
> + return grub_nilfs2_read_checkpoint(data,
> + grub_le_to_cpu64(data->sblock.s_last_cno),
> + cpp);
> +}
> +
> +/* Read the inode INO for the file described by DATA into INODE. */
> +static grub_err_t
> +grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
> + grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
> +{
> + grub_uint64_t blockno;
> + unsigned int offset;
> + grub_uint64_t pptr;
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + blockno = grub_nilfs2_palloc_entry_offset(data, ino,
> + sizeof(struct grub_nilfs2_inode));
> +
> + grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
> + NILFS2_BLOCK_SIZE(data), &offset);
> + pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return GRUB_ERR_BAD_FS;
> + }
> +
> + return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> + sizeof (struct grub_nilfs2_inode),
> + inodep);
> +}
> +
> +static int grub_nilfs2_valid_sb(struct grub_nilfs2_super_block *sbp)
> +{
> + if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
> + return 0;
> +
> + if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
> + return 0;
> +
> + return 1;
> +}
> +
> +static struct grub_nilfs2_data *
> +grub_nilfs2_mount (grub_disk_t disk)
> +{
> + struct grub_nilfs2_data *data;
> + struct grub_nilfs2_segment_summary ss;
> + struct grub_nilfs2_checkpoint last_checkpoint;
> + grub_uint64_t last_pseg;
> + grub_uint32_t nblocks;
> + unsigned int nilfs2_block_count;
> +
> + data = grub_malloc (sizeof (struct grub_nilfs2_data));
> + if (!data)
> + return 0;
> +
> + /* Read the superblock. */
> + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
> + &data->sblock);
> + if (grub_errno)
> + goto fail;
> +
> + /* Make sure this is an nilfs2 filesystem. */
> + if (!grub_nilfs2_valid_sb(&data->sblock))
> + {
> + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> + goto fail;
> + }
> +
> + nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + /* Read the last segment summary */
> + last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
> + grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
> + sizeof (struct grub_nilfs2_segment_summary), &ss);
> +
> + if (grub_errno)
> + goto fail;
> +
> + /* Read the super root block */
> + nblocks = grub_le_to_cpu32(ss.ss_nblocks);
> + grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
> + sizeof (struct grub_nilfs2_super_root), &data->sroot);
> +
> + if (grub_errno)
> + goto fail;
> +
> + data->disk = disk;
> +
> + grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
> +
> + if (grub_errno)
> + goto fail;
> +
> + grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
> + sizeof(struct grub_nilfs2_inode));
> +
> + data->diropen.data = data;
> + data->diropen.ino = 2;
> + data->diropen.inode_read = 1;
> + data->inode = &data->diropen.inode;
> +
> + grub_nilfs2_read_inode(data, 2, data->inode);
> +
> + return data;
> +
> + fail:
> + if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
> + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> +
> + grub_free (data);
> + return 0;
> +}
> +
> +static char *
> +grub_nilfs2_read_symlink (grub_fshelp_node_t node)
> +{
> + char *symlink;
> + struct grub_fshelp_node *diro = node;
> +
> + if (! diro->inode_read)
> + {
> + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> + if (grub_errno)
> + return 0;
> + }
> +
> + symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
> + if (! symlink)
> + return 0;
> +
> + grub_nilfs2_read_file (diro, 0, 0,
> + grub_le_to_cpu64 (diro->inode.i_size),
> + symlink);
> + if (grub_errno)
> + {
> + grub_free (symlink);
> + return 0;
> + }
> +
> + symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
> + return symlink;
> +}
> +
> +static int
> +grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
> + int NESTED_FUNC_ATTR
> + (*hook) (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node))
> +{
> + unsigned int fpos = 0;
> + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
> +
> + if (! diro->inode_read)
> + {
> + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> + if (grub_errno)
> + return 0;
> + }
> +
> + /* Iterate files. */
> + while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
> + {
> + struct grub_nilfs2_dir_entry dirent;
> +
> + grub_nilfs2_read_file (diro, 0, fpos,
> + sizeof (struct grub_nilfs2_dir_entry),
> + (char *) &dirent);
> + if (grub_errno)
> + return 0;
> +
> + if (dirent.rec_len == 0)
> + return 0;
> +
> + if (dirent.name_len != 0)
> + {
> + char filename[dirent.name_len + 1];
> + struct grub_fshelp_node *fdiro;
> + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
> +
> + grub_nilfs2_read_file (diro, 0,
> + fpos + sizeof (struct grub_nilfs2_dir_entry),
> + dirent.name_len, filename);
> + if (grub_errno)
> + return 0;
> +
> + fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> + if (! fdiro)
> + return 0;
> +
> + fdiro->data = diro->data;
> + fdiro->ino = grub_le_to_cpu64 (dirent.inode);
> +
> + filename[dirent.name_len] = '\0';
> +
> + if (dirent.file_type != NILFS_FT_UNKNOWN)
> + {
> + fdiro->inode_read = 0;
> +
> + if (dirent.file_type == NILFS_FT_DIR)
> + type = GRUB_FSHELP_DIR;
> + else if (dirent.file_type == NILFS_FT_SYMLINK)
> + type = GRUB_FSHELP_SYMLINK;
> + else if (dirent.file_type == NILFS_FT_REG_FILE)
> + type = GRUB_FSHELP_REG;
> + }
> + else
> + {
> + /* The filetype can not be read from the dirent, read
> + the inode to get more information. */
> + grub_nilfs2_read_inode (diro->data,
> + grub_le_to_cpu64 (dirent.inode),
> + &fdiro->inode);
> + if (grub_errno)
> + {
> + grub_free (fdiro);
> + return 0;
> + }
> +
> + fdiro->inode_read = 1;
> +
> + if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
> + type = GRUB_FSHELP_DIR;
> + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
> + type = GRUB_FSHELP_SYMLINK;
> + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
> + type = GRUB_FSHELP_REG;
> + }
> +
> + if (hook (filename, type, fdiro))
> + return 1;
> + }
> +
> + fpos += grub_le_to_cpu16 (dirent.rec_len);
> + }
> +
> + return 0;
> +}
> +
> +/* Open a file named NAME and initialize FILE. */
> +static grub_err_t
> +grub_nilfs2_open (struct grub_file *file, const char *name)
> +{
> + struct grub_nilfs2_data *data = NULL;
> + struct grub_fshelp_node *fdiro = 0;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (file->device->disk);
> + if (! data)
> + goto fail;
> +
> + grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> + grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
> + if (grub_errno)
> + goto fail;
> +
> + if (! fdiro->inode_read)
> + {
> + grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
> + if (grub_errno)
> + goto fail;
> + }
> +
> + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
> + grub_free (fdiro);
> +
> + file->size = grub_le_to_cpu64 (data->inode->i_size);
> + file->data = data;
> + file->offset = 0;
> +
> + return 0;
> +
> + fail:
> + if (fdiro != &data->diropen)
> + grub_free (fdiro);
> + grub_free (data);
> +
> + grub_dl_unref (my_mod);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_close (grub_file_t file)
> +{
> + grub_free (file->data);
> +
> + grub_dl_unref (my_mod);
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +/* Read LEN bytes data from FILE into BUF. */
> +static grub_ssize_t
> +grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
> +{
> + struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
> +
> + return grub_nilfs2_read_file (&data->diropen, file->read_hook,
> + file->offset, len, buf);
> +}
> +
> +static grub_err_t
> +grub_nilfs2_dir (grub_device_t device, const char *path,
> + int (*hook) (const char *filename,
> + const struct grub_dirhook_info *info))
> +{
> + struct grub_nilfs2_data *data = 0;
> + struct grub_fshelp_node *fdiro = 0;
> +
> + auto int NESTED_FUNC_ATTR iterate (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node);
> +
> + int NESTED_FUNC_ATTR iterate (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node)
> + {
> + struct grub_dirhook_info info;
> + grub_memset (&info, 0, sizeof (info));
> + if (! node->inode_read)
> + {
> + grub_nilfs2_read_inode (data, node->ino, &node->inode);
> + if (!grub_errno)
> + node->inode_read = 1;
> + grub_errno = GRUB_ERR_NONE;
> + }
> + if (node->inode_read)
> + {
> + info.mtimeset = 1;
> + info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
> + }
> +
> + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
> + grub_free (node);
> + return hook (filename, &info);
> + }
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (device->disk);
> + if (! data)
> + goto fail;
> +
> + grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> + grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
> + if (grub_errno)
> + goto fail;
> +
> + grub_nilfs2_iterate_dir (fdiro, iterate);
> +
> + fail:
> + if (fdiro != &data->diropen)
> + grub_free (fdiro);
> + grub_free (data);
> +
> + grub_dl_unref (my_mod);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_label (grub_device_t device, char **label)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (data)
> + *label = grub_strndup (data->sblock.s_volume_name, 14);
> + else
> + *label = NULL;
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_uuid (grub_device_t device, char **uuid)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (data)
> + {
> + *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
> + data->sblock.s_uuid[0], data->sblock.s_uuid[1],
> + data->sblock.s_uuid[2], data->sblock.s_uuid[3],
> + data->sblock.s_uuid[4], data->sblock.s_uuid[5],
> + data->sblock.s_uuid[6], data->sblock.s_uuid[7],
> + data->sblock.s_uuid[8], data->sblock.s_uuid[9],
> + data->sblock.s_uuid[10], data->sblock.s_uuid[11],
> + data->sblock.s_uuid[12], data->sblock.s_uuid[13],
> + data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
> + }
> + else
> + *uuid = NULL;
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +/* Get mtime. */
> +static grub_err_t
> +grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (!data)
> + *tm = 0;
> + else
> + *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +
> +\f
> +static struct grub_fs grub_nilfs2_fs=
> + {
> + .name = "nilfs2",
> + .dir = grub_nilfs2_dir,
> + .open = grub_nilfs2_open,
> + .read = grub_nilfs2_read,
> + .close = grub_nilfs2_close,
> + .label = grub_nilfs2_label,
> + .uuid = grub_nilfs2_uuid,
> + .mtime = grub_nilfs2_mtime,
> +#ifdef GRUB_UTIL
> + .reserved_first_sector = 1,
> +#endif
> + .next = 0
> + };
> +
> +GRUB_MOD_INIT(nilfs2)
> +{
> + grub_fs_register (&grub_nilfs2_fs);
> + my_mod = mod;
> +}
> +
> +GRUB_MOD_FINI(nilfs2)
> +{
> + grub_fs_unregister (&grub_nilfs2_fs);
> +}
>
> === modified file 'include/grub/misc.h'
> --- include/grub/misc.h 2010-02-03 00:24:07 +0000
> +++ include/grub/misc.h 2010-02-18 13:57:40 +0000
> @@ -45,6 +45,7 @@
> ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
> #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
> #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
>
> #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
> /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] a new filesystem module for nilfs2
2010-02-20 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-02-20 11:00 ` Jiro SEKIBA
0 siblings, 0 replies; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-20 11:00 UTC (permalink / raw)
To: The development of GNU GRUB
Hi,
At Sat, 20 Feb 2010 11:36:37 +0100,
Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>
> [1 <multipart/signed (7bit)>]
> [1.1 <text/plain; UTF-8 (quoted-printable)>]
> Jiro SEKIBA wrote:
> > Hi,
> >
> > This is a revised patch to support nilfs2, a log file system.
> >
> > I've checked it the first one on qemu-system-ppc and found a few bugs.
> > Thank you for encouraging me to test it on qemu-system-ppc!
> >
> > This is a bug fixed version. I've checked it by grub-fstest on PPC
> > and by installing and booting it to boot sector of nilfs2 partition on i386.
> >
> > Here are the change logs from the first one
> >
> > - big endian bug fixes
> > * add "packed" attribute for all structs
> >
> Are you sure about this? It greatly impacts the performance on non-x86.
> At first glance no structure in your patch should need this attribute.
> Which structures were a problem?
The one I needed is grub_nilfs2_dir_entry. Actual struct in nilfs2 has
char name[] and pad followed by the struc tmembers.
The struct is 12bytes and no padding was inserted on x86.
However, on PPC, extra 4 bytes padding was inserted to align 16bytes boundary.
Actual disk formats is, of course, aligned to 16 bytes.
I didn't need to the attribute for other struct on PPC.
However, I just wanted to avoid the extra padding, just in case.
thank you very much for you attention
> > * swap physical block number bytes
> > - separate pkglib_MODULES addition
> > - leftover removal
> > - moved DIV_ROUND_UP macro into misc.h
> > - add separate function to check super block
> > * add major version checking
> >
> > ToDo:
> > 1. CRC check for superblock to ensure the partition is a nilfs2 partition
> > 2. CRC check latest log block to ensure valid log
> > 3. search the latest log in case unclean unmount happened
> >
> > thanks
> >
> > regards
> >
> > ------------------------------------------------------------------------
> >
> > === modified file 'conf/any-emu.rmk'
> > --- conf/any-emu.rmk 2010-02-03 00:24:07 +0000
> > +++ conf/any-emu.rmk 2010-02-18 13:57:40 +0000
> > @@ -38,7 +38,7 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> >
> > === modified file 'conf/common.rmk'
> > --- conf/common.rmk 2010-02-06 14:37:23 +0000
> > +++ conf/common.rmk 2010-02-18 13:57:40 +0000
> > @@ -28,9 +28,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
> > kern/fs.c kern/env.c fs/fshelp.c \
> > @@ -65,7 +65,7 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
> > fs/befs_be.c fs/tar.c \
> > \
> > @@ -270,6 +270,12 @@
> > minix_mod_CFLAGS = $(COMMON_CFLAGS)
> > minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
> >
> > +# For nilfs2.mod.
> > +pkglib_MODULES += nilfs2.mod
> > +nilfs2_mod_SOURCES = fs/nilfs2.c
> > +nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
> > +nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > # For hfs.mod.
> > hfs_mod_SOURCES = fs/hfs.c
> > hfs_mod_CFLAGS = $(COMMON_CFLAGS)
> >
> > === modified file 'conf/i386-pc.rmk'
> > --- conf/i386-pc.rmk 2010-02-03 00:24:07 +0000
> > +++ conf/i386-pc.rmk 2010-02-18 13:57:40 +0000
> > @@ -100,9 +100,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/msdos.c partmap/gpt.c \
> > \
> >
> > === modified file 'conf/sparc64-ieee1275.rmk'
> > --- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
> > +++ conf/sparc64-ieee1275.rmk 2010-02-18 13:57:40 +0000
> > @@ -74,9 +74,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/amiga.c partmap/apple.c partmap/msdos.c \
> > partmap/sun.c partmap/acorn.c \
> >
> > === added file 'fs/nilfs2.c'
> > --- fs/nilfs2.c 1970-01-01 00:00:00 +0000
> > +++ fs/nilfs2.c 2010-02-18 13:57:40 +0000
> > @@ -0,0 +1,1126 @@
> > +/*
> > + * nilfs2.c - New Implementation of Log filesystem
> > + * Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
> > + */
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
> > + *
> > + * GRUB is free software: you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, either version 3 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +
> > +/* Filetype information as used in inodes. */
> > +#define FILETYPE_INO_MASK 0170000
> > +#define FILETYPE_INO_REG 0100000
> > +#define FILETYPE_INO_DIRECTORY 0040000
> > +#define FILETYPE_INO_SYMLINK 0120000
> > +
> > +#include <grub/err.h>
> > +#include <grub/file.h>
> > +#include <grub/mm.h>
> > +#include <grub/misc.h>
> > +#include <grub/disk.h>
> > +#include <grub/dl.h>
> > +#include <grub/types.h>
> > +#include <grub/fshelp.h>
> > +
> > +/** nilfs_fs.h **/
> > +#define NILFS_INODE_BMAP_SIZE 7
> > +
> > +#define NILFS_SUPORT_REV 2
> > +#define NILFS_MINOR_REV 0
> > +
> > +/* Magic value used to identify an nilfs2 filesystem. */
> > +#define NILFS2_SUPER_MAGIC 0x3434
> > +/* nilfs btree node flag */
> > +#define NILFS_BTREE_NODE_ROOT 0x01
> > +
> > +/* nilfs btree node level */
> > +#define NILFS_BTREE_LEVEL_DATA 0
> > +#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
> > +#define NILFS_BTREE_LEVEL_MAX 14
> > +
> > +struct grub_nilfs2_inode
> > +{
> > + grub_uint64_t i_blocks;
> > + grub_uint64_t i_size;
> > + grub_uint64_t i_ctime;
> > + grub_uint64_t i_mtime;
> > + grub_uint32_t i_ctime_nsec;
> > + grub_uint32_t i_mtime_nsec;
> > + grub_uint32_t i_uid;
> > + grub_uint32_t i_gid;
> > + grub_uint16_t i_mode;
> > + grub_uint16_t i_links_count;
> > + grub_uint32_t i_flags;
> > + grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
> > +#define i_device_code i_bmap[0]
> > + grub_uint64_t i_xattr;
> > + grub_uint32_t i_generation;
> > + grub_uint32_t i_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_super_root
> > +{
> > + grub_uint32_t sr_sum;
> > + grub_uint16_t sr_bytes;
> > + grub_uint16_t sr_flags;
> > + grub_uint64_t sr_nongc_ctime;
> > + struct grub_nilfs2_inode sr_dat;
> > + struct grub_nilfs2_inode sr_cpfile;
> > + struct grub_nilfs2_inode sr_sufile;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_super_block
> > +{
> > + grub_uint32_t s_rev_level;
> > + grub_uint16_t s_minor_rev_level;
> > + grub_uint16_t s_magic;
> > + grub_uint16_t s_bytes;
> > + grub_uint16_t s_flags;
> > + grub_uint32_t s_crc_seed;
> > + grub_uint32_t s_sum;
> > + grub_uint32_t s_log_block_size;
> > + grub_uint64_t s_nsegments;
> > + grub_uint64_t s_dev_size;
> > + grub_uint64_t s_first_data_block;
> > + grub_uint32_t s_blocks_per_segment;
> > + grub_uint32_t s_r_segments_percentage;
> > + grub_uint64_t s_last_cno;
> > + grub_uint64_t s_last_pseg;
> > + grub_uint64_t s_last_seq;
> > + grub_uint64_t s_free_blocks_count;
> > + grub_uint64_t s_ctime;
> > + grub_uint64_t s_mtime;
> > + grub_uint64_t s_wtime;
> > + grub_uint16_t s_mnt_count;
> > + grub_uint16_t s_max_mnt_count;
> > + grub_uint16_t s_state;
> > + grub_uint16_t s_errors;
> > + grub_uint64_t s_lastcheck;
> > + grub_uint32_t s_checkinterval;
> > + grub_uint32_t s_creator_os;
> > + grub_uint16_t s_def_resuid;
> > + grub_uint16_t s_def_resgid;
> > + grub_uint32_t s_first_ino;
> > + grub_uint16_t s_inode_size;
> > + grub_uint16_t s_dat_entry_size;
> > + grub_uint16_t s_checkpoint_size;
> > + grub_uint16_t s_segment_usage_size;
> > + grub_uint8_t s_uuid[16];
> > + char s_volume_name[16];
> > + char s_last_mounted[64];
> > + grub_uint32_t s_c_interval;
> > + grub_uint32_t s_c_block_max;
> > + grub_uint32_t s_reserved[192];
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_dir_entry
> > +{
> > + grub_uint64_t inode;
> > + grub_uint16_t rec_len;
> > + grub_uint8_t name_len;
> > + grub_uint8_t file_type;
> > +#if 0 /* followed by file name */
> > + char name[NILFS_NAME_LEN];
> > + char pad;
> > +#endif
> > +} __attribute__ ((packed));
> > +
> > +enum
> > +{
> > + NILFS_FT_UNKNOWN,
> > + NILFS_FT_REG_FILE,
> > + NILFS_FT_DIR,
> > + NILFS_FT_CHRDEV,
> > + NILFS_FT_BLKDEV,
> > + NILFS_FT_FIFO,
> > + NILFS_FT_SOCK,
> > + NILFS_FT_SYMLINK,
> > + NILFS_FT_MAX
> > +};
> > +
> > +struct grub_nilfs2_finfo
> > +{
> > + grub_uint64_t fi_ino;
> > + grub_uint64_t fi_cno;
> > + grub_uint32_t fi_nblocks;
> > + grub_uint32_t fi_ndatablk;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_binfo_v
> > +{
> > + grub_uint64_t bi_vblocknr;
> > + grub_uint64_t bi_blkoff;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_binfo_dat
> > +{
> > + grub_uint64_t bi_blkoff;
> > + grub_uint8_t bi_level;
> > + grub_uint8_t bi_pad[7];
> > +} __attribute__ ((packed));
> > +
> > +union grub_nilfs2_binfo
> > +{
> > + struct grub_nilfs2_binfo_v bi_v;
> > + struct grub_nilfs2_binfo_dat bi_dat;
> > +};
> > +
> > +struct grub_nilfs2_segment_summary
> > +{
> > + grub_uint32_t ss_datasum;
> > + grub_uint32_t ss_sumsum;
> > + grub_uint32_t ss_magic;
> > + grub_uint16_t ss_bytes;
> > + grub_uint16_t ss_flags;
> > + grub_uint64_t ss_seq;
> > + grub_uint64_t ss_create;
> > + grub_uint64_t ss_next;
> > + grub_uint32_t ss_nblocks;
> > + grub_uint32_t ss_nfinfo;
> > + grub_uint32_t ss_sumbytes;
> > + grub_uint32_t ss_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_btree_node
> > +{
> > + grub_uint8_t bn_flags;
> > + grub_uint8_t bn_level;
> > + grub_uint16_t bn_nchildren;
> > + grub_uint32_t bn_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_palloc_group_desc
> > +{
> > + grub_uint32_t pg_nfrees;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_dat_entry
> > +{
> > + grub_uint64_t de_blocknr;
> > + grub_uint64_t de_start;
> > + grub_uint64_t de_end;
> > + grub_uint64_t de_rsv;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_snapshot_list {
> > + grub_uint64_t ssl_next;
> > + grub_uint64_t ssl_prev;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_cpfile_header
> > +{
> > + grub_uint64_t ch_ncheckpoints;
> > + grub_uint64_t ch_nsnapshots;
> > + struct grub_nilfs2_snapshot_list ch_snapshot_list;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_checkpoint
> > +{
> > + grub_uint32_t cp_flags;
> > + grub_uint32_t cp_checkpoints_count;
> > + struct grub_nilfs2_snapshot_list cp_snapshot_list;
> > + grub_uint64_t cp_cno;
> > + grub_uint64_t cp_create;
> > + grub_uint64_t cp_nblk_inc;
> > + grub_uint64_t cp_inodes_count;
> > + grub_uint64_t cp_blocks_count;
> > + struct grub_nilfs2_inode cp_ifile_inode;
> > +} __attribute__ ((packed));
> > +
> > +/** nilfs_fs.h **/
> > +
> > +/** bmap.h **/
> > +#define NILFS_BMAP_LARGE 0x1
> > +#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
> > +/** bmap.h **/
> > +
> > +/** btree.h **/
> > +/* nilfs extra padding for nonroot btree node */
> > +#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
> > +#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
> > +#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
> > + ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
> > + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
> > +/** btree.h **/
> > +
> > +
> > +struct grub_fshelp_node
> > +{
> > + struct grub_nilfs2_data *data;
> > + struct grub_nilfs2_inode inode;
> > + grub_uint64_t ino;
> > + int inode_read;
> > +};
> > +
> > +struct grub_nilfs2_data
> > +{
> > + struct grub_nilfs2_super_block sblock;
> > + struct grub_nilfs2_super_root sroot;
> > + struct grub_nilfs2_inode ifile;
> > + grub_disk_t disk;
> > + struct grub_nilfs2_inode *inode;
> > + struct grub_fshelp_node diropen;
> > +};
> > +
> > +/* Log2 size of nilfs2 block in 512 blocks. */
> > +#define LOG2_NILFS2_BLOCK_SIZE(data) \
> > + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
> > +
> > +/* Log2 size of nilfs2 block in bytes. */
> > +#define LOG2_BLOCK_SIZE(data) \
> > + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
> > +
> > +/* The size of an nilfs2 block in bytes. */
> > +#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
> > +static grub_dl_t my_mod;
> > +
> > +\f
> > +
> > +static inline unsigned long
> > +grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
> > +{
> > + return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
> > + grub_uint64_t nr, grub_uint32_t *offset)
> > +{
> > + return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
> > +{
> > + return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return NILFS2_BLOCK_SIZE(data) / entry_size;
> > +}
> > +
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
> > + grub_nilfs2_entries_per_block(data,entry_size)) + 1;
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return grub_nilfs2_palloc_groups_per_desc_block(data) *
> > + grub_nilfs2_blocks_per_group(data,entry_size) + 1;
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
> > + unsigned long group,
> > + unsigned long entry_size)
> > +{
> > + grub_uint32_t desc_block =
> > + group / grub_nilfs2_palloc_groups_per_desc_block(data);
> > + return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
> > + unsigned long group,
> > + unsigned long entry_size)
> > +{
> > + unsigned long desc_offset = group %
> > + grub_nilfs2_palloc_groups_per_desc_block(data);
> > +
> > + return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
> > + desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
> > + grub_uint64_t nr, unsigned long entry_size)
> > +{
> > + unsigned long group;
> > + grub_uint32_t group_offset;
> > +
> > + group = grub_nilfs2_palloc_group(data, nr, &group_offset);
> > +
> > + return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
> > + group_offset / grub_nilfs2_entries_per_block(data, entry_size);
> > +
> > +}
> > +
> > +static inline struct grub_nilfs2_btree_node *
> > +grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
> > +{
> > + return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
> > +{
> > + return node->bn_level;
> > +}
> > +
> > +static inline grub_uint64_t *
> > +grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
> > +{
> > + return (grub_uint64_t *)((char *)(node + 1) +
> > + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
> > + 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
> > +{
> > + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
> > + grub_uint64_t key, int *indexp)
> > +{
> > + grub_uint64_t nkey;
> > + int index, low, high, s;
> > +
> > + low = 0;
> > + high = grub_le_to_cpu16(node->bn_nchildren) - 1;
> > + index = 0;
> > + s = 0;
> > + while(low <= high)
> > + {
> > + index = (low+high)/2;
> > + nkey = grub_nilfs2_btree_node_get_key(node, index);
> > + if(nkey == key)
> > + {
> > + s = 0;
> > + goto out;
> > + }
> > + else if (nkey < key)
> > + {
> > + low = index +1;
> > + s = -1;
> > + }
> > + else
> > + {
> > + high = index - 1;
> > + s = 1;
> > + }
> > + }
> > +
> > + if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
> > + {
> > + if (s > 0 && index > 0)
> > + index--;
> > + }
> > + else if (s < 0)
> > + index++;
> > +
> > + out:
> > + *indexp = index;
> > + return s == 0;
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node)
> > +{
> > + int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
> > + sizeof(struct grub_nilfs2_btree_node) -
> > + NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
> > + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
> > +
> > + return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
> > +}
> > +
> > +static inline grub_uint64_t *
> > +grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node)
> > +{
> > + return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
> > + grub_nilfs2_btree_node_nchildren_max(data,node));
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node, int index)
> > +{
> > + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
> > + grub_uint64_t ptr, void *block)
> > +{
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
> > + NILFS2_BLOCK_SIZE(data), block);
> > +}
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_inode *inode,
> > + grub_uint64_t key, int need_translate)
> > +{
> > + struct grub_nilfs2_btree_node *node;
> > + unsigned char block[NILFS2_BLOCK_SIZE(data)];
> > + grub_uint64_t ptr;
> > + int level, found, index;
> > +
> > + node = grub_nilfs2_btree_get_root(inode);
> > + level = grub_nilfs2_btree_get_level(node);
> > +
> > + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> > + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > +
> > + for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
> > + {
> > + grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
> > + if(grub_errno)
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
> > + return -1;
> > + }
> > + node = (struct grub_nilfs2_btree_node *)block;
> > +
> > + if(node->bn_level != level)
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
> > + return -1;
> > + }
> > +
> > + if(!found)
> > + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> > + else
> > + index = 0;
> > +
> > + if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
> > + {
> > + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > + }
> > + else
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
> > + return -1;
> > + }
> > + }
> > +
> > + if(!found)
> > + return -1;
> > +
> > + return ptr;
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
> > +{
> > + return grub_le_to_cpu64(inode->i_bmap[1+key]);
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_inode *inode,
> > + grub_uint64_t key, int need_translate)
> > +{
> > + struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
> > + if(root->bn_flags & NILFS_BMAP_LARGE)
> > + return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
> > + else
> > + {
> > + grub_uint64_t ptr;
> > + ptr = grub_nilfs2_direct_lookup(inode, key);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > + return ptr;
> > + }
> > +}
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
> > +{
> > + struct grub_nilfs2_dat_entry entry;
> > + grub_disk_t disk = data->disk;
> > + grub_uint64_t pptr;
> > + grub_uint32_t blockno, offset;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + blockno = grub_nilfs2_palloc_entry_offset(data, key,
> > + sizeof(struct grub_nilfs2_dat_entry));
> > +
> > + grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
> > + NILFS2_BLOCK_SIZE(data), &offset);
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return -1;
> > + }
> > +
> > + grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> > + sizeof (struct grub_nilfs2_dat_entry), &entry);
> > +
> > + return grub_le_to_cpu64(entry.de_blocknr);
> > +}
> > +
> > +
> > +static grub_disk_addr_t
> > +grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
> > +{
> > + struct grub_nilfs2_data *data = node->data;
> > + struct grub_nilfs2_inode *inode = &node->inode;
> > + grub_uint64_t pptr = -1;
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return -1;
> > + }
> > +
> > + return pptr;
> > +}
> > +
> > +/* Read LEN bytes from the file described by DATA starting with byte
> > + POS. Return the amount of read bytes in READ. */
> > +static grub_ssize_t
> > +grub_nilfs2_read_file (grub_fshelp_node_t node,
> > + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
> > + unsigned offset, unsigned length),
> > + int pos, grub_size_t len, char *buf)
> > +{
> > + return grub_fshelp_read_file (node->data->disk, node, read_hook,
> > + pos, len, buf, grub_nilfs2_read_block,
> > + grub_le_to_cpu64(node->inode.i_size),
> > + LOG2_NILFS2_BLOCK_SIZE (node->data));
> > +
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
> > + grub_uint64_t cpno,
> > + struct grub_nilfs2_checkpoint *cpp)
> > +{
> > + grub_uint64_t blockno;
> > + grub_uint32_t offset;
> > + grub_uint64_t pptr;
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + /* assume sizeof(struct grub_nilfs2_cpfile_header) <
> > + sizeof(struct grub_nilfs2_checkpoint)
> > + */
> > + blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
> > + sizeof(struct grub_nilfs2_checkpoint) , &offset);
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return GRUB_ERR_BAD_FS;
> > + }
> > +
> > + return grub_disk_read (disk, pptr * nilfs2_block_count,
> > + offset * sizeof(struct grub_nilfs2_checkpoint),
> > + sizeof (struct grub_nilfs2_checkpoint),
> > + cpp);
> > +}
> > +
> > +static inline grub_err_t
> > +grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_checkpoint *cpp)
> > +{
> > + return grub_nilfs2_read_checkpoint(data,
> > + grub_le_to_cpu64(data->sblock.s_last_cno),
> > + cpp);
> > +}
> > +
> > +/* Read the inode INO for the file described by DATA into INODE. */
> > +static grub_err_t
> > +grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
> > + grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
> > +{
> > + grub_uint64_t blockno;
> > + unsigned int offset;
> > + grub_uint64_t pptr;
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + blockno = grub_nilfs2_palloc_entry_offset(data, ino,
> > + sizeof(struct grub_nilfs2_inode));
> > +
> > + grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
> > + NILFS2_BLOCK_SIZE(data), &offset);
> > + pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return GRUB_ERR_BAD_FS;
> > + }
> > +
> > + return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> > + sizeof (struct grub_nilfs2_inode),
> > + inodep);
> > +}
> > +
> > +static int grub_nilfs2_valid_sb(struct grub_nilfs2_super_block *sbp)
> > +{
> > + if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
> > + return 0;
> > +
> > + if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
> > + return 0;
> > +
> > + return 1;
> > +}
> > +
> > +static struct grub_nilfs2_data *
> > +grub_nilfs2_mount (grub_disk_t disk)
> > +{
> > + struct grub_nilfs2_data *data;
> > + struct grub_nilfs2_segment_summary ss;
> > + struct grub_nilfs2_checkpoint last_checkpoint;
> > + grub_uint64_t last_pseg;
> > + grub_uint32_t nblocks;
> > + unsigned int nilfs2_block_count;
> > +
> > + data = grub_malloc (sizeof (struct grub_nilfs2_data));
> > + if (!data)
> > + return 0;
> > +
> > + /* Read the superblock. */
> > + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
> > + &data->sblock);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + /* Make sure this is an nilfs2 filesystem. */
> > + if (!grub_nilfs2_valid_sb(&data->sblock))
> > + {
> > + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> > + goto fail;
> > + }
> > +
> > + nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + /* Read the last segment summary */
> > + last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
> > + grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
> > + sizeof (struct grub_nilfs2_segment_summary), &ss);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + /* Read the super root block */
> > + nblocks = grub_le_to_cpu32(ss.ss_nblocks);
> > + grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
> > + sizeof (struct grub_nilfs2_super_root), &data->sroot);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + data->disk = disk;
> > +
> > + grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
> > + sizeof(struct grub_nilfs2_inode));
> > +
> > + data->diropen.data = data;
> > + data->diropen.ino = 2;
> > + data->diropen.inode_read = 1;
> > + data->inode = &data->diropen.inode;
> > +
> > + grub_nilfs2_read_inode(data, 2, data->inode);
> > +
> > + return data;
> > +
> > + fail:
> > + if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
> > + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> > +
> > + grub_free (data);
> > + return 0;
> > +}
> > +
> > +static char *
> > +grub_nilfs2_read_symlink (grub_fshelp_node_t node)
> > +{
> > + char *symlink;
> > + struct grub_fshelp_node *diro = node;
> > +
> > + if (! diro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
> > + if (! symlink)
> > + return 0;
> > +
> > + grub_nilfs2_read_file (diro, 0, 0,
> > + grub_le_to_cpu64 (diro->inode.i_size),
> > + symlink);
> > + if (grub_errno)
> > + {
> > + grub_free (symlink);
> > + return 0;
> > + }
> > +
> > + symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
> > + return symlink;
> > +}
> > +
> > +static int
> > +grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
> > + int NESTED_FUNC_ATTR
> > + (*hook) (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node))
> > +{
> > + unsigned int fpos = 0;
> > + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
> > +
> > + if (! diro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + /* Iterate files. */
> > + while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
> > + {
> > + struct grub_nilfs2_dir_entry dirent;
> > +
> > + grub_nilfs2_read_file (diro, 0, fpos,
> > + sizeof (struct grub_nilfs2_dir_entry),
> > + (char *) &dirent);
> > + if (grub_errno)
> > + return 0;
> > +
> > + if (dirent.rec_len == 0)
> > + return 0;
> > +
> > + if (dirent.name_len != 0)
> > + {
> > + char filename[dirent.name_len + 1];
> > + struct grub_fshelp_node *fdiro;
> > + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
> > +
> > + grub_nilfs2_read_file (diro, 0,
> > + fpos + sizeof (struct grub_nilfs2_dir_entry),
> > + dirent.name_len, filename);
> > + if (grub_errno)
> > + return 0;
> > +
> > + fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> > + if (! fdiro)
> > + return 0;
> > +
> > + fdiro->data = diro->data;
> > + fdiro->ino = grub_le_to_cpu64 (dirent.inode);
> > +
> > + filename[dirent.name_len] = '\0';
> > +
> > + if (dirent.file_type != NILFS_FT_UNKNOWN)
> > + {
> > + fdiro->inode_read = 0;
> > +
> > + if (dirent.file_type == NILFS_FT_DIR)
> > + type = GRUB_FSHELP_DIR;
> > + else if (dirent.file_type == NILFS_FT_SYMLINK)
> > + type = GRUB_FSHELP_SYMLINK;
> > + else if (dirent.file_type == NILFS_FT_REG_FILE)
> > + type = GRUB_FSHELP_REG;
> > + }
> > + else
> > + {
> > + /* The filetype can not be read from the dirent, read
> > + the inode to get more information. */
> > + grub_nilfs2_read_inode (diro->data,
> > + grub_le_to_cpu64 (dirent.inode),
> > + &fdiro->inode);
> > + if (grub_errno)
> > + {
> > + grub_free (fdiro);
> > + return 0;
> > + }
> > +
> > + fdiro->inode_read = 1;
> > +
> > + if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
> > + type = GRUB_FSHELP_DIR;
> > + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
> > + type = GRUB_FSHELP_SYMLINK;
> > + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
> > + type = GRUB_FSHELP_REG;
> > + }
> > +
> > + if (hook (filename, type, fdiro))
> > + return 1;
> > + }
> > +
> > + fpos += grub_le_to_cpu16 (dirent.rec_len);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/* Open a file named NAME and initialize FILE. */
> > +static grub_err_t
> > +grub_nilfs2_open (struct grub_file *file, const char *name)
> > +{
> > + struct grub_nilfs2_data *data = NULL;
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (file->device->disk);
> > + if (! data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> > + grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + if (! fdiro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
> > + if (grub_errno)
> > + goto fail;
> > + }
> > +
> > + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
> > + grub_free (fdiro);
> > +
> > + file->size = grub_le_to_cpu64 (data->inode->i_size);
> > + file->data = data;
> > + file->offset = 0;
> > +
> > + return 0;
> > +
> > + fail:
> > + if (fdiro != &data->diropen)
> > + grub_free (fdiro);
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_close (grub_file_t file)
> > +{
> > + grub_free (file->data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +/* Read LEN bytes data from FILE into BUF. */
> > +static grub_ssize_t
> > +grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
> > +{
> > + struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
> > +
> > + return grub_nilfs2_read_file (&data->diropen, file->read_hook,
> > + file->offset, len, buf);
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_dir (grub_device_t device, const char *path,
> > + int (*hook) (const char *filename,
> > + const struct grub_dirhook_info *info))
> > +{
> > + struct grub_nilfs2_data *data = 0;
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + auto int NESTED_FUNC_ATTR iterate (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node);
> > +
> > + int NESTED_FUNC_ATTR iterate (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node)
> > + {
> > + struct grub_dirhook_info info;
> > + grub_memset (&info, 0, sizeof (info));
> > + if (! node->inode_read)
> > + {
> > + grub_nilfs2_read_inode (data, node->ino, &node->inode);
> > + if (!grub_errno)
> > + node->inode_read = 1;
> > + grub_errno = GRUB_ERR_NONE;
> > + }
> > + if (node->inode_read)
> > + {
> > + info.mtimeset = 1;
> > + info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
> > + }
> > +
> > + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
> > + grub_free (node);
> > + return hook (filename, &info);
> > + }
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (device->disk);
> > + if (! data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> > + grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + grub_nilfs2_iterate_dir (fdiro, iterate);
> > +
> > + fail:
> > + if (fdiro != &data->diropen)
> > + grub_free (fdiro);
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_label (grub_device_t device, char **label)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (data)
> > + *label = grub_strndup (data->sblock.s_volume_name, 14);
> > + else
> > + *label = NULL;
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_uuid (grub_device_t device, char **uuid)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (data)
> > + {
> > + *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
> > + data->sblock.s_uuid[0], data->sblock.s_uuid[1],
> > + data->sblock.s_uuid[2], data->sblock.s_uuid[3],
> > + data->sblock.s_uuid[4], data->sblock.s_uuid[5],
> > + data->sblock.s_uuid[6], data->sblock.s_uuid[7],
> > + data->sblock.s_uuid[8], data->sblock.s_uuid[9],
> > + data->sblock.s_uuid[10], data->sblock.s_uuid[11],
> > + data->sblock.s_uuid[12], data->sblock.s_uuid[13],
> > + data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
> > + }
> > + else
> > + *uuid = NULL;
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +/* Get mtime. */
> > +static grub_err_t
> > +grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (!data)
> > + *tm = 0;
> > + else
> > + *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +
> > +\f
> > +static struct grub_fs grub_nilfs2_fs=
> > + {
> > + .name = "nilfs2",
> > + .dir = grub_nilfs2_dir,
> > + .open = grub_nilfs2_open,
> > + .read = grub_nilfs2_read,
> > + .close = grub_nilfs2_close,
> > + .label = grub_nilfs2_label,
> > + .uuid = grub_nilfs2_uuid,
> > + .mtime = grub_nilfs2_mtime,
> > +#ifdef GRUB_UTIL
> > + .reserved_first_sector = 1,
> > +#endif
> > + .next = 0
> > + };
> > +
> > +GRUB_MOD_INIT(nilfs2)
> > +{
> > + grub_fs_register (&grub_nilfs2_fs);
> > + my_mod = mod;
> > +}
> > +
> > +GRUB_MOD_FINI(nilfs2)
> > +{
> > + grub_fs_unregister (&grub_nilfs2_fs);
> > +}
> >
> > === modified file 'include/grub/misc.h'
> > --- include/grub/misc.h 2010-02-03 00:24:07 +0000
> > +++ include/grub/misc.h 2010-02-18 13:57:40 +0000
> > @@ -45,6 +45,7 @@
> > ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
> > #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
> > #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
> > +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> >
> > #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
> > /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
> >
> >
> >
> > ------------------------------------------------------------------------
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > http://lists.gnu.org/mailman/listinfo/grub-devel
> >
>
>
> --
> Regards
> Vladimir 'φ-coder/phcoder' Serbinenko
>
>
> [1.2 OpenPGP digital signature <application/pgp-signature (7bit)>]
>
> [2 <text/plain; us-ascii (7bit)>]
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Jiro SEKIBA <jir@unicus.jp>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] a new filesystem module for nilfs2
2010-02-18 9:13 [PATCHv2] a new filesystem " Jiro SEKIBA
2010-02-20 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-02-24 10:57 ` Vladimir 'φ-coder/phcoder' Serbinenko
1 sibling, 0 replies; 10+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-02-24 10:57 UTC (permalink / raw)
To: The development of GNU GRUB
[-- Attachment #1: Type: text/plain, Size: 38951 bytes --]
Jiro SEKIBA wrote:
> Hi,
>
> This is a revised patch to support nilfs2, a log file system.
>
Could you please answer the e-mail I send you about copyright?
> I've checked it the first one on qemu-system-ppc and found a few bugs.
> Thank you for encouraging me to test it on qemu-system-ppc!
>
> This is a bug fixed version. I've checked it by grub-fstest on PPC
> and by installing and booting it to boot sector of nilfs2 partition on i386.
>
> Here are the change logs from the first one
>
> - big endian bug fixes
> * add "packed" attribute for all structs
> * swap physical block number bytes
> - separate pkglib_MODULES addition
> - leftover removal
> - moved DIV_ROUND_UP macro into misc.h
> - add separate function to check super block
> * add major version checking
>
> ToDo:
> 1. CRC check for superblock to ensure the partition is a nilfs2 partition
> 2. CRC check latest log block to ensure valid log
> 3. search the latest log in case unclean unmount happened
>
> thanks
>
> regards
>
> ------------------------------------------------------------------------
>
> === modified file 'conf/any-emu.rmk'
> --- conf/any-emu.rmk 2010-02-03 00:24:07 +0000
> +++ conf/any-emu.rmk 2010-02-18 13:57:40 +0000
> @@ -38,7 +38,7 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> fs/befs.c fs/befs_be.c fs/tar.c \
> \
>
> === modified file 'conf/common.rmk'
> --- conf/common.rmk 2010-02-06 14:37:23 +0000
> +++ conf/common.rmk 2010-02-18 13:57:40 +0000
> @@ -28,9 +28,9 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
> kern/fs.c kern/env.c fs/fshelp.c \
> @@ -65,7 +65,7 @@
> \
> fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
> fs/befs_be.c fs/tar.c \
> \
> @@ -270,6 +270,12 @@
> minix_mod_CFLAGS = $(COMMON_CFLAGS)
> minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
>
> +# For nilfs2.mod.
> +pkglib_MODULES += nilfs2.mod
> +nilfs2_mod_SOURCES = fs/nilfs2.c
> +nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
> +nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> # For hfs.mod.
> hfs_mod_SOURCES = fs/hfs.c
> hfs_mod_CFLAGS = $(COMMON_CFLAGS)
>
> === modified file 'conf/i386-pc.rmk'
> --- conf/i386-pc.rmk 2010-02-03 00:24:07 +0000
> +++ conf/i386-pc.rmk 2010-02-18 13:57:40 +0000
> @@ -100,9 +100,9 @@
> \
> fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/msdos.c partmap/gpt.c \
> \
>
> === modified file 'conf/sparc64-ieee1275.rmk'
> --- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
> +++ conf/sparc64-ieee1275.rmk 2010-02-18 13:57:40 +0000
> @@ -74,9 +74,9 @@
> \
> fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> - fs/befs.c fs/befs_be.c fs/tar.c \
> + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> \
> partmap/amiga.c partmap/apple.c partmap/msdos.c \
> partmap/sun.c partmap/acorn.c \
>
> === added file 'fs/nilfs2.c'
> --- fs/nilfs2.c 1970-01-01 00:00:00 +0000
> +++ fs/nilfs2.c 2010-02-18 13:57:40 +0000
> @@ -0,0 +1,1126 @@
> +/*
> + * nilfs2.c - New Implementation of Log filesystem
> + * Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
> + */
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
> + *
> + * GRUB is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +
> +/* Filetype information as used in inodes. */
> +#define FILETYPE_INO_MASK 0170000
> +#define FILETYPE_INO_REG 0100000
> +#define FILETYPE_INO_DIRECTORY 0040000
> +#define FILETYPE_INO_SYMLINK 0120000
> +
> +#include <grub/err.h>
> +#include <grub/file.h>
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/disk.h>
> +#include <grub/dl.h>
> +#include <grub/types.h>
> +#include <grub/fshelp.h>
> +
> +/** nilfs_fs.h **/
> +#define NILFS_INODE_BMAP_SIZE 7
> +
> +#define NILFS_SUPORT_REV 2
> +#define NILFS_MINOR_REV 0
> +
> +/* Magic value used to identify an nilfs2 filesystem. */
> +#define NILFS2_SUPER_MAGIC 0x3434
> +/* nilfs btree node flag */
> +#define NILFS_BTREE_NODE_ROOT 0x01
> +
> +/* nilfs btree node level */
> +#define NILFS_BTREE_LEVEL_DATA 0
> +#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
> +#define NILFS_BTREE_LEVEL_MAX 14
> +
> +struct grub_nilfs2_inode
> +{
> + grub_uint64_t i_blocks;
> + grub_uint64_t i_size;
> + grub_uint64_t i_ctime;
> + grub_uint64_t i_mtime;
> + grub_uint32_t i_ctime_nsec;
> + grub_uint32_t i_mtime_nsec;
> + grub_uint32_t i_uid;
> + grub_uint32_t i_gid;
> + grub_uint16_t i_mode;
> + grub_uint16_t i_links_count;
> + grub_uint32_t i_flags;
> + grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
> +#define i_device_code i_bmap[0]
> + grub_uint64_t i_xattr;
> + grub_uint32_t i_generation;
> + grub_uint32_t i_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_super_root
> +{
> + grub_uint32_t sr_sum;
> + grub_uint16_t sr_bytes;
> + grub_uint16_t sr_flags;
> + grub_uint64_t sr_nongc_ctime;
> + struct grub_nilfs2_inode sr_dat;
> + struct grub_nilfs2_inode sr_cpfile;
> + struct grub_nilfs2_inode sr_sufile;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_super_block
> +{
> + grub_uint32_t s_rev_level;
> + grub_uint16_t s_minor_rev_level;
> + grub_uint16_t s_magic;
> + grub_uint16_t s_bytes;
> + grub_uint16_t s_flags;
> + grub_uint32_t s_crc_seed;
> + grub_uint32_t s_sum;
> + grub_uint32_t s_log_block_size;
> + grub_uint64_t s_nsegments;
> + grub_uint64_t s_dev_size;
> + grub_uint64_t s_first_data_block;
> + grub_uint32_t s_blocks_per_segment;
> + grub_uint32_t s_r_segments_percentage;
> + grub_uint64_t s_last_cno;
> + grub_uint64_t s_last_pseg;
> + grub_uint64_t s_last_seq;
> + grub_uint64_t s_free_blocks_count;
> + grub_uint64_t s_ctime;
> + grub_uint64_t s_mtime;
> + grub_uint64_t s_wtime;
> + grub_uint16_t s_mnt_count;
> + grub_uint16_t s_max_mnt_count;
> + grub_uint16_t s_state;
> + grub_uint16_t s_errors;
> + grub_uint64_t s_lastcheck;
> + grub_uint32_t s_checkinterval;
> + grub_uint32_t s_creator_os;
> + grub_uint16_t s_def_resuid;
> + grub_uint16_t s_def_resgid;
> + grub_uint32_t s_first_ino;
> + grub_uint16_t s_inode_size;
> + grub_uint16_t s_dat_entry_size;
> + grub_uint16_t s_checkpoint_size;
> + grub_uint16_t s_segment_usage_size;
> + grub_uint8_t s_uuid[16];
> + char s_volume_name[16];
> + char s_last_mounted[64];
> + grub_uint32_t s_c_interval;
> + grub_uint32_t s_c_block_max;
> + grub_uint32_t s_reserved[192];
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_dir_entry
> +{
> + grub_uint64_t inode;
> + grub_uint16_t rec_len;
> + grub_uint8_t name_len;
> + grub_uint8_t file_type;
> +#if 0 /* followed by file name */
> + char name[NILFS_NAME_LEN];
> + char pad;
> +#endif
> +} __attribute__ ((packed));
> +
> +enum
> +{
> + NILFS_FT_UNKNOWN,
> + NILFS_FT_REG_FILE,
> + NILFS_FT_DIR,
> + NILFS_FT_CHRDEV,
> + NILFS_FT_BLKDEV,
> + NILFS_FT_FIFO,
> + NILFS_FT_SOCK,
> + NILFS_FT_SYMLINK,
> + NILFS_FT_MAX
> +};
> +
> +struct grub_nilfs2_finfo
> +{
> + grub_uint64_t fi_ino;
> + grub_uint64_t fi_cno;
> + grub_uint32_t fi_nblocks;
> + grub_uint32_t fi_ndatablk;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_binfo_v
> +{
> + grub_uint64_t bi_vblocknr;
> + grub_uint64_t bi_blkoff;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_binfo_dat
> +{
> + grub_uint64_t bi_blkoff;
> + grub_uint8_t bi_level;
> + grub_uint8_t bi_pad[7];
> +} __attribute__ ((packed));
> +
> +union grub_nilfs2_binfo
> +{
> + struct grub_nilfs2_binfo_v bi_v;
> + struct grub_nilfs2_binfo_dat bi_dat;
> +};
> +
> +struct grub_nilfs2_segment_summary
> +{
> + grub_uint32_t ss_datasum;
> + grub_uint32_t ss_sumsum;
> + grub_uint32_t ss_magic;
> + grub_uint16_t ss_bytes;
> + grub_uint16_t ss_flags;
> + grub_uint64_t ss_seq;
> + grub_uint64_t ss_create;
> + grub_uint64_t ss_next;
> + grub_uint32_t ss_nblocks;
> + grub_uint32_t ss_nfinfo;
> + grub_uint32_t ss_sumbytes;
> + grub_uint32_t ss_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_btree_node
> +{
> + grub_uint8_t bn_flags;
> + grub_uint8_t bn_level;
> + grub_uint16_t bn_nchildren;
> + grub_uint32_t bn_pad;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_palloc_group_desc
> +{
> + grub_uint32_t pg_nfrees;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_dat_entry
> +{
> + grub_uint64_t de_blocknr;
> + grub_uint64_t de_start;
> + grub_uint64_t de_end;
> + grub_uint64_t de_rsv;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_snapshot_list {
> + grub_uint64_t ssl_next;
> + grub_uint64_t ssl_prev;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_cpfile_header
> +{
> + grub_uint64_t ch_ncheckpoints;
> + grub_uint64_t ch_nsnapshots;
> + struct grub_nilfs2_snapshot_list ch_snapshot_list;
> +} __attribute__ ((packed));
> +
> +struct grub_nilfs2_checkpoint
> +{
> + grub_uint32_t cp_flags;
> + grub_uint32_t cp_checkpoints_count;
> + struct grub_nilfs2_snapshot_list cp_snapshot_list;
> + grub_uint64_t cp_cno;
> + grub_uint64_t cp_create;
> + grub_uint64_t cp_nblk_inc;
> + grub_uint64_t cp_inodes_count;
> + grub_uint64_t cp_blocks_count;
> + struct grub_nilfs2_inode cp_ifile_inode;
> +} __attribute__ ((packed));
> +
> +/** nilfs_fs.h **/
> +
> +/** bmap.h **/
> +#define NILFS_BMAP_LARGE 0x1
> +#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
> +/** bmap.h **/
> +
> +/** btree.h **/
> +/* nilfs extra padding for nonroot btree node */
> +#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
> +#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
> +#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
> + ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
> + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
> +/** btree.h **/
> +
> +
> +struct grub_fshelp_node
> +{
> + struct grub_nilfs2_data *data;
> + struct grub_nilfs2_inode inode;
> + grub_uint64_t ino;
> + int inode_read;
> +};
> +
> +struct grub_nilfs2_data
> +{
> + struct grub_nilfs2_super_block sblock;
> + struct grub_nilfs2_super_root sroot;
> + struct grub_nilfs2_inode ifile;
> + grub_disk_t disk;
> + struct grub_nilfs2_inode *inode;
> + struct grub_fshelp_node diropen;
> +};
> +
> +/* Log2 size of nilfs2 block in 512 blocks. */
> +#define LOG2_NILFS2_BLOCK_SIZE(data) \
> + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
> +
> +/* Log2 size of nilfs2 block in bytes. */
> +#define LOG2_BLOCK_SIZE(data) \
> + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
> +
> +/* The size of an nilfs2 block in bytes. */
> +#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
> +
> +static grub_uint64_t
> +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
> +static grub_dl_t my_mod;
> +
> +\f
> +
> +static inline unsigned long
> +grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
> +{
> + return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
> + grub_uint64_t nr, grub_uint32_t *offset)
> +{
> + return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
> +{
> + return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return NILFS2_BLOCK_SIZE(data) / entry_size;
> +}
> +
> +
> +static inline grub_uint32_t
> +grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
> + grub_nilfs2_entries_per_block(data,entry_size)) + 1;
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
> + unsigned long entry_size)
> +{
> + return grub_nilfs2_palloc_groups_per_desc_block(data) *
> + grub_nilfs2_blocks_per_group(data,entry_size) + 1;
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
> + unsigned long group,
> + unsigned long entry_size)
> +{
> + grub_uint32_t desc_block =
> + group / grub_nilfs2_palloc_groups_per_desc_block(data);
> + return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
> + unsigned long group,
> + unsigned long entry_size)
> +{
> + unsigned long desc_offset = group %
> + grub_nilfs2_palloc_groups_per_desc_block(data);
> +
> + return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
> + desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
> +}
> +
> +static inline grub_uint32_t
> +grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
> + grub_uint64_t nr, unsigned long entry_size)
> +{
> + unsigned long group;
> + grub_uint32_t group_offset;
> +
> + group = grub_nilfs2_palloc_group(data, nr, &group_offset);
> +
> + return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
> + group_offset / grub_nilfs2_entries_per_block(data, entry_size);
> +
> +}
> +
> +static inline struct grub_nilfs2_btree_node *
> +grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
> +{
> + return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
> +}
> +
> +static inline int
> +grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
> +{
> + return node->bn_level;
> +}
> +
> +static inline grub_uint64_t *
> +grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
> +{
> + return (grub_uint64_t *)((char *)(node + 1) +
> + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
> + 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
> +{
> + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
> +}
> +
> +static inline int
> +grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
> + grub_uint64_t key, int *indexp)
> +{
> + grub_uint64_t nkey;
> + int index, low, high, s;
> +
> + low = 0;
> + high = grub_le_to_cpu16(node->bn_nchildren) - 1;
> + index = 0;
> + s = 0;
> + while(low <= high)
> + {
> + index = (low+high)/2;
> + nkey = grub_nilfs2_btree_node_get_key(node, index);
> + if(nkey == key)
> + {
> + s = 0;
> + goto out;
> + }
> + else if (nkey < key)
> + {
> + low = index +1;
> + s = -1;
> + }
> + else
> + {
> + high = index - 1;
> + s = 1;
> + }
> + }
> +
> + if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
> + {
> + if (s > 0 && index > 0)
> + index--;
> + }
> + else if (s < 0)
> + index++;
> +
> + out:
> + *indexp = index;
> + return s == 0;
> +}
> +
> +static inline int
> +grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node)
> +{
> + int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
> + sizeof(struct grub_nilfs2_btree_node) -
> + NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
> + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
> +
> + return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
> +}
> +
> +static inline grub_uint64_t *
> +grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node)
> +{
> + return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
> + grub_nilfs2_btree_node_nchildren_max(data,node));
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_btree_node *node, int index)
> +{
> + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
> +}
> +
> +static inline int
> +grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
> + grub_uint64_t ptr, void *block)
> +{
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
> + NILFS2_BLOCK_SIZE(data), block);
> +}
> +
> +static grub_uint64_t
> +grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_inode *inode,
> + grub_uint64_t key, int need_translate)
> +{
> + struct grub_nilfs2_btree_node *node;
> + unsigned char block[NILFS2_BLOCK_SIZE(data)];
> + grub_uint64_t ptr;
> + int level, found, index;
> +
> + node = grub_nilfs2_btree_get_root(inode);
> + level = grub_nilfs2_btree_get_level(node);
> +
> + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> +
> + for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
> + {
> + grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
> + if(grub_errno)
> + {
> + grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
> + return -1;
> + }
> + node = (struct grub_nilfs2_btree_node *)block;
> +
> + if(node->bn_level != level)
> + {
> + grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
> + return -1;
> + }
> +
> + if(!found)
> + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> + else
> + index = 0;
> +
> + if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
> + {
> + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> + }
> + else
> + {
> + grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
> + return -1;
> + }
> + }
> +
> + if(!found)
> + return -1;
> +
> + return ptr;
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
> +{
> + return grub_le_to_cpu64(inode->i_bmap[1+key]);
> +}
> +
> +static inline grub_uint64_t
> +grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_inode *inode,
> + grub_uint64_t key, int need_translate)
> +{
> + struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
> + if(root->bn_flags & NILFS_BMAP_LARGE)
> + return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
> + else
> + {
> + grub_uint64_t ptr;
> + ptr = grub_nilfs2_direct_lookup(inode, key);
> + if(need_translate)
> + ptr = grub_nilfs2_dat_translate(data, ptr);
> + return ptr;
> + }
> +}
> +
> +static grub_uint64_t
> +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
> +{
> + struct grub_nilfs2_dat_entry entry;
> + grub_disk_t disk = data->disk;
> + grub_uint64_t pptr;
> + grub_uint32_t blockno, offset;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + blockno = grub_nilfs2_palloc_entry_offset(data, key,
> + sizeof(struct grub_nilfs2_dat_entry));
> +
> + grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
> + NILFS2_BLOCK_SIZE(data), &offset);
> +
> + pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return -1;
> + }
> +
> + grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> + sizeof (struct grub_nilfs2_dat_entry), &entry);
> +
> + return grub_le_to_cpu64(entry.de_blocknr);
> +}
> +
> +
> +static grub_disk_addr_t
> +grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
> +{
> + struct grub_nilfs2_data *data = node->data;
> + struct grub_nilfs2_inode *inode = &node->inode;
> + grub_uint64_t pptr = -1;
> +
> + pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return -1;
> + }
> +
> + return pptr;
> +}
> +
> +/* Read LEN bytes from the file described by DATA starting with byte
> + POS. Return the amount of read bytes in READ. */
> +static grub_ssize_t
> +grub_nilfs2_read_file (grub_fshelp_node_t node,
> + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
> + unsigned offset, unsigned length),
> + int pos, grub_size_t len, char *buf)
> +{
> + return grub_fshelp_read_file (node->data->disk, node, read_hook,
> + pos, len, buf, grub_nilfs2_read_block,
> + grub_le_to_cpu64(node->inode.i_size),
> + LOG2_NILFS2_BLOCK_SIZE (node->data));
> +
> +}
> +
> +static grub_err_t
> +grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
> + grub_uint64_t cpno,
> + struct grub_nilfs2_checkpoint *cpp)
> +{
> + grub_uint64_t blockno;
> + grub_uint32_t offset;
> + grub_uint64_t pptr;
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + /* assume sizeof(struct grub_nilfs2_cpfile_header) <
> + sizeof(struct grub_nilfs2_checkpoint)
> + */
> + blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
> + sizeof(struct grub_nilfs2_checkpoint) , &offset);
> +
> + pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return GRUB_ERR_BAD_FS;
> + }
> +
> + return grub_disk_read (disk, pptr * nilfs2_block_count,
> + offset * sizeof(struct grub_nilfs2_checkpoint),
> + sizeof (struct grub_nilfs2_checkpoint),
> + cpp);
> +}
> +
> +static inline grub_err_t
> +grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
> + struct grub_nilfs2_checkpoint *cpp)
> +{
> + return grub_nilfs2_read_checkpoint(data,
> + grub_le_to_cpu64(data->sblock.s_last_cno),
> + cpp);
> +}
> +
> +/* Read the inode INO for the file described by DATA into INODE. */
> +static grub_err_t
> +grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
> + grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
> +{
> + grub_uint64_t blockno;
> + unsigned int offset;
> + grub_uint64_t pptr;
> + grub_disk_t disk = data->disk;
> + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + blockno = grub_nilfs2_palloc_entry_offset(data, ino,
> + sizeof(struct grub_nilfs2_inode));
> +
> + grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
> + NILFS2_BLOCK_SIZE(data), &offset);
> + pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
> + if(pptr == (grub_uint64_t)-1) {
> + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> + return GRUB_ERR_BAD_FS;
> + }
> +
> + return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> + sizeof (struct grub_nilfs2_inode),
> + inodep);
> +}
> +
> +static int grub_nilfs2_valid_sb(struct grub_nilfs2_super_block *sbp)
> +{
> + if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
> + return 0;
> +
> + if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
> + return 0;
> +
> + return 1;
> +}
> +
> +static struct grub_nilfs2_data *
> +grub_nilfs2_mount (grub_disk_t disk)
> +{
> + struct grub_nilfs2_data *data;
> + struct grub_nilfs2_segment_summary ss;
> + struct grub_nilfs2_checkpoint last_checkpoint;
> + grub_uint64_t last_pseg;
> + grub_uint32_t nblocks;
> + unsigned int nilfs2_block_count;
> +
> + data = grub_malloc (sizeof (struct grub_nilfs2_data));
> + if (!data)
> + return 0;
> +
> + /* Read the superblock. */
> + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
> + &data->sblock);
> + if (grub_errno)
> + goto fail;
> +
> + /* Make sure this is an nilfs2 filesystem. */
> + if (!grub_nilfs2_valid_sb(&data->sblock))
> + {
> + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> + goto fail;
> + }
> +
> + nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> +
> + /* Read the last segment summary */
> + last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
> + grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
> + sizeof (struct grub_nilfs2_segment_summary), &ss);
> +
> + if (grub_errno)
> + goto fail;
> +
> + /* Read the super root block */
> + nblocks = grub_le_to_cpu32(ss.ss_nblocks);
> + grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
> + sizeof (struct grub_nilfs2_super_root), &data->sroot);
> +
> + if (grub_errno)
> + goto fail;
> +
> + data->disk = disk;
> +
> + grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
> +
> + if (grub_errno)
> + goto fail;
> +
> + grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
> + sizeof(struct grub_nilfs2_inode));
> +
> + data->diropen.data = data;
> + data->diropen.ino = 2;
> + data->diropen.inode_read = 1;
> + data->inode = &data->diropen.inode;
> +
> + grub_nilfs2_read_inode(data, 2, data->inode);
> +
> + return data;
> +
> + fail:
> + if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
> + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> +
> + grub_free (data);
> + return 0;
> +}
> +
> +static char *
> +grub_nilfs2_read_symlink (grub_fshelp_node_t node)
> +{
> + char *symlink;
> + struct grub_fshelp_node *diro = node;
> +
> + if (! diro->inode_read)
> + {
> + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> + if (grub_errno)
> + return 0;
> + }
> +
> + symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
> + if (! symlink)
> + return 0;
> +
> + grub_nilfs2_read_file (diro, 0, 0,
> + grub_le_to_cpu64 (diro->inode.i_size),
> + symlink);
> + if (grub_errno)
> + {
> + grub_free (symlink);
> + return 0;
> + }
> +
> + symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
> + return symlink;
> +}
> +
> +static int
> +grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
> + int NESTED_FUNC_ATTR
> + (*hook) (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node))
> +{
> + unsigned int fpos = 0;
> + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
> +
> + if (! diro->inode_read)
> + {
> + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> + if (grub_errno)
> + return 0;
> + }
> +
> + /* Iterate files. */
> + while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
> + {
> + struct grub_nilfs2_dir_entry dirent;
> +
> + grub_nilfs2_read_file (diro, 0, fpos,
> + sizeof (struct grub_nilfs2_dir_entry),
> + (char *) &dirent);
> + if (grub_errno)
> + return 0;
> +
> + if (dirent.rec_len == 0)
> + return 0;
> +
> + if (dirent.name_len != 0)
> + {
> + char filename[dirent.name_len + 1];
> + struct grub_fshelp_node *fdiro;
> + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
> +
> + grub_nilfs2_read_file (diro, 0,
> + fpos + sizeof (struct grub_nilfs2_dir_entry),
> + dirent.name_len, filename);
> + if (grub_errno)
> + return 0;
> +
> + fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> + if (! fdiro)
> + return 0;
> +
> + fdiro->data = diro->data;
> + fdiro->ino = grub_le_to_cpu64 (dirent.inode);
> +
> + filename[dirent.name_len] = '\0';
> +
> + if (dirent.file_type != NILFS_FT_UNKNOWN)
> + {
> + fdiro->inode_read = 0;
> +
> + if (dirent.file_type == NILFS_FT_DIR)
> + type = GRUB_FSHELP_DIR;
> + else if (dirent.file_type == NILFS_FT_SYMLINK)
> + type = GRUB_FSHELP_SYMLINK;
> + else if (dirent.file_type == NILFS_FT_REG_FILE)
> + type = GRUB_FSHELP_REG;
> + }
> + else
> + {
> + /* The filetype can not be read from the dirent, read
> + the inode to get more information. */
> + grub_nilfs2_read_inode (diro->data,
> + grub_le_to_cpu64 (dirent.inode),
> + &fdiro->inode);
> + if (grub_errno)
> + {
> + grub_free (fdiro);
> + return 0;
> + }
> +
> + fdiro->inode_read = 1;
> +
> + if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
> + type = GRUB_FSHELP_DIR;
> + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
> + type = GRUB_FSHELP_SYMLINK;
> + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> + & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
> + type = GRUB_FSHELP_REG;
> + }
> +
> + if (hook (filename, type, fdiro))
> + return 1;
> + }
> +
> + fpos += grub_le_to_cpu16 (dirent.rec_len);
> + }
> +
> + return 0;
> +}
> +
> +/* Open a file named NAME and initialize FILE. */
> +static grub_err_t
> +grub_nilfs2_open (struct grub_file *file, const char *name)
> +{
> + struct grub_nilfs2_data *data = NULL;
> + struct grub_fshelp_node *fdiro = 0;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (file->device->disk);
> + if (! data)
> + goto fail;
> +
> + grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> + grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
> + if (grub_errno)
> + goto fail;
> +
> + if (! fdiro->inode_read)
> + {
> + grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
> + if (grub_errno)
> + goto fail;
> + }
> +
> + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
> + grub_free (fdiro);
> +
> + file->size = grub_le_to_cpu64 (data->inode->i_size);
> + file->data = data;
> + file->offset = 0;
> +
> + return 0;
> +
> + fail:
> + if (fdiro != &data->diropen)
> + grub_free (fdiro);
> + grub_free (data);
> +
> + grub_dl_unref (my_mod);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_close (grub_file_t file)
> +{
> + grub_free (file->data);
> +
> + grub_dl_unref (my_mod);
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +/* Read LEN bytes data from FILE into BUF. */
> +static grub_ssize_t
> +grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
> +{
> + struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
> +
> + return grub_nilfs2_read_file (&data->diropen, file->read_hook,
> + file->offset, len, buf);
> +}
> +
> +static grub_err_t
> +grub_nilfs2_dir (grub_device_t device, const char *path,
> + int (*hook) (const char *filename,
> + const struct grub_dirhook_info *info))
> +{
> + struct grub_nilfs2_data *data = 0;
> + struct grub_fshelp_node *fdiro = 0;
> +
> + auto int NESTED_FUNC_ATTR iterate (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node);
> +
> + int NESTED_FUNC_ATTR iterate (const char *filename,
> + enum grub_fshelp_filetype filetype,
> + grub_fshelp_node_t node)
> + {
> + struct grub_dirhook_info info;
> + grub_memset (&info, 0, sizeof (info));
> + if (! node->inode_read)
> + {
> + grub_nilfs2_read_inode (data, node->ino, &node->inode);
> + if (!grub_errno)
> + node->inode_read = 1;
> + grub_errno = GRUB_ERR_NONE;
> + }
> + if (node->inode_read)
> + {
> + info.mtimeset = 1;
> + info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
> + }
> +
> + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
> + grub_free (node);
> + return hook (filename, &info);
> + }
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (device->disk);
> + if (! data)
> + goto fail;
> +
> + grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> + grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
> + if (grub_errno)
> + goto fail;
> +
> + grub_nilfs2_iterate_dir (fdiro, iterate);
> +
> + fail:
> + if (fdiro != &data->diropen)
> + grub_free (fdiro);
> + grub_free (data);
> +
> + grub_dl_unref (my_mod);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_label (grub_device_t device, char **label)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (data)
> + *label = grub_strndup (data->sblock.s_volume_name, 14);
> + else
> + *label = NULL;
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_nilfs2_uuid (grub_device_t device, char **uuid)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (data)
> + {
> + *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
> + data->sblock.s_uuid[0], data->sblock.s_uuid[1],
> + data->sblock.s_uuid[2], data->sblock.s_uuid[3],
> + data->sblock.s_uuid[4], data->sblock.s_uuid[5],
> + data->sblock.s_uuid[6], data->sblock.s_uuid[7],
> + data->sblock.s_uuid[8], data->sblock.s_uuid[9],
> + data->sblock.s_uuid[10], data->sblock.s_uuid[11],
> + data->sblock.s_uuid[12], data->sblock.s_uuid[13],
> + data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
> + }
> + else
> + *uuid = NULL;
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +/* Get mtime. */
> +static grub_err_t
> +grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
> +{
> + struct grub_nilfs2_data *data;
> + grub_disk_t disk = device->disk;
> +
> + grub_dl_ref (my_mod);
> +
> + data = grub_nilfs2_mount (disk);
> + if (!data)
> + *tm = 0;
> + else
> + *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
> +
> + grub_dl_unref (my_mod);
> +
> + grub_free (data);
> +
> + return grub_errno;
> +}
> +
> +
> +\f
> +static struct grub_fs grub_nilfs2_fs=
> + {
> + .name = "nilfs2",
> + .dir = grub_nilfs2_dir,
> + .open = grub_nilfs2_open,
> + .read = grub_nilfs2_read,
> + .close = grub_nilfs2_close,
> + .label = grub_nilfs2_label,
> + .uuid = grub_nilfs2_uuid,
> + .mtime = grub_nilfs2_mtime,
> +#ifdef GRUB_UTIL
> + .reserved_first_sector = 1,
> +#endif
> + .next = 0
> + };
> +
> +GRUB_MOD_INIT(nilfs2)
> +{
> + grub_fs_register (&grub_nilfs2_fs);
> + my_mod = mod;
> +}
> +
> +GRUB_MOD_FINI(nilfs2)
> +{
> + grub_fs_unregister (&grub_nilfs2_fs);
> +}
>
> === modified file 'include/grub/misc.h'
> --- include/grub/misc.h 2010-02-03 00:24:07 +0000
> +++ include/grub/misc.h 2010-02-18 13:57:40 +0000
> @@ -45,6 +45,7 @@
> ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
> #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
> #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
> +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
>
> #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
> /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
>
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCHv2] a new filesystem module for nilfs2
2010-02-06 5:02 ` Jiro SEKIBA
@ 2010-02-24 11:25 ` Jiro SEKIBA
0 siblings, 0 replies; 10+ messages in thread
From: Jiro SEKIBA @ 2010-02-24 11:25 UTC (permalink / raw)
To: The development of GNU GRUB
Hi,
At Wed, 24 Feb 2010 11:57:57 +0100,
Vladimir 'φ-coder/phcoder' Serbinenko wrote:
>
> [1 <multipart/signed (7bit)>]
> [1.1 <text/plain; UTF-8 (quoted-printable)>]
> Jiro SEKIBA wrote:
> > Hi,
> >
> > This is a revised patch to support nilfs2, a log file system.
> >
> Could you please answer the e-mail I send you about copyright?
Was the following mail insufficient? Or you just missed it?
http://osdir.com/ml/grub-devel-gnu/2010-02/msg00045.html
Just in case I cite the mail. And I think it'll be gpl3.
At Sat, 06 Feb 2010 14:02:52 +0900,
Jiro SEKIBA wrote:
Message-ID: <87tytv6jnn.wl%jir@sekiba.com>
...snip..
> Thank you for the attention. That is very important issue,
> sorry that I didn't describe it explicitly.
>
> The code is based on fs/ext2.c in grub-1.97.1 release.
> I reused the file/directory iteration code from it.
>
> Other nilfs2 specific code is writte by me from scratch.
> I referred the original implementation, but have never borrowed
> any code from it.
>
> So I'm thinking the license would be gpl3, for it is derived
> from gpl3(fs/ext2.c) code.
>
> thanks,
>
> regards,
thanks,
regards,
> > I've checked it the first one on qemu-system-ppc and found a few bugs.
> > Thank you for encouraging me to test it on qemu-system-ppc!
> >
> > This is a bug fixed version. I've checked it by grub-fstest on PPC
> > and by installing and booting it to boot sector of nilfs2 partition on i386.
> >
> > Here are the change logs from the first one
> >
> > - big endian bug fixes
> > * add "packed" attribute for all structs
> > * swap physical block number bytes
> > - separate pkglib_MODULES addition
> > - leftover removal
> > - moved DIV_ROUND_UP macro into misc.h
> > - add separate function to check super block
> > * add major version checking
> >
> > ToDo:
> > 1. CRC check for superblock to ensure the partition is a nilfs2 partition
> > 2. CRC check latest log block to ensure valid log
> > 3. search the latest log in case unclean unmount happened
> >
> > thanks
> >
> > regards
> >
> > ------------------------------------------------------------------------
> >
> > === modified file 'conf/any-emu.rmk'
> > --- conf/any-emu.rmk 2010-02-03 00:24:07 +0000
> > +++ conf/any-emu.rmk 2010-02-18 13:57:40 +0000
> > @@ -38,7 +38,7 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> >
> > === modified file 'conf/common.rmk'
> > --- conf/common.rmk 2010-02-06 14:37:23 +0000
> > +++ conf/common.rmk 2010-02-18 13:57:40 +0000
> > @@ -28,9 +28,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/msdos.c partmap/apple.c partmap/sun.c partmap/gpt.c\
> > kern/fs.c kern/env.c fs/fshelp.c \
> > @@ -65,7 +65,7 @@
> > \
> > fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c fs/befs.c \
> > fs/befs_be.c fs/tar.c \
> > \
> > @@ -270,6 +270,12 @@
> > minix_mod_CFLAGS = $(COMMON_CFLAGS)
> > minix_mod_LDFLAGS = $(COMMON_LDFLAGS)
> >
> > +# For nilfs2.mod.
> > +pkglib_MODULES += nilfs2.mod
> > +nilfs2_mod_SOURCES = fs/nilfs2.c
> > +nilfs2_mod_CFLAGS = $(COMMON_CFLAGS)
> > +nilfs2_mod_LDFLAGS = $(COMMON_LDFLAGS)
> > +
> > # For hfs.mod.
> > hfs_mod_SOURCES = fs/hfs.c
> > hfs_mod_CFLAGS = $(COMMON_CFLAGS)
> >
> > === modified file 'conf/i386-pc.rmk'
> > --- conf/i386-pc.rmk 2010-02-03 00:24:07 +0000
> > +++ conf/i386-pc.rmk 2010-02-18 13:57:40 +0000
> > @@ -100,9 +100,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/msdos.c partmap/gpt.c \
> > \
> >
> > === modified file 'conf/sparc64-ieee1275.rmk'
> > --- conf/sparc64-ieee1275.rmk 2010-01-20 20:31:39 +0000
> > +++ conf/sparc64-ieee1275.rmk 2010-02-18 13:57:40 +0000
> > @@ -74,9 +74,9 @@
> > \
> > fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
> > fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
> > - fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \
> > - fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c fs/afs_be.c \
> > - fs/befs.c fs/befs_be.c fs/tar.c \
> > + fs/nilfs2.c fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c \
> > + fs/sfs.c fs/ufs.c fs/ufs2.c fs/xfs.c fs/afs.c \
> > + fs/afs_be.c fs/befs.c fs/befs_be.c fs/tar.c \
> > \
> > partmap/amiga.c partmap/apple.c partmap/msdos.c \
> > partmap/sun.c partmap/acorn.c \
> >
> > === added file 'fs/nilfs2.c'
> > --- fs/nilfs2.c 1970-01-01 00:00:00 +0000
> > +++ fs/nilfs2.c 2010-02-18 13:57:40 +0000
> > @@ -0,0 +1,1126 @@
> > +/*
> > + * nilfs2.c - New Implementation of Log filesystem
> > + * Copyright (C) 2010 Jiro SEKIBA <jir@unicus.jp>
> > + */
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2003,2004,2005,2007,2008 Free Software Foundation, Inc.
> > + *
> > + * GRUB is free software: you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation, either version 3 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * GRUB is distributed in the hope that 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +
> > +/* Filetype information as used in inodes. */
> > +#define FILETYPE_INO_MASK 0170000
> > +#define FILETYPE_INO_REG 0100000
> > +#define FILETYPE_INO_DIRECTORY 0040000
> > +#define FILETYPE_INO_SYMLINK 0120000
> > +
> > +#include <grub/err.h>
> > +#include <grub/file.h>
> > +#include <grub/mm.h>
> > +#include <grub/misc.h>
> > +#include <grub/disk.h>
> > +#include <grub/dl.h>
> > +#include <grub/types.h>
> > +#include <grub/fshelp.h>
> > +
> > +/** nilfs_fs.h **/
> > +#define NILFS_INODE_BMAP_SIZE 7
> > +
> > +#define NILFS_SUPORT_REV 2
> > +#define NILFS_MINOR_REV 0
> > +
> > +/* Magic value used to identify an nilfs2 filesystem. */
> > +#define NILFS2_SUPER_MAGIC 0x3434
> > +/* nilfs btree node flag */
> > +#define NILFS_BTREE_NODE_ROOT 0x01
> > +
> > +/* nilfs btree node level */
> > +#define NILFS_BTREE_LEVEL_DATA 0
> > +#define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
> > +#define NILFS_BTREE_LEVEL_MAX 14
> > +
> > +struct grub_nilfs2_inode
> > +{
> > + grub_uint64_t i_blocks;
> > + grub_uint64_t i_size;
> > + grub_uint64_t i_ctime;
> > + grub_uint64_t i_mtime;
> > + grub_uint32_t i_ctime_nsec;
> > + grub_uint32_t i_mtime_nsec;
> > + grub_uint32_t i_uid;
> > + grub_uint32_t i_gid;
> > + grub_uint16_t i_mode;
> > + grub_uint16_t i_links_count;
> > + grub_uint32_t i_flags;
> > + grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
> > +#define i_device_code i_bmap[0]
> > + grub_uint64_t i_xattr;
> > + grub_uint32_t i_generation;
> > + grub_uint32_t i_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_super_root
> > +{
> > + grub_uint32_t sr_sum;
> > + grub_uint16_t sr_bytes;
> > + grub_uint16_t sr_flags;
> > + grub_uint64_t sr_nongc_ctime;
> > + struct grub_nilfs2_inode sr_dat;
> > + struct grub_nilfs2_inode sr_cpfile;
> > + struct grub_nilfs2_inode sr_sufile;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_super_block
> > +{
> > + grub_uint32_t s_rev_level;
> > + grub_uint16_t s_minor_rev_level;
> > + grub_uint16_t s_magic;
> > + grub_uint16_t s_bytes;
> > + grub_uint16_t s_flags;
> > + grub_uint32_t s_crc_seed;
> > + grub_uint32_t s_sum;
> > + grub_uint32_t s_log_block_size;
> > + grub_uint64_t s_nsegments;
> > + grub_uint64_t s_dev_size;
> > + grub_uint64_t s_first_data_block;
> > + grub_uint32_t s_blocks_per_segment;
> > + grub_uint32_t s_r_segments_percentage;
> > + grub_uint64_t s_last_cno;
> > + grub_uint64_t s_last_pseg;
> > + grub_uint64_t s_last_seq;
> > + grub_uint64_t s_free_blocks_count;
> > + grub_uint64_t s_ctime;
> > + grub_uint64_t s_mtime;
> > + grub_uint64_t s_wtime;
> > + grub_uint16_t s_mnt_count;
> > + grub_uint16_t s_max_mnt_count;
> > + grub_uint16_t s_state;
> > + grub_uint16_t s_errors;
> > + grub_uint64_t s_lastcheck;
> > + grub_uint32_t s_checkinterval;
> > + grub_uint32_t s_creator_os;
> > + grub_uint16_t s_def_resuid;
> > + grub_uint16_t s_def_resgid;
> > + grub_uint32_t s_first_ino;
> > + grub_uint16_t s_inode_size;
> > + grub_uint16_t s_dat_entry_size;
> > + grub_uint16_t s_checkpoint_size;
> > + grub_uint16_t s_segment_usage_size;
> > + grub_uint8_t s_uuid[16];
> > + char s_volume_name[16];
> > + char s_last_mounted[64];
> > + grub_uint32_t s_c_interval;
> > + grub_uint32_t s_c_block_max;
> > + grub_uint32_t s_reserved[192];
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_dir_entry
> > +{
> > + grub_uint64_t inode;
> > + grub_uint16_t rec_len;
> > + grub_uint8_t name_len;
> > + grub_uint8_t file_type;
> > +#if 0 /* followed by file name */
> > + char name[NILFS_NAME_LEN];
> > + char pad;
> > +#endif
> > +} __attribute__ ((packed));
> > +
> > +enum
> > +{
> > + NILFS_FT_UNKNOWN,
> > + NILFS_FT_REG_FILE,
> > + NILFS_FT_DIR,
> > + NILFS_FT_CHRDEV,
> > + NILFS_FT_BLKDEV,
> > + NILFS_FT_FIFO,
> > + NILFS_FT_SOCK,
> > + NILFS_FT_SYMLINK,
> > + NILFS_FT_MAX
> > +};
> > +
> > +struct grub_nilfs2_finfo
> > +{
> > + grub_uint64_t fi_ino;
> > + grub_uint64_t fi_cno;
> > + grub_uint32_t fi_nblocks;
> > + grub_uint32_t fi_ndatablk;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_binfo_v
> > +{
> > + grub_uint64_t bi_vblocknr;
> > + grub_uint64_t bi_blkoff;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_binfo_dat
> > +{
> > + grub_uint64_t bi_blkoff;
> > + grub_uint8_t bi_level;
> > + grub_uint8_t bi_pad[7];
> > +} __attribute__ ((packed));
> > +
> > +union grub_nilfs2_binfo
> > +{
> > + struct grub_nilfs2_binfo_v bi_v;
> > + struct grub_nilfs2_binfo_dat bi_dat;
> > +};
> > +
> > +struct grub_nilfs2_segment_summary
> > +{
> > + grub_uint32_t ss_datasum;
> > + grub_uint32_t ss_sumsum;
> > + grub_uint32_t ss_magic;
> > + grub_uint16_t ss_bytes;
> > + grub_uint16_t ss_flags;
> > + grub_uint64_t ss_seq;
> > + grub_uint64_t ss_create;
> > + grub_uint64_t ss_next;
> > + grub_uint32_t ss_nblocks;
> > + grub_uint32_t ss_nfinfo;
> > + grub_uint32_t ss_sumbytes;
> > + grub_uint32_t ss_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_btree_node
> > +{
> > + grub_uint8_t bn_flags;
> > + grub_uint8_t bn_level;
> > + grub_uint16_t bn_nchildren;
> > + grub_uint32_t bn_pad;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_palloc_group_desc
> > +{
> > + grub_uint32_t pg_nfrees;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_dat_entry
> > +{
> > + grub_uint64_t de_blocknr;
> > + grub_uint64_t de_start;
> > + grub_uint64_t de_end;
> > + grub_uint64_t de_rsv;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_snapshot_list {
> > + grub_uint64_t ssl_next;
> > + grub_uint64_t ssl_prev;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_cpfile_header
> > +{
> > + grub_uint64_t ch_ncheckpoints;
> > + grub_uint64_t ch_nsnapshots;
> > + struct grub_nilfs2_snapshot_list ch_snapshot_list;
> > +} __attribute__ ((packed));
> > +
> > +struct grub_nilfs2_checkpoint
> > +{
> > + grub_uint32_t cp_flags;
> > + grub_uint32_t cp_checkpoints_count;
> > + struct grub_nilfs2_snapshot_list cp_snapshot_list;
> > + grub_uint64_t cp_cno;
> > + grub_uint64_t cp_create;
> > + grub_uint64_t cp_nblk_inc;
> > + grub_uint64_t cp_inodes_count;
> > + grub_uint64_t cp_blocks_count;
> > + struct grub_nilfs2_inode cp_ifile_inode;
> > +} __attribute__ ((packed));
> > +
> > +/** nilfs_fs.h **/
> > +
> > +/** bmap.h **/
> > +#define NILFS_BMAP_LARGE 0x1
> > +#define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
> > +/** bmap.h **/
> > +
> > +/** btree.h **/
> > +/* nilfs extra padding for nonroot btree node */
> > +#define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
> > +#define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
> > +#define NILFS_BTREE_ROOT_NCHILDREN_MAX \
> > + ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
> > + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
> > +/** btree.h **/
> > +
> > +
> > +struct grub_fshelp_node
> > +{
> > + struct grub_nilfs2_data *data;
> > + struct grub_nilfs2_inode inode;
> > + grub_uint64_t ino;
> > + int inode_read;
> > +};
> > +
> > +struct grub_nilfs2_data
> > +{
> > + struct grub_nilfs2_super_block sblock;
> > + struct grub_nilfs2_super_root sroot;
> > + struct grub_nilfs2_inode ifile;
> > + grub_disk_t disk;
> > + struct grub_nilfs2_inode *inode;
> > + struct grub_fshelp_node diropen;
> > +};
> > +
> > +/* Log2 size of nilfs2 block in 512 blocks. */
> > +#define LOG2_NILFS2_BLOCK_SIZE(data) \
> > + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
> > +
> > +/* Log2 size of nilfs2 block in bytes. */
> > +#define LOG2_BLOCK_SIZE(data) \
> > + (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
> > +
> > +/* The size of an nilfs2 block in bytes. */
> > +#define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key);
> > +static grub_dl_t my_mod;
> > +
> > +\f
> > +
> > +static inline unsigned long
> > +grub_nilfs2_palloc_entries_per_group(struct grub_nilfs2_data *data)
> > +{
> > + return 1UL << (LOG2_BLOCK_SIZE(data) + 3);
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_palloc_group(struct grub_nilfs2_data *data,
> > + grub_uint64_t nr, grub_uint32_t *offset)
> > +{
> > + return grub_divmod64(nr, grub_nilfs2_palloc_entries_per_group(data), offset);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_groups_per_desc_block(struct grub_nilfs2_data *data)
> > +{
> > + return NILFS2_BLOCK_SIZE(data) / sizeof(struct grub_nilfs2_palloc_group_desc);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_entries_per_block(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return NILFS2_BLOCK_SIZE(data) / entry_size;
> > +}
> > +
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_blocks_per_group(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return DIV_ROUND_UP(grub_nilfs2_palloc_entries_per_group(data),
> > + grub_nilfs2_entries_per_block(data,entry_size)) + 1;
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_blocks_per_desc_block(struct grub_nilfs2_data *data,
> > + unsigned long entry_size)
> > +{
> > + return grub_nilfs2_palloc_groups_per_desc_block(data) *
> > + grub_nilfs2_blocks_per_group(data,entry_size) + 1;
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_desc_block_offset(struct grub_nilfs2_data *data,
> > + unsigned long group,
> > + unsigned long entry_size)
> > +{
> > + grub_uint32_t desc_block =
> > + group / grub_nilfs2_palloc_groups_per_desc_block(data);
> > + return desc_block * grub_nilfs2_blocks_per_desc_block(data,entry_size);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_bitmap_block_offset(struct grub_nilfs2_data *data,
> > + unsigned long group,
> > + unsigned long entry_size)
> > +{
> > + unsigned long desc_offset = group %
> > + grub_nilfs2_palloc_groups_per_desc_block(data);
> > +
> > + return grub_nilfs2_palloc_desc_block_offset(data, group, entry_size) + 1 +
> > + desc_offset * grub_nilfs2_blocks_per_group(data, entry_size);
> > +}
> > +
> > +static inline grub_uint32_t
> > +grub_nilfs2_palloc_entry_offset(struct grub_nilfs2_data *data,
> > + grub_uint64_t nr, unsigned long entry_size)
> > +{
> > + unsigned long group;
> > + grub_uint32_t group_offset;
> > +
> > + group = grub_nilfs2_palloc_group(data, nr, &group_offset);
> > +
> > + return grub_nilfs2_palloc_bitmap_block_offset(data, group,entry_size) + 1 +
> > + group_offset / grub_nilfs2_entries_per_block(data, entry_size);
> > +
> > +}
> > +
> > +static inline struct grub_nilfs2_btree_node *
> > +grub_nilfs2_btree_get_root(struct grub_nilfs2_inode *inode)
> > +{
> > + return (struct grub_nilfs2_btree_node *)&inode->i_bmap[0];
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_get_level(struct grub_nilfs2_btree_node *node)
> > +{
> > + return node->bn_level;
> > +}
> > +
> > +static inline grub_uint64_t *
> > +grub_nilfs2_btree_node_dkeys(struct grub_nilfs2_btree_node *node)
> > +{
> > + return (grub_uint64_t *)((char *)(node + 1) +
> > + ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
> > + 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_btree_node_get_key(struct grub_nilfs2_btree_node *node, int index)
> > +{
> > + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dkeys(node) + index));
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_node_lookup(struct grub_nilfs2_btree_node *node,
> > + grub_uint64_t key, int *indexp)
> > +{
> > + grub_uint64_t nkey;
> > + int index, low, high, s;
> > +
> > + low = 0;
> > + high = grub_le_to_cpu16(node->bn_nchildren) - 1;
> > + index = 0;
> > + s = 0;
> > + while(low <= high)
> > + {
> > + index = (low+high)/2;
> > + nkey = grub_nilfs2_btree_node_get_key(node, index);
> > + if(nkey == key)
> > + {
> > + s = 0;
> > + goto out;
> > + }
> > + else if (nkey < key)
> > + {
> > + low = index +1;
> > + s = -1;
> > + }
> > + else
> > + {
> > + high = index - 1;
> > + s = 1;
> > + }
> > + }
> > +
> > + if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
> > + {
> > + if (s > 0 && index > 0)
> > + index--;
> > + }
> > + else if (s < 0)
> > + index++;
> > +
> > + out:
> > + *indexp = index;
> > + return s == 0;
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_node_nchildren_max(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node)
> > +{
> > + int node_children_max = (( NILFS2_BLOCK_SIZE(data) -
> > + sizeof(struct grub_nilfs2_btree_node) -
> > + NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) /
> > + (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) );
> > +
> > + return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
> > +}
> > +
> > +static inline grub_uint64_t *
> > +grub_nilfs2_btree_node_dptrs(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node)
> > +{
> > + return (grub_uint64_t *)(grub_nilfs2_btree_node_dkeys(node) +
> > + grub_nilfs2_btree_node_nchildren_max(data,node));
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_btree_node_get_ptr(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_btree_node *node, int index)
> > +{
> > + return grub_le_to_cpu64(*(grub_nilfs2_btree_node_dptrs(data,node) + index));
> > +}
> > +
> > +static inline int
> > +grub_nilfs2_btree_get_nonroot_node(struct grub_nilfs2_data *data,
> > + grub_uint64_t ptr, void *block)
> > +{
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
> > + NILFS2_BLOCK_SIZE(data), block);
> > +}
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_btree_lookup(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_inode *inode,
> > + grub_uint64_t key, int need_translate)
> > +{
> > + struct grub_nilfs2_btree_node *node;
> > + unsigned char block[NILFS2_BLOCK_SIZE(data)];
> > + grub_uint64_t ptr;
> > + int level, found, index;
> > +
> > + node = grub_nilfs2_btree_get_root(inode);
> > + level = grub_nilfs2_btree_get_level(node);
> > +
> > + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> > + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > +
> > + for(level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
> > + {
> > + grub_nilfs2_btree_get_nonroot_node(data, ptr, block);
> > + if(grub_errno)
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"disk read error\n");
> > + return -1;
> > + }
> > + node = (struct grub_nilfs2_btree_node *)block;
> > +
> > + if(node->bn_level != level)
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"btree level mismatch\n");
> > + return -1;
> > + }
> > +
> > + if(!found)
> > + found = grub_nilfs2_btree_node_lookup(node, key, &index);
> > + else
> > + index = 0;
> > +
> > + if(index < grub_nilfs2_btree_node_nchildren_max(data, node))
> > + {
> > + ptr = grub_nilfs2_btree_node_get_ptr(data, node, index);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > + }
> > + else
> > + {
> > + grub_error(GRUB_ERR_BAD_FS,"btree corruption\n");
> > + return -1;
> > + }
> > + }
> > +
> > + if(!found)
> > + return -1;
> > +
> > + return ptr;
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_direct_lookup(struct grub_nilfs2_inode *inode, grub_uint64_t key)
> > +{
> > + return grub_le_to_cpu64(inode->i_bmap[1+key]);
> > +}
> > +
> > +static inline grub_uint64_t
> > +grub_nilfs2_bmap_lookup(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_inode *inode,
> > + grub_uint64_t key, int need_translate)
> > +{
> > + struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root(inode);
> > + if(root->bn_flags & NILFS_BMAP_LARGE)
> > + return grub_nilfs2_btree_lookup(data, inode, key, need_translate);
> > + else
> > + {
> > + grub_uint64_t ptr;
> > + ptr = grub_nilfs2_direct_lookup(inode, key);
> > + if(need_translate)
> > + ptr = grub_nilfs2_dat_translate(data, ptr);
> > + return ptr;
> > + }
> > +}
> > +
> > +static grub_uint64_t
> > +grub_nilfs2_dat_translate(struct grub_nilfs2_data *data, grub_uint64_t key)
> > +{
> > + struct grub_nilfs2_dat_entry entry;
> > + grub_disk_t disk = data->disk;
> > + grub_uint64_t pptr;
> > + grub_uint32_t blockno, offset;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + blockno = grub_nilfs2_palloc_entry_offset(data, key,
> > + sizeof(struct grub_nilfs2_dat_entry));
> > +
> > + grub_divmod64(key * sizeof(struct grub_nilfs2_dat_entry),
> > + NILFS2_BLOCK_SIZE(data), &offset);
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data, &data->sroot.sr_dat, blockno, 0);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return -1;
> > + }
> > +
> > + grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> > + sizeof (struct grub_nilfs2_dat_entry), &entry);
> > +
> > + return grub_le_to_cpu64(entry.de_blocknr);
> > +}
> > +
> > +
> > +static grub_disk_addr_t
> > +grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
> > +{
> > + struct grub_nilfs2_data *data = node->data;
> > + struct grub_nilfs2_inode *inode = &node->inode;
> > + grub_uint64_t pptr = -1;
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data, inode, fileblock, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return -1;
> > + }
> > +
> > + return pptr;
> > +}
> > +
> > +/* Read LEN bytes from the file described by DATA starting with byte
> > + POS. Return the amount of read bytes in READ. */
> > +static grub_ssize_t
> > +grub_nilfs2_read_file (grub_fshelp_node_t node,
> > + void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
> > + unsigned offset, unsigned length),
> > + int pos, grub_size_t len, char *buf)
> > +{
> > + return grub_fshelp_read_file (node->data->disk, node, read_hook,
> > + pos, len, buf, grub_nilfs2_read_block,
> > + grub_le_to_cpu64(node->inode.i_size),
> > + LOG2_NILFS2_BLOCK_SIZE (node->data));
> > +
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_read_checkpoint(struct grub_nilfs2_data *data,
> > + grub_uint64_t cpno,
> > + struct grub_nilfs2_checkpoint *cpp)
> > +{
> > + grub_uint64_t blockno;
> > + grub_uint32_t offset;
> > + grub_uint64_t pptr;
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + /* assume sizeof(struct grub_nilfs2_cpfile_header) <
> > + sizeof(struct grub_nilfs2_checkpoint)
> > + */
> > + blockno = grub_divmod64(cpno, NILFS2_BLOCK_SIZE(data) /
> > + sizeof(struct grub_nilfs2_checkpoint) , &offset);
> > +
> > + pptr = grub_nilfs2_bmap_lookup(data ,&data->sroot.sr_cpfile, blockno, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return GRUB_ERR_BAD_FS;
> > + }
> > +
> > + return grub_disk_read (disk, pptr * nilfs2_block_count,
> > + offset * sizeof(struct grub_nilfs2_checkpoint),
> > + sizeof (struct grub_nilfs2_checkpoint),
> > + cpp);
> > +}
> > +
> > +static inline grub_err_t
> > +grub_nilfs2_read_last_checkpoint(struct grub_nilfs2_data *data,
> > + struct grub_nilfs2_checkpoint *cpp)
> > +{
> > + return grub_nilfs2_read_checkpoint(data,
> > + grub_le_to_cpu64(data->sblock.s_last_cno),
> > + cpp);
> > +}
> > +
> > +/* Read the inode INO for the file described by DATA into INODE. */
> > +static grub_err_t
> > +grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
> > + grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
> > +{
> > + grub_uint64_t blockno;
> > + unsigned int offset;
> > + grub_uint64_t pptr;
> > + grub_disk_t disk = data->disk;
> > + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + blockno = grub_nilfs2_palloc_entry_offset(data, ino,
> > + sizeof(struct grub_nilfs2_inode));
> > +
> > + grub_divmod64(sizeof(struct grub_nilfs2_inode) * ino,
> > + NILFS2_BLOCK_SIZE(data), &offset);
> > + pptr = grub_nilfs2_bmap_lookup(data ,&data->ifile, blockno, 1);
> > + if(pptr == (grub_uint64_t)-1) {
> > + grub_error(GRUB_ERR_BAD_FS,"btree lookup failure");
> > + return GRUB_ERR_BAD_FS;
> > + }
> > +
> > + return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
> > + sizeof (struct grub_nilfs2_inode),
> > + inodep);
> > +}
> > +
> > +static int grub_nilfs2_valid_sb(struct grub_nilfs2_super_block *sbp)
> > +{
> > + if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
> > + return 0;
> > +
> > + if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
> > + return 0;
> > +
> > + return 1;
> > +}
> > +
> > +static struct grub_nilfs2_data *
> > +grub_nilfs2_mount (grub_disk_t disk)
> > +{
> > + struct grub_nilfs2_data *data;
> > + struct grub_nilfs2_segment_summary ss;
> > + struct grub_nilfs2_checkpoint last_checkpoint;
> > + grub_uint64_t last_pseg;
> > + grub_uint32_t nblocks;
> > + unsigned int nilfs2_block_count;
> > +
> > + data = grub_malloc (sizeof (struct grub_nilfs2_data));
> > + if (!data)
> > + return 0;
> > +
> > + /* Read the superblock. */
> > + grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
> > + &data->sblock);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + /* Make sure this is an nilfs2 filesystem. */
> > + if (!grub_nilfs2_valid_sb(&data->sblock))
> > + {
> > + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> > + goto fail;
> > + }
> > +
> > + nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE(data));
> > +
> > + /* Read the last segment summary */
> > + last_pseg = grub_le_to_cpu64(data->sblock.s_last_pseg);
> > + grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
> > + sizeof (struct grub_nilfs2_segment_summary), &ss);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + /* Read the super root block */
> > + nblocks = grub_le_to_cpu32(ss.ss_nblocks);
> > + grub_disk_read (disk, (last_pseg + (nblocks -1)) * nilfs2_block_count, 0,
> > + sizeof (struct grub_nilfs2_super_root), &data->sroot);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + data->disk = disk;
> > +
> > + grub_nilfs2_read_last_checkpoint(data, &last_checkpoint);
> > +
> > + if (grub_errno)
> > + goto fail;
> > +
> > + grub_memcpy(&data->ifile, &last_checkpoint.cp_ifile_inode,
> > + sizeof(struct grub_nilfs2_inode));
> > +
> > + data->diropen.data = data;
> > + data->diropen.ino = 2;
> > + data->diropen.inode_read = 1;
> > + data->inode = &data->diropen.inode;
> > +
> > + grub_nilfs2_read_inode(data, 2, data->inode);
> > +
> > + return data;
> > +
> > + fail:
> > + if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
> > + grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
> > +
> > + grub_free (data);
> > + return 0;
> > +}
> > +
> > +static char *
> > +grub_nilfs2_read_symlink (grub_fshelp_node_t node)
> > +{
> > + char *symlink;
> > + struct grub_fshelp_node *diro = node;
> > +
> > + if (! diro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
> > + if (! symlink)
> > + return 0;
> > +
> > + grub_nilfs2_read_file (diro, 0, 0,
> > + grub_le_to_cpu64 (diro->inode.i_size),
> > + symlink);
> > + if (grub_errno)
> > + {
> > + grub_free (symlink);
> > + return 0;
> > + }
> > +
> > + symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
> > + return symlink;
> > +}
> > +
> > +static int
> > +grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
> > + int NESTED_FUNC_ATTR
> > + (*hook) (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node))
> > +{
> > + unsigned int fpos = 0;
> > + struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
> > +
> > + if (! diro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
> > + if (grub_errno)
> > + return 0;
> > + }
> > +
> > + /* Iterate files. */
> > + while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
> > + {
> > + struct grub_nilfs2_dir_entry dirent;
> > +
> > + grub_nilfs2_read_file (diro, 0, fpos,
> > + sizeof (struct grub_nilfs2_dir_entry),
> > + (char *) &dirent);
> > + if (grub_errno)
> > + return 0;
> > +
> > + if (dirent.rec_len == 0)
> > + return 0;
> > +
> > + if (dirent.name_len != 0)
> > + {
> > + char filename[dirent.name_len + 1];
> > + struct grub_fshelp_node *fdiro;
> > + enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
> > +
> > + grub_nilfs2_read_file (diro, 0,
> > + fpos + sizeof (struct grub_nilfs2_dir_entry),
> > + dirent.name_len, filename);
> > + if (grub_errno)
> > + return 0;
> > +
> > + fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
> > + if (! fdiro)
> > + return 0;
> > +
> > + fdiro->data = diro->data;
> > + fdiro->ino = grub_le_to_cpu64 (dirent.inode);
> > +
> > + filename[dirent.name_len] = '\0';
> > +
> > + if (dirent.file_type != NILFS_FT_UNKNOWN)
> > + {
> > + fdiro->inode_read = 0;
> > +
> > + if (dirent.file_type == NILFS_FT_DIR)
> > + type = GRUB_FSHELP_DIR;
> > + else if (dirent.file_type == NILFS_FT_SYMLINK)
> > + type = GRUB_FSHELP_SYMLINK;
> > + else if (dirent.file_type == NILFS_FT_REG_FILE)
> > + type = GRUB_FSHELP_REG;
> > + }
> > + else
> > + {
> > + /* The filetype can not be read from the dirent, read
> > + the inode to get more information. */
> > + grub_nilfs2_read_inode (diro->data,
> > + grub_le_to_cpu64 (dirent.inode),
> > + &fdiro->inode);
> > + if (grub_errno)
> > + {
> > + grub_free (fdiro);
> > + return 0;
> > + }
> > +
> > + fdiro->inode_read = 1;
> > +
> > + if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
> > + type = GRUB_FSHELP_DIR;
> > + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
> > + type = GRUB_FSHELP_SYMLINK;
> > + else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
> > + & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
> > + type = GRUB_FSHELP_REG;
> > + }
> > +
> > + if (hook (filename, type, fdiro))
> > + return 1;
> > + }
> > +
> > + fpos += grub_le_to_cpu16 (dirent.rec_len);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/* Open a file named NAME and initialize FILE. */
> > +static grub_err_t
> > +grub_nilfs2_open (struct grub_file *file, const char *name)
> > +{
> > + struct grub_nilfs2_data *data = NULL;
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (file->device->disk);
> > + if (! data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (name, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> > + grub_nilfs2_read_symlink, GRUB_FSHELP_REG);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + if (! fdiro->inode_read)
> > + {
> > + grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
> > + if (grub_errno)
> > + goto fail;
> > + }
> > +
> > + grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
> > + grub_free (fdiro);
> > +
> > + file->size = grub_le_to_cpu64 (data->inode->i_size);
> > + file->data = data;
> > + file->offset = 0;
> > +
> > + return 0;
> > +
> > + fail:
> > + if (fdiro != &data->diropen)
> > + grub_free (fdiro);
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_close (grub_file_t file)
> > +{
> > + grub_free (file->data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +/* Read LEN bytes data from FILE into BUF. */
> > +static grub_ssize_t
> > +grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
> > +{
> > + struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
> > +
> > + return grub_nilfs2_read_file (&data->diropen, file->read_hook,
> > + file->offset, len, buf);
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_dir (grub_device_t device, const char *path,
> > + int (*hook) (const char *filename,
> > + const struct grub_dirhook_info *info))
> > +{
> > + struct grub_nilfs2_data *data = 0;
> > + struct grub_fshelp_node *fdiro = 0;
> > +
> > + auto int NESTED_FUNC_ATTR iterate (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node);
> > +
> > + int NESTED_FUNC_ATTR iterate (const char *filename,
> > + enum grub_fshelp_filetype filetype,
> > + grub_fshelp_node_t node)
> > + {
> > + struct grub_dirhook_info info;
> > + grub_memset (&info, 0, sizeof (info));
> > + if (! node->inode_read)
> > + {
> > + grub_nilfs2_read_inode (data, node->ino, &node->inode);
> > + if (!grub_errno)
> > + node->inode_read = 1;
> > + grub_errno = GRUB_ERR_NONE;
> > + }
> > + if (node->inode_read)
> > + {
> > + info.mtimeset = 1;
> > + info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
> > + }
> > +
> > + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
> > + grub_free (node);
> > + return hook (filename, &info);
> > + }
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (device->disk);
> > + if (! data)
> > + goto fail;
> > +
> > + grub_fshelp_find_file (path, &data->diropen, &fdiro, grub_nilfs2_iterate_dir,
> > + grub_nilfs2_read_symlink, GRUB_FSHELP_DIR);
> > + if (grub_errno)
> > + goto fail;
> > +
> > + grub_nilfs2_iterate_dir (fdiro, iterate);
> > +
> > + fail:
> > + if (fdiro != &data->diropen)
> > + grub_free (fdiro);
> > + grub_free (data);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_label (grub_device_t device, char **label)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (data)
> > + *label = grub_strndup (data->sblock.s_volume_name, 14);
> > + else
> > + *label = NULL;
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +static grub_err_t
> > +grub_nilfs2_uuid (grub_device_t device, char **uuid)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (data)
> > + {
> > + *uuid = grub_xasprintf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
> > + data->sblock.s_uuid[0], data->sblock.s_uuid[1],
> > + data->sblock.s_uuid[2], data->sblock.s_uuid[3],
> > + data->sblock.s_uuid[4], data->sblock.s_uuid[5],
> > + data->sblock.s_uuid[6], data->sblock.s_uuid[7],
> > + data->sblock.s_uuid[8], data->sblock.s_uuid[9],
> > + data->sblock.s_uuid[10], data->sblock.s_uuid[11],
> > + data->sblock.s_uuid[12], data->sblock.s_uuid[13],
> > + data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
> > + }
> > + else
> > + *uuid = NULL;
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +/* Get mtime. */
> > +static grub_err_t
> > +grub_nilfs2_mtime (grub_device_t device, grub_int32_t *tm)
> > +{
> > + struct grub_nilfs2_data *data;
> > + grub_disk_t disk = device->disk;
> > +
> > + grub_dl_ref (my_mod);
> > +
> > + data = grub_nilfs2_mount (disk);
> > + if (!data)
> > + *tm = 0;
> > + else
> > + *tm = (grub_int32_t)grub_le_to_cpu64 (data->sblock.s_mtime);
> > +
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (data);
> > +
> > + return grub_errno;
> > +}
> > +
> > +
> > +\f
> > +static struct grub_fs grub_nilfs2_fs=
> > + {
> > + .name = "nilfs2",
> > + .dir = grub_nilfs2_dir,
> > + .open = grub_nilfs2_open,
> > + .read = grub_nilfs2_read,
> > + .close = grub_nilfs2_close,
> > + .label = grub_nilfs2_label,
> > + .uuid = grub_nilfs2_uuid,
> > + .mtime = grub_nilfs2_mtime,
> > +#ifdef GRUB_UTIL
> > + .reserved_first_sector = 1,
> > +#endif
> > + .next = 0
> > + };
> > +
> > +GRUB_MOD_INIT(nilfs2)
> > +{
> > + grub_fs_register (&grub_nilfs2_fs);
> > + my_mod = mod;
> > +}
> > +
> > +GRUB_MOD_FINI(nilfs2)
> > +{
> > + grub_fs_unregister (&grub_nilfs2_fs);
> > +}
> >
> > === modified file 'include/grub/misc.h'
> > --- include/grub/misc.h 2010-02-03 00:24:07 +0000
> > +++ include/grub/misc.h 2010-02-18 13:57:40 +0000
> > @@ -45,6 +45,7 @@
> > ((addr + (typeof (addr)) align - 1) & ~((typeof (addr)) align - 1))
> > #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
> > #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; }
> > +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
> >
> > #define grub_dprintf(condition, fmt, args...) grub_real_dprintf(__FILE__, __LINE__, condition, fmt, ## args)
> > /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
> >
> >
> >
> > ------------------------------------------------------------------------
> >
> > _______________________________________________
> > Grub-devel mailing list
> > Grub-devel@gnu.org
> > http://lists.gnu.org/mailman/listinfo/grub-devel
> >
>
>
> --
> Regards
> Vladimir 'φ-coder/phcoder' Serbinenko
>
>
> [1.2 OpenPGP digital signature <application/pgp-signature (7bit)>]
>
> [2 <text/plain; us-ascii (7bit)>]
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
--
Jiro SEKIBA <jir@unicus.jp>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2010-02-24 11:25 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-03 9:41 [PATCH] a new filessytem module for nilfs2 Jiro SEKIBA
2010-02-05 16:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-06 5:02 ` Jiro SEKIBA
2010-02-24 11:25 ` [PATCHv2] a new filesystem " Jiro SEKIBA
2010-02-10 0:31 ` [PATCH] a new filessytem " Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-11 14:25 ` Jiro SEKIBA
-- strict thread matches above, loose matches on Subject: below --
2010-02-18 9:13 [PATCHv2] a new filesystem " Jiro SEKIBA
2010-02-20 10:36 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-02-20 11:00 ` Jiro SEKIBA
2010-02-24 10:57 ` Vladimir 'φ-coder/phcoder' Serbinenko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.