2 * nilfs2.c - New Implementation of Log filesystem
4 * Written by Jiro SEKIBA <jir@unicus.jp>
6 * Copyright (C) 2003,2004,2005,2007,2008,2010 Free Software Foundation, Inc.
8 * GRUB is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * GRUB is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
23 /* Filetype information as used in inodes. */
24 #define FILETYPE_INO_MASK 0170000
25 #define FILETYPE_INO_REG 0100000
26 #define FILETYPE_INO_DIRECTORY 0040000
27 #define FILETYPE_INO_SYMLINK 0120000
30 #include <grub/file.h>
32 #include <grub/misc.h>
33 #include <grub/disk.h>
35 #include <grub/types.h>
36 #include <grub/fshelp.h>
38 GRUB_MOD_LICENSE ("GPLv3+");
40 #define NILFS_INODE_BMAP_SIZE 7
42 #define NILFS_SUPORT_REV 2
44 /* Magic value used to identify an nilfs2 filesystem. */
45 #define NILFS2_SUPER_MAGIC 0x3434
46 /* nilfs btree node flag. */
47 #define NILFS_BTREE_NODE_ROOT 0x01
49 /* nilfs btree node level. */
50 #define NILFS_BTREE_LEVEL_DATA 0
51 #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
53 /* nilfs 1st super block posission from beginning of the partition
55 #define NILFS_1ST_SUPER_BLOCK 2
56 /* nilfs 2nd super block posission from beginning of the partition
58 #define NILFS_2ND_SUPER_BLOCK(devsize) (((devsize >> 3) - 1) << 3)
60 #define LOG_INODE_SIZE 7
61 struct grub_nilfs2_inode
63 grub_uint64_t i_blocks
;
65 grub_uint64_t i_ctime
;
66 grub_uint64_t i_mtime
;
67 grub_uint32_t i_ctime_nsec
;
68 grub_uint32_t i_mtime_nsec
;
72 grub_uint16_t i_links_count
;
73 grub_uint32_t i_flags
;
74 grub_uint64_t i_bmap
[NILFS_INODE_BMAP_SIZE
];
75 #define i_device_code i_bmap[0]
76 grub_uint64_t i_xattr
;
77 grub_uint32_t i_generation
;
81 struct grub_nilfs2_super_root
84 grub_uint16_t sr_bytes
;
85 grub_uint16_t sr_flags
;
86 grub_uint64_t sr_nongc_ctime
;
87 struct grub_nilfs2_inode sr_dat
;
88 struct grub_nilfs2_inode sr_cpfile
;
89 struct grub_nilfs2_inode sr_sufile
;
92 struct grub_nilfs2_super_block
94 grub_uint32_t s_rev_level
;
95 grub_uint16_t s_minor_rev_level
;
96 grub_uint16_t s_magic
;
97 grub_uint16_t s_bytes
;
98 grub_uint16_t s_flags
;
99 grub_uint32_t s_crc_seed
;
101 grub_uint32_t s_log_block_size
;
102 grub_uint64_t s_nsegments
;
103 grub_uint64_t s_dev_size
;
104 grub_uint64_t s_first_data_block
;
105 grub_uint32_t s_blocks_per_segment
;
106 grub_uint32_t s_r_segments_percentage
;
107 grub_uint64_t s_last_cno
;
108 grub_uint64_t s_last_pseg
;
109 grub_uint64_t s_last_seq
;
110 grub_uint64_t s_free_blocks_count
;
111 grub_uint64_t s_ctime
;
112 grub_uint64_t s_mtime
;
113 grub_uint64_t s_wtime
;
114 grub_uint16_t s_mnt_count
;
115 grub_uint16_t s_max_mnt_count
;
116 grub_uint16_t s_state
;
117 grub_uint16_t s_errors
;
118 grub_uint64_t s_lastcheck
;
119 grub_uint32_t s_checkinterval
;
120 grub_uint32_t s_creator_os
;
121 grub_uint16_t s_def_resuid
;
122 grub_uint16_t s_def_resgid
;
123 grub_uint32_t s_first_ino
;
124 grub_uint16_t s_inode_size
;
125 grub_uint16_t s_dat_entry_size
;
126 grub_uint16_t s_checkpoint_size
;
127 grub_uint16_t s_segment_usage_size
;
128 grub_uint8_t s_uuid
[16];
129 char s_volume_name
[80];
130 grub_uint32_t s_c_interval
;
131 grub_uint32_t s_c_block_max
;
132 grub_uint32_t s_reserved
[192];
135 struct grub_nilfs2_dir_entry
138 grub_uint16_t rec_len
;
139 #define MAX_NAMELEN 255
140 grub_uint8_t name_len
;
141 grub_uint8_t file_type
;
142 #if 0 /* followed by file name. */
143 char name
[NILFS_NAME_LEN
];
161 struct grub_nilfs2_finfo
163 grub_uint64_t fi_ino
;
164 grub_uint64_t fi_cno
;
165 grub_uint32_t fi_nblocks
;
166 grub_uint32_t fi_ndatablk
;
169 struct grub_nilfs2_binfo_v
171 grub_uint64_t bi_vblocknr
;
172 grub_uint64_t bi_blkoff
;
175 struct grub_nilfs2_binfo_dat
177 grub_uint64_t bi_blkoff
;
178 grub_uint8_t bi_level
;
179 grub_uint8_t bi_pad
[7];
182 union grub_nilfs2_binfo
184 struct grub_nilfs2_binfo_v bi_v
;
185 struct grub_nilfs2_binfo_dat bi_dat
;
188 struct grub_nilfs2_segment_summary
190 grub_uint32_t ss_datasum
;
191 grub_uint32_t ss_sumsum
;
192 grub_uint32_t ss_magic
;
193 grub_uint16_t ss_bytes
;
194 grub_uint16_t ss_flags
;
195 grub_uint64_t ss_seq
;
196 grub_uint64_t ss_create
;
197 grub_uint64_t ss_next
;
198 grub_uint32_t ss_nblocks
;
199 grub_uint32_t ss_nfinfo
;
200 grub_uint32_t ss_sumbytes
;
201 grub_uint32_t ss_pad
;
204 struct grub_nilfs2_btree_node
206 grub_uint8_t bn_flags
;
207 grub_uint8_t bn_level
;
208 grub_uint16_t bn_nchildren
;
209 grub_uint32_t bn_pad
;
210 grub_uint64_t keys
[0];
213 struct grub_nilfs2_palloc_group_desc
215 grub_uint32_t pg_nfrees
;
218 #define LOG_SIZE_GROUP_DESC 2
220 #define LOG_NILFS_DAT_ENTRY_SIZE 5
221 struct grub_nilfs2_dat_entry
223 grub_uint64_t de_blocknr
;
224 grub_uint64_t de_start
;
225 grub_uint64_t de_end
;
226 grub_uint64_t de_rsv
;
229 struct grub_nilfs2_snapshot_list
231 grub_uint64_t ssl_next
;
232 grub_uint64_t ssl_prev
;
235 struct grub_nilfs2_cpfile_header
237 grub_uint64_t ch_ncheckpoints
;
238 grub_uint64_t ch_nsnapshots
;
239 struct grub_nilfs2_snapshot_list ch_snapshot_list
;
242 struct grub_nilfs2_checkpoint
244 grub_uint32_t cp_flags
;
245 grub_uint32_t cp_checkpoints_count
;
246 struct grub_nilfs2_snapshot_list cp_snapshot_list
;
247 grub_uint64_t cp_cno
;
248 grub_uint64_t cp_create
;
249 grub_uint64_t cp_nblk_inc
;
250 grub_uint64_t cp_inodes_count
;
251 grub_uint64_t cp_blocks_count
;
252 struct grub_nilfs2_inode cp_ifile_inode
;
256 #define NILFS_BMAP_LARGE 0x1
257 #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
259 /* nilfs extra padding for nonroot btree node. */
260 #define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
261 #define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
262 #define NILFS_BTREE_ROOT_NCHILDREN_MAX \
263 ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
264 (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
267 struct grub_fshelp_node
269 struct grub_nilfs2_data
*data
;
270 struct grub_nilfs2_inode inode
;
275 struct grub_nilfs2_data
277 struct grub_nilfs2_super_block sblock
;
278 struct grub_nilfs2_super_root sroot
;
279 struct grub_nilfs2_inode ifile
;
281 struct grub_nilfs2_inode
*inode
;
282 struct grub_fshelp_node diropen
;
285 /* Log2 size of nilfs2 block in 512 blocks. */
286 #define LOG2_NILFS2_BLOCK_SIZE(data) \
287 (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
289 /* Log2 size of nilfs2 block in bytes. */
290 #define LOG2_BLOCK_SIZE(data) \
291 (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
293 /* The size of an nilfs2 block in bytes. */
294 #define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
297 grub_nilfs2_dat_translate (struct grub_nilfs2_data
*data
, grub_uint64_t key
);
298 static grub_dl_t my_mod
;
302 static inline unsigned long
303 grub_nilfs2_log_palloc_entries_per_group (struct grub_nilfs2_data
*data
)
305 return LOG2_BLOCK_SIZE (data
) + 3;
308 static inline grub_uint64_t
309 grub_nilfs2_palloc_group (struct grub_nilfs2_data
*data
,
310 grub_uint64_t nr
, grub_uint64_t
* offset
)
312 *offset
= nr
& ((1 << grub_nilfs2_log_palloc_entries_per_group (data
)) - 1);
313 return nr
>> grub_nilfs2_log_palloc_entries_per_group (data
);
316 static inline grub_uint32_t
317 grub_nilfs2_palloc_log_groups_per_desc_block (struct grub_nilfs2_data
*data
)
319 return LOG2_BLOCK_SIZE (data
) - LOG_SIZE_GROUP_DESC
;
321 COMPILE_TIME_ASSERT (sizeof (struct grub_nilfs2_palloc_group_desc
)
322 == (1 << LOG_SIZE_GROUP_DESC
));
325 static inline grub_uint32_t
326 grub_nilfs2_log_entries_per_block_log (struct grub_nilfs2_data
*data
,
327 unsigned long log_entry_size
)
329 return LOG2_BLOCK_SIZE (data
) - log_entry_size
;
333 static inline grub_uint32_t
334 grub_nilfs2_blocks_per_group_log (struct grub_nilfs2_data
*data
,
335 unsigned long log_entry_size
)
337 return (1 << (grub_nilfs2_log_palloc_entries_per_group (data
)
338 - grub_nilfs2_log_entries_per_block_log (data
,
339 log_entry_size
))) + 1;
342 static inline grub_uint32_t
343 grub_nilfs2_blocks_per_desc_block_log (struct grub_nilfs2_data
*data
,
344 unsigned long log_entry_size
)
346 return(grub_nilfs2_blocks_per_group_log (data
, log_entry_size
)
347 << grub_nilfs2_palloc_log_groups_per_desc_block (data
)) + 1;
350 static inline grub_uint32_t
351 grub_nilfs2_palloc_desc_block_offset_log (struct grub_nilfs2_data
*data
,
353 unsigned long log_entry_size
)
355 grub_uint32_t desc_block
=
356 group
>> grub_nilfs2_palloc_log_groups_per_desc_block (data
);
357 return desc_block
* grub_nilfs2_blocks_per_desc_block_log (data
,
361 static inline grub_uint32_t
362 grub_nilfs2_palloc_bitmap_block_offset (struct grub_nilfs2_data
*data
,
364 unsigned long log_entry_size
)
366 unsigned long desc_offset
= group
367 & ((1 << grub_nilfs2_palloc_log_groups_per_desc_block (data
)) - 1);
369 return grub_nilfs2_palloc_desc_block_offset_log (data
, group
, log_entry_size
)
371 + desc_offset
* grub_nilfs2_blocks_per_group_log (data
, log_entry_size
);
374 static inline grub_uint32_t
375 grub_nilfs2_palloc_entry_offset_log (struct grub_nilfs2_data
*data
,
377 unsigned long log_entry_size
)
380 grub_uint64_t group_offset
;
382 group
= grub_nilfs2_palloc_group (data
, nr
, &group_offset
);
384 return grub_nilfs2_palloc_bitmap_block_offset (data
, group
,
385 log_entry_size
) + 1 +
386 (group_offset
>> grub_nilfs2_log_entries_per_block_log (data
,
391 static inline struct grub_nilfs2_btree_node
*
392 grub_nilfs2_btree_get_root (struct grub_nilfs2_inode
*inode
)
394 return (struct grub_nilfs2_btree_node
*) &inode
->i_bmap
[0];
398 grub_nilfs2_btree_get_level (struct grub_nilfs2_btree_node
*node
)
400 return node
->bn_level
;
403 static inline grub_uint64_t
*
404 grub_nilfs2_btree_node_dkeys (struct grub_nilfs2_btree_node
*node
)
407 ((node
->bn_flags
& NILFS_BTREE_NODE_ROOT
) ?
408 0 : (NILFS_BTREE_NODE_EXTRA_PAD_SIZE
/ sizeof (grub_uint64_t
))));
411 static inline grub_uint64_t
412 grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node
*node
,
415 return grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dkeys (node
) + index
));
419 grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node
*node
,
420 grub_uint64_t key
, int *indexp
)
423 int index
, low
, high
, s
;
426 high
= grub_le_to_cpu16 (node
->bn_nchildren
) - 1;
431 index
= (low
+ high
) / 2;
432 nkey
= grub_nilfs2_btree_node_get_key (node
, index
);
450 if (node
->bn_level
> NILFS_BTREE_LEVEL_NODE_MIN
)
452 if (s
> 0 && index
> 0)
463 grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data
*data
,
464 struct grub_nilfs2_btree_node
*node
)
466 int node_children_max
= ((NILFS2_BLOCK_SIZE (data
) -
467 sizeof (struct grub_nilfs2_btree_node
) -
468 NILFS_BTREE_NODE_EXTRA_PAD_SIZE
) /
469 (sizeof (grub_uint64_t
) + sizeof (grub_uint64_t
)));
471 return (node
->bn_flags
& NILFS_BTREE_NODE_ROOT
) ? 3 : node_children_max
;
474 static inline grub_uint64_t
*
475 grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data
*data
,
476 struct grub_nilfs2_btree_node
*node
)
478 return (grub_uint64_t
*) (grub_nilfs2_btree_node_dkeys (node
) +
479 grub_nilfs2_btree_node_nchildren_max (data
,
483 static inline grub_uint64_t
484 grub_nilfs2_btree_node_get_ptr (struct grub_nilfs2_data
*data
,
485 struct grub_nilfs2_btree_node
*node
,
489 grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dptrs (data
, node
) + index
));
493 grub_nilfs2_btree_get_nonroot_node (struct grub_nilfs2_data
*data
,
494 grub_uint64_t ptr
, void *block
)
496 grub_disk_t disk
= data
->disk
;
497 unsigned int nilfs2_block_count
= (1 << LOG2_NILFS2_BLOCK_SIZE (data
));
499 return grub_disk_read (disk
, ptr
* nilfs2_block_count
, 0,
500 NILFS2_BLOCK_SIZE (data
), block
);
504 grub_nilfs2_btree_lookup (struct grub_nilfs2_data
*data
,
505 struct grub_nilfs2_inode
*inode
,
506 grub_uint64_t key
, int need_translate
)
508 struct grub_nilfs2_btree_node
*node
;
511 int level
, found
= 0, index
;
513 block
= grub_malloc (NILFS2_BLOCK_SIZE (data
));
517 node
= grub_nilfs2_btree_get_root (inode
);
518 level
= grub_nilfs2_btree_get_level (node
);
520 found
= grub_nilfs2_btree_node_lookup (node
, key
, &index
);
521 ptr
= grub_nilfs2_btree_node_get_ptr (data
, node
, index
);
523 ptr
= grub_nilfs2_dat_translate (data
, ptr
);
525 for (level
--; level
>= NILFS_BTREE_LEVEL_NODE_MIN
; level
--)
527 grub_nilfs2_btree_get_nonroot_node (data
, ptr
, block
);
532 node
= (struct grub_nilfs2_btree_node
*) block
;
534 if (node
->bn_level
!= level
)
536 grub_error (GRUB_ERR_BAD_FS
, "btree level mismatch\n");
541 found
= grub_nilfs2_btree_node_lookup (node
, key
, &index
);
545 if (index
< grub_nilfs2_btree_node_nchildren_max (data
, node
))
547 ptr
= grub_nilfs2_btree_node_get_ptr (data
, node
, index
);
549 ptr
= grub_nilfs2_dat_translate (data
, ptr
);
553 grub_error (GRUB_ERR_BAD_FS
, "btree corruption\n");
569 static inline grub_uint64_t
570 grub_nilfs2_direct_lookup (struct grub_nilfs2_inode
*inode
, grub_uint64_t key
)
572 return grub_le_to_cpu64 (inode
->i_bmap
[1 + key
]);
575 static inline grub_uint64_t
576 grub_nilfs2_bmap_lookup (struct grub_nilfs2_data
*data
,
577 struct grub_nilfs2_inode
*inode
,
578 grub_uint64_t key
, int need_translate
)
580 struct grub_nilfs2_btree_node
*root
= grub_nilfs2_btree_get_root (inode
);
581 if (root
->bn_flags
& NILFS_BMAP_LARGE
)
582 return grub_nilfs2_btree_lookup (data
, inode
, key
, need_translate
);
586 ptr
= grub_nilfs2_direct_lookup (inode
, key
);
588 ptr
= grub_nilfs2_dat_translate (data
, ptr
);
594 grub_nilfs2_dat_translate (struct grub_nilfs2_data
*data
, grub_uint64_t key
)
596 struct grub_nilfs2_dat_entry entry
;
597 grub_disk_t disk
= data
->disk
;
599 grub_uint64_t blockno
, offset
;
600 unsigned int nilfs2_block_count
= (1 << LOG2_NILFS2_BLOCK_SIZE (data
));
602 blockno
= grub_nilfs2_palloc_entry_offset_log (data
, key
,
603 LOG_NILFS_DAT_ENTRY_SIZE
);
605 offset
= ((key
* sizeof (struct grub_nilfs2_dat_entry
))
606 & ((1 << LOG2_BLOCK_SIZE (data
)) - 1));
608 pptr
= grub_nilfs2_bmap_lookup (data
, &data
->sroot
.sr_dat
, blockno
, 0);
609 if (pptr
== (grub_uint64_t
) - 1)
611 grub_error (GRUB_ERR_BAD_FS
, "btree lookup failure");
615 grub_disk_read (disk
, pptr
* nilfs2_block_count
, offset
,
616 sizeof (struct grub_nilfs2_dat_entry
), &entry
);
618 return grub_le_to_cpu64 (entry
.de_blocknr
);
622 static grub_disk_addr_t
623 grub_nilfs2_read_block (grub_fshelp_node_t node
, grub_disk_addr_t fileblock
)
625 struct grub_nilfs2_data
*data
= node
->data
;
626 struct grub_nilfs2_inode
*inode
= &node
->inode
;
627 grub_uint64_t pptr
= -1;
629 pptr
= grub_nilfs2_bmap_lookup (data
, inode
, fileblock
, 1);
630 if (pptr
== (grub_uint64_t
) - 1)
632 grub_error (GRUB_ERR_BAD_FS
, "btree lookup failure");
639 /* Read LEN bytes from the file described by DATA starting with byte
640 POS. Return the amount of read bytes in READ. */
642 grub_nilfs2_read_file (grub_fshelp_node_t node
,
643 grub_disk_read_hook_t read_hook
, void *read_hook_data
,
644 grub_off_t pos
, grub_size_t len
, char *buf
)
646 return grub_fshelp_read_file (node
->data
->disk
, node
,
647 read_hook
, read_hook_data
,
648 pos
, len
, buf
, grub_nilfs2_read_block
,
649 grub_le_to_cpu64 (node
->inode
.i_size
),
650 LOG2_NILFS2_BLOCK_SIZE (node
->data
), 0);
655 grub_nilfs2_read_checkpoint (struct grub_nilfs2_data
*data
,
657 struct grub_nilfs2_checkpoint
*cpp
)
659 grub_uint64_t blockno
;
660 grub_uint64_t offset
;
662 grub_disk_t disk
= data
->disk
;
663 unsigned int nilfs2_block_count
= (1 << LOG2_NILFS2_BLOCK_SIZE (data
));
665 /* Assume sizeof(struct grub_nilfs2_cpfile_header) <
666 sizeof(struct grub_nilfs2_checkpoint).
668 blockno
= grub_divmod64 (cpno
, NILFS2_BLOCK_SIZE (data
) /
669 sizeof (struct grub_nilfs2_checkpoint
), &offset
);
671 pptr
= grub_nilfs2_bmap_lookup (data
, &data
->sroot
.sr_cpfile
, blockno
, 1);
672 if (pptr
== (grub_uint64_t
) - 1)
674 return grub_error (GRUB_ERR_BAD_FS
, "btree lookup failure");
677 return grub_disk_read (disk
, pptr
* nilfs2_block_count
,
678 offset
* sizeof (struct grub_nilfs2_checkpoint
),
679 sizeof (struct grub_nilfs2_checkpoint
), cpp
);
682 static inline grub_err_t
683 grub_nilfs2_read_last_checkpoint (struct grub_nilfs2_data
*data
,
684 struct grub_nilfs2_checkpoint
*cpp
)
686 return grub_nilfs2_read_checkpoint (data
,
687 grub_le_to_cpu64 (data
->
692 /* Read the inode INO for the file described by DATA into INODE. */
694 grub_nilfs2_read_inode (struct grub_nilfs2_data
*data
,
695 grub_uint64_t ino
, struct grub_nilfs2_inode
*inodep
)
697 grub_uint64_t blockno
;
698 grub_uint64_t offset
;
700 grub_disk_t disk
= data
->disk
;
701 unsigned int nilfs2_block_count
= (1 << LOG2_NILFS2_BLOCK_SIZE (data
));
703 blockno
= grub_nilfs2_palloc_entry_offset_log (data
, ino
,
706 offset
= ((sizeof (struct grub_nilfs2_inode
) * ino
)
707 & ((1 << LOG2_BLOCK_SIZE (data
)) - 1));
708 pptr
= grub_nilfs2_bmap_lookup (data
, &data
->ifile
, blockno
, 1);
709 if (pptr
== (grub_uint64_t
) - 1)
711 return grub_error (GRUB_ERR_BAD_FS
, "btree lookup failure");
714 return grub_disk_read (disk
, pptr
* nilfs2_block_count
, offset
,
715 sizeof (struct grub_nilfs2_inode
), inodep
);
719 grub_nilfs2_valid_sb (struct grub_nilfs2_super_block
*sbp
)
721 if (grub_le_to_cpu16 (sbp
->s_magic
) != NILFS2_SUPER_MAGIC
)
724 if (grub_le_to_cpu32 (sbp
->s_rev_level
) != NILFS_SUPORT_REV
)
727 /* 20 already means 1GiB blocks. We don't want to deal with blocks overflowing int32. */
728 if (grub_le_to_cpu32 (sbp
->s_log_block_size
) > 20)
735 grub_nilfs2_load_sb (struct grub_nilfs2_data
*data
)
737 grub_disk_t disk
= data
->disk
;
738 struct grub_nilfs2_super_block sb2
;
739 grub_uint64_t partition_size
;
744 /* Read first super block. */
745 err
= grub_disk_read (disk
, NILFS_1ST_SUPER_BLOCK
, 0,
746 sizeof (struct grub_nilfs2_super_block
), &data
->sblock
);
749 /* Make sure if 1st super block is valid. */
750 valid
[0] = grub_nilfs2_valid_sb (&data
->sblock
);
753 partition_size
= (grub_le_to_cpu64 (data
->sblock
.s_dev_size
)
754 >> GRUB_DISK_SECTOR_BITS
);
756 partition_size
= grub_disk_get_size (disk
);
757 if (partition_size
!= GRUB_DISK_SIZE_UNKNOWN
)
759 /* Read second super block. */
760 err
= grub_disk_read (disk
, NILFS_2ND_SUPER_BLOCK (partition_size
), 0,
761 sizeof (struct grub_nilfs2_super_block
), &sb2
);
765 grub_errno
= GRUB_ERR_NONE
;
768 /* Make sure if 2nd super block is valid. */
769 valid
[1] = grub_nilfs2_valid_sb (&sb2
);
772 /* 2nd super block may not exist, so it's invalid. */
775 if (!valid
[0] && !valid
[1])
776 return grub_error (GRUB_ERR_BAD_FS
, "not a nilfs2 filesystem");
778 swp
= valid
[1] && (!valid
[0] ||
779 grub_le_to_cpu64 (data
->sblock
.s_last_cno
) <
780 grub_le_to_cpu64 (sb2
.s_last_cno
));
782 /* swap if first super block is invalid or older than second one. */
784 grub_memcpy (&data
->sblock
, &sb2
,
785 sizeof (struct grub_nilfs2_super_block
));
787 return GRUB_ERR_NONE
;
790 static struct grub_nilfs2_data
*
791 grub_nilfs2_mount (grub_disk_t disk
)
793 struct grub_nilfs2_data
*data
;
794 struct grub_nilfs2_segment_summary ss
;
795 struct grub_nilfs2_checkpoint last_checkpoint
;
796 grub_uint64_t last_pseg
;
797 grub_uint32_t nblocks
;
798 unsigned int nilfs2_block_count
;
800 data
= grub_malloc (sizeof (struct grub_nilfs2_data
));
806 /* Read the superblock. */
807 grub_nilfs2_load_sb (data
);
811 nilfs2_block_count
= (1 << LOG2_NILFS2_BLOCK_SIZE (data
));
813 /* Read the last segment summary. */
814 last_pseg
= grub_le_to_cpu64 (data
->sblock
.s_last_pseg
);
815 grub_disk_read (disk
, last_pseg
* nilfs2_block_count
, 0,
816 sizeof (struct grub_nilfs2_segment_summary
), &ss
);
821 /* Read the super root block. */
822 nblocks
= grub_le_to_cpu32 (ss
.ss_nblocks
);
823 grub_disk_read (disk
, (last_pseg
+ (nblocks
- 1)) * nilfs2_block_count
, 0,
824 sizeof (struct grub_nilfs2_super_root
), &data
->sroot
);
829 grub_nilfs2_read_last_checkpoint (data
, &last_checkpoint
);
834 grub_memcpy (&data
->ifile
, &last_checkpoint
.cp_ifile_inode
,
835 sizeof (struct grub_nilfs2_inode
));
837 data
->diropen
.data
= data
;
838 data
->diropen
.ino
= 2;
839 data
->diropen
.inode_read
= 1;
840 data
->inode
= &data
->diropen
.inode
;
842 grub_nilfs2_read_inode (data
, 2, data
->inode
);
847 if (grub_errno
== GRUB_ERR_OUT_OF_RANGE
)
848 grub_error (GRUB_ERR_BAD_FS
, "not a nilfs2 filesystem");
855 grub_nilfs2_read_symlink (grub_fshelp_node_t node
)
858 struct grub_fshelp_node
*diro
= node
;
860 if (!diro
->inode_read
)
862 grub_nilfs2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
867 symlink
= grub_malloc (grub_le_to_cpu64 (diro
->inode
.i_size
) + 1);
871 grub_nilfs2_read_file (diro
, 0, 0, 0,
872 grub_le_to_cpu64 (diro
->inode
.i_size
), symlink
);
879 symlink
[grub_le_to_cpu64 (diro
->inode
.i_size
)] = '\0';
884 grub_nilfs2_iterate_dir (grub_fshelp_node_t dir
,
885 grub_fshelp_iterate_dir_hook_t hook
, void *hook_data
)
888 struct grub_fshelp_node
*diro
= (struct grub_fshelp_node
*) dir
;
890 if (!diro
->inode_read
)
892 grub_nilfs2_read_inode (diro
->data
, diro
->ino
, &diro
->inode
);
898 while (fpos
< grub_le_to_cpu64 (diro
->inode
.i_size
))
900 struct grub_nilfs2_dir_entry dirent
;
902 grub_nilfs2_read_file (diro
, 0, 0, fpos
,
903 sizeof (struct grub_nilfs2_dir_entry
),
908 if (dirent
.rec_len
== 0)
911 if (dirent
.name_len
!= 0)
913 char filename
[MAX_NAMELEN
+ 1];
914 struct grub_fshelp_node
*fdiro
;
915 enum grub_fshelp_filetype type
= GRUB_FSHELP_UNKNOWN
;
917 grub_nilfs2_read_file (diro
, 0, 0,
918 fpos
+ sizeof (struct grub_nilfs2_dir_entry
),
919 dirent
.name_len
, filename
);
923 fdiro
= grub_malloc (sizeof (struct grub_fshelp_node
));
927 fdiro
->data
= diro
->data
;
928 fdiro
->ino
= grub_le_to_cpu64 (dirent
.inode
);
930 filename
[dirent
.name_len
] = '\0';
932 if (dirent
.file_type
!= NILFS_FT_UNKNOWN
)
934 fdiro
->inode_read
= 0;
936 if (dirent
.file_type
== NILFS_FT_DIR
)
937 type
= GRUB_FSHELP_DIR
;
938 else if (dirent
.file_type
== NILFS_FT_SYMLINK
)
939 type
= GRUB_FSHELP_SYMLINK
;
940 else if (dirent
.file_type
== NILFS_FT_REG_FILE
)
941 type
= GRUB_FSHELP_REG
;
945 /* The filetype can not be read from the dirent, read
946 the inode to get more information. */
947 grub_nilfs2_read_inode (diro
->data
,
948 grub_le_to_cpu64 (dirent
.inode
),
956 fdiro
->inode_read
= 1;
958 if ((grub_le_to_cpu16 (fdiro
->inode
.i_mode
)
959 & FILETYPE_INO_MASK
) == FILETYPE_INO_DIRECTORY
)
960 type
= GRUB_FSHELP_DIR
;
961 else if ((grub_le_to_cpu16 (fdiro
->inode
.i_mode
)
962 & FILETYPE_INO_MASK
) == FILETYPE_INO_SYMLINK
)
963 type
= GRUB_FSHELP_SYMLINK
;
964 else if ((grub_le_to_cpu16 (fdiro
->inode
.i_mode
)
965 & FILETYPE_INO_MASK
) == FILETYPE_INO_REG
)
966 type
= GRUB_FSHELP_REG
;
969 if (hook (filename
, type
, fdiro
, hook_data
))
973 fpos
+= grub_le_to_cpu16 (dirent
.rec_len
);
979 /* Open a file named NAME and initialize FILE. */
981 grub_nilfs2_open (struct grub_file
*file
, const char *name
)
983 struct grub_nilfs2_data
*data
= NULL
;
984 struct grub_fshelp_node
*fdiro
= 0;
986 grub_dl_ref (my_mod
);
988 data
= grub_nilfs2_mount (file
->device
->disk
);
992 grub_fshelp_find_file (name
, &data
->diropen
, &fdiro
,
993 grub_nilfs2_iterate_dir
, grub_nilfs2_read_symlink
,
998 if (!fdiro
->inode_read
)
1000 grub_nilfs2_read_inode (data
, fdiro
->ino
, &fdiro
->inode
);
1005 grub_memcpy (data
->inode
, &fdiro
->inode
, sizeof (struct grub_nilfs2_inode
));
1008 file
->size
= grub_le_to_cpu64 (data
->inode
->i_size
);
1015 if (fdiro
!= &data
->diropen
)
1019 grub_dl_unref (my_mod
);
1025 grub_nilfs2_close (grub_file_t file
)
1027 grub_free (file
->data
);
1029 grub_dl_unref (my_mod
);
1031 return GRUB_ERR_NONE
;
1034 /* Read LEN bytes data from FILE into BUF. */
1036 grub_nilfs2_read (grub_file_t file
, char *buf
, grub_size_t len
)
1038 struct grub_nilfs2_data
*data
= (struct grub_nilfs2_data
*) file
->data
;
1040 return grub_nilfs2_read_file (&data
->diropen
,
1041 file
->read_hook
, file
->read_hook_data
,
1042 file
->offset
, len
, buf
);
1045 /* Context for grub_nilfs2_dir. */
1046 struct grub_nilfs2_dir_ctx
1048 grub_fs_dir_hook_t hook
;
1050 struct grub_nilfs2_data
*data
;
1053 /* Helper for grub_nilfs2_dir. */
1055 grub_nilfs2_dir_iter (const char *filename
, enum grub_fshelp_filetype filetype
,
1056 grub_fshelp_node_t node
, void *data
)
1058 struct grub_nilfs2_dir_ctx
*ctx
= data
;
1059 struct grub_dirhook_info info
;
1061 grub_memset (&info
, 0, sizeof (info
));
1062 if (!node
->inode_read
)
1064 grub_nilfs2_read_inode (ctx
->data
, node
->ino
, &node
->inode
);
1066 node
->inode_read
= 1;
1067 grub_errno
= GRUB_ERR_NONE
;
1069 if (node
->inode_read
)
1072 info
.mtime
= grub_le_to_cpu64 (node
->inode
.i_mtime
);
1075 info
.dir
= ((filetype
& GRUB_FSHELP_TYPE_MASK
) == GRUB_FSHELP_DIR
);
1077 return ctx
->hook (filename
, &info
, ctx
->hook_data
);
1081 grub_nilfs2_dir (grub_device_t device
, const char *path
,
1082 grub_fs_dir_hook_t hook
, void *hook_data
)
1084 struct grub_nilfs2_dir_ctx ctx
= {
1086 .hook_data
= hook_data
1088 struct grub_fshelp_node
*fdiro
= 0;
1090 grub_dl_ref (my_mod
);
1092 ctx
.data
= grub_nilfs2_mount (device
->disk
);
1096 grub_fshelp_find_file (path
, &ctx
.data
->diropen
, &fdiro
,
1097 grub_nilfs2_iterate_dir
, grub_nilfs2_read_symlink
,
1102 grub_nilfs2_iterate_dir (fdiro
, grub_nilfs2_dir_iter
, &ctx
);
1105 if (fdiro
!= &ctx
.data
->diropen
)
1107 grub_free (ctx
.data
);
1109 grub_dl_unref (my_mod
);
1115 grub_nilfs2_label (grub_device_t device
, char **label
)
1117 struct grub_nilfs2_data
*data
;
1118 grub_disk_t disk
= device
->disk
;
1120 grub_dl_ref (my_mod
);
1122 data
= grub_nilfs2_mount (disk
);
1124 *label
= grub_strndup (data
->sblock
.s_volume_name
,
1125 sizeof (data
->sblock
.s_volume_name
));
1129 grub_dl_unref (my_mod
);
1137 grub_nilfs2_uuid (grub_device_t device
, char **uuid
)
1139 struct grub_nilfs2_data
*data
;
1140 grub_disk_t disk
= device
->disk
;
1142 grub_dl_ref (my_mod
);
1144 data
= grub_nilfs2_mount (disk
);
1149 ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
1150 data
->sblock
.s_uuid
[0], data
->sblock
.s_uuid
[1],
1151 data
->sblock
.s_uuid
[2], data
->sblock
.s_uuid
[3],
1152 data
->sblock
.s_uuid
[4], data
->sblock
.s_uuid
[5],
1153 data
->sblock
.s_uuid
[6], data
->sblock
.s_uuid
[7],
1154 data
->sblock
.s_uuid
[8], data
->sblock
.s_uuid
[9],
1155 data
->sblock
.s_uuid
[10], data
->sblock
.s_uuid
[11],
1156 data
->sblock
.s_uuid
[12], data
->sblock
.s_uuid
[13],
1157 data
->sblock
.s_uuid
[14], data
->sblock
.s_uuid
[15]);
1162 grub_dl_unref (my_mod
);
1171 grub_nilfs2_mtime (grub_device_t device
, grub_int32_t
* tm
)
1173 struct grub_nilfs2_data
*data
;
1174 grub_disk_t disk
= device
->disk
;
1176 grub_dl_ref (my_mod
);
1178 data
= grub_nilfs2_mount (disk
);
1182 *tm
= (grub_int32_t
) grub_le_to_cpu64 (data
->sblock
.s_wtime
);
1184 grub_dl_unref (my_mod
);
1193 static struct grub_fs grub_nilfs2_fs
= {
1195 .dir
= grub_nilfs2_dir
,
1196 .open
= grub_nilfs2_open
,
1197 .read
= grub_nilfs2_read
,
1198 .close
= grub_nilfs2_close
,
1199 .label
= grub_nilfs2_label
,
1200 .uuid
= grub_nilfs2_uuid
,
1201 .mtime
= grub_nilfs2_mtime
,
1203 .reserved_first_sector
= 1,
1204 .blocklist_install
= 0,
1209 GRUB_MOD_INIT (nilfs2
)
1211 COMPILE_TIME_ASSERT ((1 << LOG_NILFS_DAT_ENTRY_SIZE
)
1213 grub_nilfs2_dat_entry
));
1214 COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE
1215 == sizeof (struct grub_nilfs2_inode
));
1216 grub_fs_register (&grub_nilfs2_fs
);
1220 GRUB_MOD_FINI (nilfs2
)
1222 grub_fs_unregister (&grub_nilfs2_fs
);