nilfs2.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. /*
  2. * nilfs2.c - New Implementation of Log filesystem
  3. *
  4. * Written by Jiro SEKIBA <jir@unicus.jp>
  5. *
  6. * Copyright (C) 2003,2004,2005,2007,2008,2010 Free Software Foundation, Inc.
  7. *
  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.
  12. *
  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.
  17. *
  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/>.
  20. */
  21. /* Filetype information as used in inodes. */
  22. #define FILETYPE_INO_MASK 0170000
  23. #define FILETYPE_INO_REG 0100000
  24. #define FILETYPE_INO_DIRECTORY 0040000
  25. #define FILETYPE_INO_SYMLINK 0120000
  26. #include <grub/err.h>
  27. #include <grub/file.h>
  28. #include <grub/mm.h>
  29. #include <grub/misc.h>
  30. #include <grub/disk.h>
  31. #include <grub/dl.h>
  32. #include <grub/types.h>
  33. #include <grub/fshelp.h>
  34. #define NILFS_INODE_BMAP_SIZE 7
  35. #define NILFS_SUPORT_REV 2
  36. /* Magic value used to identify an nilfs2 filesystem. */
  37. #define NILFS2_SUPER_MAGIC 0x3434
  38. /* nilfs btree node flag. */
  39. #define NILFS_BTREE_NODE_ROOT 0x01
  40. /* nilfs btree node level. */
  41. #define NILFS_BTREE_LEVEL_DATA 0
  42. #define NILFS_BTREE_LEVEL_NODE_MIN (NILFS_BTREE_LEVEL_DATA + 1)
  43. #define NILFS_BTREE_LEVEL_MAX 14
  44. struct grub_nilfs2_inode
  45. {
  46. grub_uint64_t i_blocks;
  47. grub_uint64_t i_size;
  48. grub_uint64_t i_ctime;
  49. grub_uint64_t i_mtime;
  50. grub_uint32_t i_ctime_nsec;
  51. grub_uint32_t i_mtime_nsec;
  52. grub_uint32_t i_uid;
  53. grub_uint32_t i_gid;
  54. grub_uint16_t i_mode;
  55. grub_uint16_t i_links_count;
  56. grub_uint32_t i_flags;
  57. grub_uint64_t i_bmap[NILFS_INODE_BMAP_SIZE];
  58. #define i_device_code i_bmap[0]
  59. grub_uint64_t i_xattr;
  60. grub_uint32_t i_generation;
  61. grub_uint32_t i_pad;
  62. };
  63. struct grub_nilfs2_super_root
  64. {
  65. grub_uint32_t sr_sum;
  66. grub_uint16_t sr_bytes;
  67. grub_uint16_t sr_flags;
  68. grub_uint64_t sr_nongc_ctime;
  69. struct grub_nilfs2_inode sr_dat;
  70. struct grub_nilfs2_inode sr_cpfile;
  71. struct grub_nilfs2_inode sr_sufile;
  72. };
  73. struct grub_nilfs2_super_block
  74. {
  75. grub_uint32_t s_rev_level;
  76. grub_uint16_t s_minor_rev_level;
  77. grub_uint16_t s_magic;
  78. grub_uint16_t s_bytes;
  79. grub_uint16_t s_flags;
  80. grub_uint32_t s_crc_seed;
  81. grub_uint32_t s_sum;
  82. grub_uint32_t s_log_block_size;
  83. grub_uint64_t s_nsegments;
  84. grub_uint64_t s_dev_size;
  85. grub_uint64_t s_first_data_block;
  86. grub_uint32_t s_blocks_per_segment;
  87. grub_uint32_t s_r_segments_percentage;
  88. grub_uint64_t s_last_cno;
  89. grub_uint64_t s_last_pseg;
  90. grub_uint64_t s_last_seq;
  91. grub_uint64_t s_free_blocks_count;
  92. grub_uint64_t s_ctime;
  93. grub_uint64_t s_mtime;
  94. grub_uint64_t s_wtime;
  95. grub_uint16_t s_mnt_count;
  96. grub_uint16_t s_max_mnt_count;
  97. grub_uint16_t s_state;
  98. grub_uint16_t s_errors;
  99. grub_uint64_t s_lastcheck;
  100. grub_uint32_t s_checkinterval;
  101. grub_uint32_t s_creator_os;
  102. grub_uint16_t s_def_resuid;
  103. grub_uint16_t s_def_resgid;
  104. grub_uint32_t s_first_ino;
  105. grub_uint16_t s_inode_size;
  106. grub_uint16_t s_dat_entry_size;
  107. grub_uint16_t s_checkpoint_size;
  108. grub_uint16_t s_segment_usage_size;
  109. grub_uint8_t s_uuid[16];
  110. char s_volume_name[16];
  111. char s_last_mounted[64];
  112. grub_uint32_t s_c_interval;
  113. grub_uint32_t s_c_block_max;
  114. grub_uint32_t s_reserved[192];
  115. };
  116. struct grub_nilfs2_dir_entry
  117. {
  118. grub_uint64_t inode;
  119. grub_uint16_t rec_len;
  120. grub_uint8_t name_len;
  121. grub_uint8_t file_type;
  122. #if 0 /* followed by file name. */
  123. char name[NILFS_NAME_LEN];
  124. char pad;
  125. #endif
  126. } __attribute__ ((packed));
  127. enum
  128. {
  129. NILFS_FT_UNKNOWN,
  130. NILFS_FT_REG_FILE,
  131. NILFS_FT_DIR,
  132. NILFS_FT_CHRDEV,
  133. NILFS_FT_BLKDEV,
  134. NILFS_FT_FIFO,
  135. NILFS_FT_SOCK,
  136. NILFS_FT_SYMLINK,
  137. NILFS_FT_MAX
  138. };
  139. struct grub_nilfs2_finfo
  140. {
  141. grub_uint64_t fi_ino;
  142. grub_uint64_t fi_cno;
  143. grub_uint32_t fi_nblocks;
  144. grub_uint32_t fi_ndatablk;
  145. };
  146. struct grub_nilfs2_binfo_v
  147. {
  148. grub_uint64_t bi_vblocknr;
  149. grub_uint64_t bi_blkoff;
  150. };
  151. struct grub_nilfs2_binfo_dat
  152. {
  153. grub_uint64_t bi_blkoff;
  154. grub_uint8_t bi_level;
  155. grub_uint8_t bi_pad[7];
  156. };
  157. union grub_nilfs2_binfo
  158. {
  159. struct grub_nilfs2_binfo_v bi_v;
  160. struct grub_nilfs2_binfo_dat bi_dat;
  161. };
  162. struct grub_nilfs2_segment_summary
  163. {
  164. grub_uint32_t ss_datasum;
  165. grub_uint32_t ss_sumsum;
  166. grub_uint32_t ss_magic;
  167. grub_uint16_t ss_bytes;
  168. grub_uint16_t ss_flags;
  169. grub_uint64_t ss_seq;
  170. grub_uint64_t ss_create;
  171. grub_uint64_t ss_next;
  172. grub_uint32_t ss_nblocks;
  173. grub_uint32_t ss_nfinfo;
  174. grub_uint32_t ss_sumbytes;
  175. grub_uint32_t ss_pad;
  176. };
  177. struct grub_nilfs2_btree_node
  178. {
  179. grub_uint8_t bn_flags;
  180. grub_uint8_t bn_level;
  181. grub_uint16_t bn_nchildren;
  182. grub_uint32_t bn_pad;
  183. };
  184. struct grub_nilfs2_palloc_group_desc
  185. {
  186. grub_uint32_t pg_nfrees;
  187. };
  188. struct grub_nilfs2_dat_entry
  189. {
  190. grub_uint64_t de_blocknr;
  191. grub_uint64_t de_start;
  192. grub_uint64_t de_end;
  193. grub_uint64_t de_rsv;
  194. };
  195. struct grub_nilfs2_snapshot_list
  196. {
  197. grub_uint64_t ssl_next;
  198. grub_uint64_t ssl_prev;
  199. };
  200. struct grub_nilfs2_cpfile_header
  201. {
  202. grub_uint64_t ch_ncheckpoints;
  203. grub_uint64_t ch_nsnapshots;
  204. struct grub_nilfs2_snapshot_list ch_snapshot_list;
  205. };
  206. struct grub_nilfs2_checkpoint
  207. {
  208. grub_uint32_t cp_flags;
  209. grub_uint32_t cp_checkpoints_count;
  210. struct grub_nilfs2_snapshot_list cp_snapshot_list;
  211. grub_uint64_t cp_cno;
  212. grub_uint64_t cp_create;
  213. grub_uint64_t cp_nblk_inc;
  214. grub_uint64_t cp_inodes_count;
  215. grub_uint64_t cp_blocks_count;
  216. struct grub_nilfs2_inode cp_ifile_inode;
  217. };
  218. #define NILFS_BMAP_LARGE 0x1
  219. #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(grub_uint64_t))
  220. /* nilfs extra padding for nonroot btree node. */
  221. #define NILFS_BTREE_NODE_EXTRA_PAD_SIZE (sizeof(grub_uint64_t))
  222. #define NILFS_BTREE_ROOT_SIZE NILFS_BMAP_SIZE
  223. #define NILFS_BTREE_ROOT_NCHILDREN_MAX \
  224. ((NILFS_BTREE_ROOT_SIZE - sizeof(struct nilfs_btree_node)) / \
  225. (sizeof(grub_uint64_t) + sizeof(grub_uint64_t)) )
  226. struct grub_fshelp_node
  227. {
  228. struct grub_nilfs2_data *data;
  229. struct grub_nilfs2_inode inode;
  230. grub_uint64_t ino;
  231. int inode_read;
  232. };
  233. struct grub_nilfs2_data
  234. {
  235. struct grub_nilfs2_super_block sblock;
  236. struct grub_nilfs2_super_root sroot;
  237. struct grub_nilfs2_inode ifile;
  238. grub_disk_t disk;
  239. struct grub_nilfs2_inode *inode;
  240. struct grub_fshelp_node diropen;
  241. };
  242. /* Log2 size of nilfs2 block in 512 blocks. */
  243. #define LOG2_NILFS2_BLOCK_SIZE(data) \
  244. (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 1)
  245. /* Log2 size of nilfs2 block in bytes. */
  246. #define LOG2_BLOCK_SIZE(data) \
  247. (grub_le_to_cpu32 (data->sblock.s_log_block_size) + 10)
  248. /* The size of an nilfs2 block in bytes. */
  249. #define NILFS2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE (data))
  250. static grub_uint64_t
  251. grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key);
  252. static grub_dl_t my_mod;
  253. static inline unsigned long
  254. grub_nilfs2_palloc_entries_per_group (struct grub_nilfs2_data *data)
  255. {
  256. return 1UL << (LOG2_BLOCK_SIZE (data) + 3);
  257. }
  258. static inline grub_uint64_t
  259. grub_nilfs2_palloc_group (struct grub_nilfs2_data *data,
  260. grub_uint64_t nr, grub_uint32_t * offset)
  261. {
  262. return grub_divmod64 (nr, grub_nilfs2_palloc_entries_per_group (data),
  263. offset);
  264. }
  265. static inline grub_uint32_t
  266. grub_nilfs2_palloc_groups_per_desc_block (struct grub_nilfs2_data *data)
  267. {
  268. return NILFS2_BLOCK_SIZE (data) /
  269. sizeof (struct grub_nilfs2_palloc_group_desc);
  270. }
  271. static inline grub_uint32_t
  272. grub_nilfs2_entries_per_block (struct grub_nilfs2_data *data,
  273. unsigned long entry_size)
  274. {
  275. return NILFS2_BLOCK_SIZE (data) / entry_size;
  276. }
  277. static inline grub_uint32_t
  278. grub_nilfs2_blocks_per_group (struct grub_nilfs2_data *data,
  279. unsigned long entry_size)
  280. {
  281. return grub_div_roundup (grub_nilfs2_palloc_entries_per_group (data),
  282. grub_nilfs2_entries_per_block (data,
  283. entry_size)) + 1;
  284. }
  285. static inline grub_uint32_t
  286. grub_nilfs2_blocks_per_desc_block (struct grub_nilfs2_data *data,
  287. unsigned long entry_size)
  288. {
  289. return grub_nilfs2_palloc_groups_per_desc_block (data) *
  290. grub_nilfs2_blocks_per_group (data, entry_size) + 1;
  291. }
  292. static inline grub_uint32_t
  293. grub_nilfs2_palloc_desc_block_offset (struct grub_nilfs2_data *data,
  294. unsigned long group,
  295. unsigned long entry_size)
  296. {
  297. grub_uint32_t desc_block =
  298. group / grub_nilfs2_palloc_groups_per_desc_block (data);
  299. return desc_block * grub_nilfs2_blocks_per_desc_block (data, entry_size);
  300. }
  301. static inline grub_uint32_t
  302. grub_nilfs2_palloc_bitmap_block_offset (struct grub_nilfs2_data *data,
  303. unsigned long group,
  304. unsigned long entry_size)
  305. {
  306. unsigned long desc_offset = group %
  307. grub_nilfs2_palloc_groups_per_desc_block (data);
  308. return grub_nilfs2_palloc_desc_block_offset (data, group, entry_size) + 1 +
  309. desc_offset * grub_nilfs2_blocks_per_group (data, entry_size);
  310. }
  311. static inline grub_uint32_t
  312. grub_nilfs2_palloc_entry_offset (struct grub_nilfs2_data *data,
  313. grub_uint64_t nr, unsigned long entry_size)
  314. {
  315. unsigned long group;
  316. grub_uint32_t group_offset;
  317. group = grub_nilfs2_palloc_group (data, nr, &group_offset);
  318. return grub_nilfs2_palloc_bitmap_block_offset (data, group,
  319. entry_size) + 1 +
  320. group_offset / grub_nilfs2_entries_per_block (data, entry_size);
  321. }
  322. static inline struct grub_nilfs2_btree_node *
  323. grub_nilfs2_btree_get_root (struct grub_nilfs2_inode *inode)
  324. {
  325. return (struct grub_nilfs2_btree_node *) &inode->i_bmap[0];
  326. }
  327. static inline int
  328. grub_nilfs2_btree_get_level (struct grub_nilfs2_btree_node *node)
  329. {
  330. return node->bn_level;
  331. }
  332. static inline grub_uint64_t *
  333. grub_nilfs2_btree_node_dkeys (struct grub_nilfs2_btree_node *node)
  334. {
  335. return (grub_uint64_t *) ((char *) (node + 1) +
  336. ((node->bn_flags & NILFS_BTREE_NODE_ROOT) ?
  337. 0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE));
  338. }
  339. static inline grub_uint64_t
  340. grub_nilfs2_btree_node_get_key (struct grub_nilfs2_btree_node *node,
  341. int index)
  342. {
  343. return grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dkeys (node) + index));
  344. }
  345. static inline int
  346. grub_nilfs2_btree_node_lookup (struct grub_nilfs2_btree_node *node,
  347. grub_uint64_t key, int *indexp)
  348. {
  349. grub_uint64_t nkey;
  350. int index, low, high, s;
  351. low = 0;
  352. high = grub_le_to_cpu16 (node->bn_nchildren) - 1;
  353. index = 0;
  354. s = 0;
  355. while (low <= high)
  356. {
  357. index = (low + high) / 2;
  358. nkey = grub_nilfs2_btree_node_get_key (node, index);
  359. if (nkey == key)
  360. {
  361. *indexp = index;
  362. return 1;
  363. }
  364. else if (nkey < key)
  365. {
  366. low = index + 1;
  367. s = -1;
  368. }
  369. else
  370. {
  371. high = index - 1;
  372. s = 1;
  373. }
  374. }
  375. if (node->bn_level > NILFS_BTREE_LEVEL_NODE_MIN)
  376. {
  377. if (s > 0 && index > 0)
  378. index--;
  379. }
  380. else if (s < 0)
  381. index++;
  382. *indexp = index;
  383. return s == 0;
  384. }
  385. static inline int
  386. grub_nilfs2_btree_node_nchildren_max (struct grub_nilfs2_data *data,
  387. struct grub_nilfs2_btree_node *node)
  388. {
  389. int node_children_max = ((NILFS2_BLOCK_SIZE (data) -
  390. sizeof (struct grub_nilfs2_btree_node) -
  391. NILFS_BTREE_NODE_EXTRA_PAD_SIZE) /
  392. (sizeof (grub_uint64_t) + sizeof (grub_uint64_t)));
  393. return (node->bn_flags & NILFS_BTREE_NODE_ROOT) ? 3 : node_children_max;
  394. }
  395. static inline grub_uint64_t *
  396. grub_nilfs2_btree_node_dptrs (struct grub_nilfs2_data *data,
  397. struct grub_nilfs2_btree_node *node)
  398. {
  399. return (grub_uint64_t *) (grub_nilfs2_btree_node_dkeys (node) +
  400. grub_nilfs2_btree_node_nchildren_max (data,
  401. node));
  402. }
  403. static inline grub_uint64_t
  404. grub_nilfs2_btree_node_get_ptr (struct grub_nilfs2_data *data,
  405. struct grub_nilfs2_btree_node *node,
  406. int index)
  407. {
  408. return
  409. grub_le_to_cpu64 (*(grub_nilfs2_btree_node_dptrs (data, node) + index));
  410. }
  411. static inline int
  412. grub_nilfs2_btree_get_nonroot_node (struct grub_nilfs2_data *data,
  413. grub_uint64_t ptr, void *block)
  414. {
  415. grub_disk_t disk = data->disk;
  416. unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
  417. return grub_disk_read (disk, ptr * nilfs2_block_count, 0,
  418. NILFS2_BLOCK_SIZE (data), block);
  419. }
  420. static grub_uint64_t
  421. grub_nilfs2_btree_lookup (struct grub_nilfs2_data *data,
  422. struct grub_nilfs2_inode *inode,
  423. grub_uint64_t key, int need_translate)
  424. {
  425. struct grub_nilfs2_btree_node *node;
  426. unsigned char block[NILFS2_BLOCK_SIZE (data)];
  427. grub_uint64_t ptr;
  428. int level, found, index;
  429. node = grub_nilfs2_btree_get_root (inode);
  430. level = grub_nilfs2_btree_get_level (node);
  431. found = grub_nilfs2_btree_node_lookup (node, key, &index);
  432. ptr = grub_nilfs2_btree_node_get_ptr (data, node, index);
  433. if (need_translate)
  434. ptr = grub_nilfs2_dat_translate (data, ptr);
  435. for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--)
  436. {
  437. grub_nilfs2_btree_get_nonroot_node (data, ptr, block);
  438. if (grub_errno)
  439. {
  440. return -1;
  441. }
  442. node = (struct grub_nilfs2_btree_node *) block;
  443. if (node->bn_level != level)
  444. {
  445. grub_error (GRUB_ERR_BAD_FS, "btree level mismatch\n");
  446. return -1;
  447. }
  448. if (!found)
  449. found = grub_nilfs2_btree_node_lookup (node, key, &index);
  450. else
  451. index = 0;
  452. if (index < grub_nilfs2_btree_node_nchildren_max (data, node))
  453. {
  454. ptr = grub_nilfs2_btree_node_get_ptr (data, node, index);
  455. if (need_translate)
  456. ptr = grub_nilfs2_dat_translate (data, ptr);
  457. }
  458. else
  459. {
  460. grub_error (GRUB_ERR_BAD_FS, "btree corruption\n");
  461. return -1;
  462. }
  463. }
  464. if (!found)
  465. return -1;
  466. return ptr;
  467. }
  468. static inline grub_uint64_t
  469. grub_nilfs2_direct_lookup (struct grub_nilfs2_inode *inode, grub_uint64_t key)
  470. {
  471. return grub_le_to_cpu64 (inode->i_bmap[1 + key]);
  472. }
  473. static inline grub_uint64_t
  474. grub_nilfs2_bmap_lookup (struct grub_nilfs2_data *data,
  475. struct grub_nilfs2_inode *inode,
  476. grub_uint64_t key, int need_translate)
  477. {
  478. struct grub_nilfs2_btree_node *root = grub_nilfs2_btree_get_root (inode);
  479. if (root->bn_flags & NILFS_BMAP_LARGE)
  480. return grub_nilfs2_btree_lookup (data, inode, key, need_translate);
  481. else
  482. {
  483. grub_uint64_t ptr;
  484. ptr = grub_nilfs2_direct_lookup (inode, key);
  485. if (need_translate)
  486. ptr = grub_nilfs2_dat_translate (data, ptr);
  487. return ptr;
  488. }
  489. }
  490. static grub_uint64_t
  491. grub_nilfs2_dat_translate (struct grub_nilfs2_data *data, grub_uint64_t key)
  492. {
  493. struct grub_nilfs2_dat_entry entry;
  494. grub_disk_t disk = data->disk;
  495. grub_uint64_t pptr;
  496. grub_uint32_t blockno, offset;
  497. unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
  498. blockno = grub_nilfs2_palloc_entry_offset (data, key,
  499. sizeof (struct
  500. grub_nilfs2_dat_entry));
  501. grub_divmod64 (key * sizeof (struct grub_nilfs2_dat_entry),
  502. NILFS2_BLOCK_SIZE (data), &offset);
  503. pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_dat, blockno, 0);
  504. if (pptr == (grub_uint64_t) - 1)
  505. {
  506. grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
  507. return -1;
  508. }
  509. grub_disk_read (disk, pptr * nilfs2_block_count, offset,
  510. sizeof (struct grub_nilfs2_dat_entry), &entry);
  511. return grub_le_to_cpu64 (entry.de_blocknr);
  512. }
  513. static grub_disk_addr_t
  514. grub_nilfs2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
  515. {
  516. struct grub_nilfs2_data *data = node->data;
  517. struct grub_nilfs2_inode *inode = &node->inode;
  518. grub_uint64_t pptr = -1;
  519. pptr = grub_nilfs2_bmap_lookup (data, inode, fileblock, 1);
  520. if (pptr == (grub_uint64_t) - 1)
  521. {
  522. grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
  523. return -1;
  524. }
  525. return pptr;
  526. }
  527. /* Read LEN bytes from the file described by DATA starting with byte
  528. POS. Return the amount of read bytes in READ. */
  529. static grub_ssize_t
  530. grub_nilfs2_read_file (grub_fshelp_node_t node,
  531. void (*read_hook) (grub_disk_addr_t
  532. sector,
  533. unsigned offset,
  534. unsigned length,
  535. void *closure),
  536. void *closure, int flags,
  537. int pos, grub_size_t len, char *buf)
  538. {
  539. return grub_fshelp_read_file (node->data->disk, node, read_hook, closure,
  540. flags, pos, len, buf, grub_nilfs2_read_block,
  541. grub_le_to_cpu64 (node->inode.i_size),
  542. LOG2_NILFS2_BLOCK_SIZE (node->data));
  543. }
  544. static grub_err_t
  545. grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data,
  546. grub_uint64_t cpno,
  547. struct grub_nilfs2_checkpoint *cpp)
  548. {
  549. grub_uint64_t blockno;
  550. grub_uint32_t offset;
  551. grub_uint64_t pptr;
  552. grub_disk_t disk = data->disk;
  553. unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
  554. /* Assume sizeof(struct grub_nilfs2_cpfile_header) <
  555. sizeof(struct grub_nilfs2_checkpoint).
  556. */
  557. blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) /
  558. sizeof (struct grub_nilfs2_checkpoint), &offset);
  559. pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1);
  560. if (pptr == (grub_uint64_t) - 1)
  561. {
  562. return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
  563. }
  564. return grub_disk_read (disk, pptr * nilfs2_block_count,
  565. offset * sizeof (struct grub_nilfs2_checkpoint),
  566. sizeof (struct grub_nilfs2_checkpoint), cpp);
  567. }
  568. static inline grub_err_t
  569. grub_nilfs2_read_last_checkpoint (struct grub_nilfs2_data *data,
  570. struct grub_nilfs2_checkpoint *cpp)
  571. {
  572. return grub_nilfs2_read_checkpoint (data,
  573. grub_le_to_cpu64 (data->
  574. sblock.s_last_cno),
  575. cpp);
  576. }
  577. /* Read the inode INO for the file described by DATA into INODE. */
  578. static grub_err_t
  579. grub_nilfs2_read_inode (struct grub_nilfs2_data *data,
  580. grub_uint64_t ino, struct grub_nilfs2_inode *inodep)
  581. {
  582. grub_uint64_t blockno;
  583. unsigned int offset;
  584. grub_uint64_t pptr;
  585. grub_disk_t disk = data->disk;
  586. unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
  587. blockno = grub_nilfs2_palloc_entry_offset (data, ino,
  588. sizeof (struct
  589. grub_nilfs2_inode));
  590. grub_divmod64 (sizeof (struct grub_nilfs2_inode) * ino,
  591. NILFS2_BLOCK_SIZE (data), &offset);
  592. pptr = grub_nilfs2_bmap_lookup (data, &data->ifile, blockno, 1);
  593. if (pptr == (grub_uint64_t) - 1)
  594. {
  595. return grub_error (GRUB_ERR_BAD_FS, "btree lookup failure");
  596. }
  597. return grub_disk_read (disk, pptr * nilfs2_block_count, offset,
  598. sizeof (struct grub_nilfs2_inode), inodep);
  599. }
  600. static int
  601. grub_nilfs2_valid_sb (struct grub_nilfs2_super_block *sbp)
  602. {
  603. if (grub_le_to_cpu16 (sbp->s_magic) != NILFS2_SUPER_MAGIC)
  604. return 0;
  605. if (grub_le_to_cpu32 (sbp->s_rev_level) != NILFS_SUPORT_REV)
  606. return 0;
  607. return 1;
  608. }
  609. static struct grub_nilfs2_data *
  610. grub_nilfs2_mount (grub_disk_t disk)
  611. {
  612. struct grub_nilfs2_data *data;
  613. struct grub_nilfs2_segment_summary ss;
  614. struct grub_nilfs2_checkpoint last_checkpoint;
  615. grub_uint64_t last_pseg;
  616. grub_uint32_t nblocks;
  617. unsigned int nilfs2_block_count;
  618. data = grub_malloc (sizeof (struct grub_nilfs2_data));
  619. if (!data)
  620. return 0;
  621. /* Read the superblock. */
  622. grub_disk_read (disk, 1 * 2, 0, sizeof (struct grub_nilfs2_super_block),
  623. &data->sblock);
  624. if (grub_errno)
  625. goto fail;
  626. /* Make sure this is an nilfs2 filesystem. */
  627. if (!grub_nilfs2_valid_sb (&data->sblock))
  628. {
  629. grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
  630. goto fail;
  631. }
  632. nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data));
  633. /* Read the last segment summary. */
  634. last_pseg = grub_le_to_cpu64 (data->sblock.s_last_pseg);
  635. grub_disk_read (disk, last_pseg * nilfs2_block_count, 0,
  636. sizeof (struct grub_nilfs2_segment_summary), &ss);
  637. if (grub_errno)
  638. goto fail;
  639. /* Read the super root block. */
  640. nblocks = grub_le_to_cpu32 (ss.ss_nblocks);
  641. grub_disk_read (disk, (last_pseg + (nblocks - 1)) * nilfs2_block_count, 0,
  642. sizeof (struct grub_nilfs2_super_root), &data->sroot);
  643. if (grub_errno)
  644. goto fail;
  645. data->disk = disk;
  646. grub_nilfs2_read_last_checkpoint (data, &last_checkpoint);
  647. if (grub_errno)
  648. goto fail;
  649. grub_memcpy (&data->ifile, &last_checkpoint.cp_ifile_inode,
  650. sizeof (struct grub_nilfs2_inode));
  651. data->diropen.data = data;
  652. data->diropen.ino = 2;
  653. data->diropen.inode_read = 1;
  654. data->inode = &data->diropen.inode;
  655. grub_nilfs2_read_inode (data, 2, data->inode);
  656. return data;
  657. fail:
  658. if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
  659. grub_error (GRUB_ERR_BAD_FS, "not a nilfs2 filesystem");
  660. grub_free (data);
  661. return 0;
  662. }
  663. static char *
  664. grub_nilfs2_read_symlink (grub_fshelp_node_t node)
  665. {
  666. char *symlink;
  667. struct grub_fshelp_node *diro = node;
  668. if (!diro->inode_read)
  669. {
  670. grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
  671. if (grub_errno)
  672. return 0;
  673. }
  674. symlink = grub_malloc (grub_le_to_cpu64 (diro->inode.i_size) + 1);
  675. if (!symlink)
  676. return 0;
  677. grub_nilfs2_read_file (diro, 0, 0, 0, 0,
  678. grub_le_to_cpu64 (diro->inode.i_size), symlink);
  679. if (grub_errno)
  680. {
  681. grub_free (symlink);
  682. return 0;
  683. }
  684. symlink[grub_le_to_cpu64 (diro->inode.i_size)] = '\0';
  685. return symlink;
  686. }
  687. static int
  688. grub_nilfs2_iterate_dir (grub_fshelp_node_t dir,
  689. int (*hook) (const char *filename,
  690. enum grub_fshelp_filetype filetype,
  691. grub_fshelp_node_t node,
  692. void *closure),
  693. void *closure)
  694. {
  695. unsigned int fpos = 0;
  696. struct grub_fshelp_node *diro = (struct grub_fshelp_node *) dir;
  697. if (!diro->inode_read)
  698. {
  699. grub_nilfs2_read_inode (diro->data, diro->ino, &diro->inode);
  700. if (grub_errno)
  701. return 0;
  702. }
  703. /* Iterate files. */
  704. while (fpos < grub_le_to_cpu64 (diro->inode.i_size))
  705. {
  706. struct grub_nilfs2_dir_entry dirent;
  707. grub_nilfs2_read_file (diro, 0, 0, 0, fpos,
  708. sizeof (struct grub_nilfs2_dir_entry),
  709. (char *) &dirent);
  710. if (grub_errno)
  711. return 0;
  712. if (dirent.rec_len == 0)
  713. return 0;
  714. if (dirent.name_len != 0)
  715. {
  716. char filename[dirent.name_len + 1];
  717. struct grub_fshelp_node *fdiro;
  718. enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
  719. grub_nilfs2_read_file (diro, 0, 0, 0,
  720. fpos + sizeof (struct grub_nilfs2_dir_entry),
  721. dirent.name_len, filename);
  722. if (grub_errno)
  723. return 0;
  724. fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
  725. if (!fdiro)
  726. return 0;
  727. fdiro->data = diro->data;
  728. fdiro->ino = grub_le_to_cpu64 (dirent.inode);
  729. filename[dirent.name_len] = '\0';
  730. if (dirent.file_type != NILFS_FT_UNKNOWN)
  731. {
  732. fdiro->inode_read = 0;
  733. if (dirent.file_type == NILFS_FT_DIR)
  734. type = GRUB_FSHELP_DIR;
  735. else if (dirent.file_type == NILFS_FT_SYMLINK)
  736. type = GRUB_FSHELP_SYMLINK;
  737. else if (dirent.file_type == NILFS_FT_REG_FILE)
  738. type = GRUB_FSHELP_REG;
  739. }
  740. else
  741. {
  742. /* The filetype can not be read from the dirent, read
  743. the inode to get more information. */
  744. grub_nilfs2_read_inode (diro->data,
  745. grub_le_to_cpu64 (dirent.inode),
  746. &fdiro->inode);
  747. if (grub_errno)
  748. {
  749. grub_free (fdiro);
  750. return 0;
  751. }
  752. fdiro->inode_read = 1;
  753. if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
  754. & FILETYPE_INO_MASK) == FILETYPE_INO_DIRECTORY)
  755. type = GRUB_FSHELP_DIR;
  756. else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
  757. & FILETYPE_INO_MASK) == FILETYPE_INO_SYMLINK)
  758. type = GRUB_FSHELP_SYMLINK;
  759. else if ((grub_le_to_cpu16 (fdiro->inode.i_mode)
  760. & FILETYPE_INO_MASK) == FILETYPE_INO_REG)
  761. type = GRUB_FSHELP_REG;
  762. }
  763. if (hook (filename, type, fdiro, closure))
  764. return 1;
  765. }
  766. fpos += grub_le_to_cpu16 (dirent.rec_len);
  767. }
  768. return 0;
  769. }
  770. /* Open a file named NAME and initialize FILE. */
  771. static grub_err_t
  772. grub_nilfs2_open (struct grub_file *file, const char *name)
  773. {
  774. struct grub_nilfs2_data *data = NULL;
  775. struct grub_fshelp_node *fdiro = 0;
  776. grub_dl_ref (my_mod);
  777. data = grub_nilfs2_mount (file->device->disk);
  778. if (!data)
  779. goto fail;
  780. grub_fshelp_find_file (name, &data->diropen, &fdiro,
  781. grub_nilfs2_iterate_dir, 0, grub_nilfs2_read_symlink,
  782. GRUB_FSHELP_REG);
  783. if (grub_errno)
  784. goto fail;
  785. if (!fdiro->inode_read)
  786. {
  787. grub_nilfs2_read_inode (data, fdiro->ino, &fdiro->inode);
  788. if (grub_errno)
  789. goto fail;
  790. }
  791. grub_memcpy (data->inode, &fdiro->inode, sizeof (struct grub_nilfs2_inode));
  792. grub_free (fdiro);
  793. file->size = grub_le_to_cpu64 (data->inode->i_size);
  794. file->data = data;
  795. file->offset = 0;
  796. return 0;
  797. fail:
  798. if (fdiro != &data->diropen)
  799. grub_free (fdiro);
  800. grub_free (data);
  801. grub_dl_unref (my_mod);
  802. return grub_errno;
  803. }
  804. static grub_err_t
  805. grub_nilfs2_close (grub_file_t file)
  806. {
  807. grub_free (file->data);
  808. grub_dl_unref (my_mod);
  809. return GRUB_ERR_NONE;
  810. }
  811. /* Read LEN bytes data from FILE into BUF. */
  812. static grub_ssize_t
  813. grub_nilfs2_read (grub_file_t file, char *buf, grub_size_t len)
  814. {
  815. struct grub_nilfs2_data *data = (struct grub_nilfs2_data *) file->data;
  816. return grub_nilfs2_read_file (&data->diropen, file->read_hook, file->closure,
  817. file->flags, file->offset, len, buf);
  818. }
  819. struct grub_nilfs2_dir_closure
  820. {
  821. int (*hook) (const char *filename,
  822. const struct grub_dirhook_info *info,
  823. void *closure);
  824. void *closure;
  825. struct grub_nilfs2_data *data;
  826. };
  827. static int
  828. iterate (const char *filename,
  829. enum grub_fshelp_filetype filetype,
  830. grub_fshelp_node_t node,
  831. void *closure)
  832. {
  833. struct grub_nilfs2_dir_closure *c = closure;
  834. struct grub_dirhook_info info;
  835. grub_memset (&info, 0, sizeof (info));
  836. if (!node->inode_read)
  837. {
  838. grub_nilfs2_read_inode (c->data, node->ino, &node->inode);
  839. if (!grub_errno)
  840. node->inode_read = 1;
  841. grub_errno = GRUB_ERR_NONE;
  842. }
  843. if (node->inode_read)
  844. {
  845. info.mtimeset = 1;
  846. info.mtime = grub_le_to_cpu64 (node->inode.i_mtime);
  847. }
  848. info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
  849. grub_free (node);
  850. return c->hook (filename, &info, c->closure);
  851. }
  852. static grub_err_t
  853. grub_nilfs2_dir (grub_device_t device, const char *path,
  854. int (*hook) (const char *filename,
  855. const struct grub_dirhook_info * info,
  856. void *closure),
  857. void *closure)
  858. {
  859. struct grub_nilfs2_data *data = 0;
  860. struct grub_fshelp_node *fdiro = 0;
  861. struct grub_nilfs2_dir_closure c;
  862. grub_dl_ref (my_mod);
  863. data = grub_nilfs2_mount (device->disk);
  864. if (!data)
  865. goto fail;
  866. grub_fshelp_find_file (path, &data->diropen, &fdiro,
  867. grub_nilfs2_iterate_dir, 0, grub_nilfs2_read_symlink,
  868. GRUB_FSHELP_DIR);
  869. if (grub_errno)
  870. goto fail;
  871. c.hook = hook;
  872. c.closure = closure;
  873. c.data = data;
  874. grub_nilfs2_iterate_dir (fdiro, iterate, &c);
  875. fail:
  876. if (fdiro != &data->diropen)
  877. grub_free (fdiro);
  878. grub_free (data);
  879. grub_dl_unref (my_mod);
  880. return grub_errno;
  881. }
  882. static grub_err_t
  883. grub_nilfs2_label (grub_device_t device, char **label)
  884. {
  885. struct grub_nilfs2_data *data;
  886. grub_disk_t disk = device->disk;
  887. grub_dl_ref (my_mod);
  888. data = grub_nilfs2_mount (disk);
  889. if (data)
  890. *label = grub_strndup (data->sblock.s_volume_name, 14);
  891. else
  892. *label = NULL;
  893. grub_dl_unref (my_mod);
  894. grub_free (data);
  895. return grub_errno;
  896. }
  897. static grub_err_t
  898. grub_nilfs2_uuid (grub_device_t device, char **uuid)
  899. {
  900. struct grub_nilfs2_data *data;
  901. grub_disk_t disk = device->disk;
  902. grub_dl_ref (my_mod);
  903. data = grub_nilfs2_mount (disk);
  904. if (data)
  905. {
  906. *uuid =
  907. grub_xasprintf
  908. ("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%0x-%02x%02x%02x%02x%02x%02x",
  909. data->sblock.s_uuid[0], data->sblock.s_uuid[1],
  910. data->sblock.s_uuid[2], data->sblock.s_uuid[3],
  911. data->sblock.s_uuid[4], data->sblock.s_uuid[5],
  912. data->sblock.s_uuid[6], data->sblock.s_uuid[7],
  913. data->sblock.s_uuid[8], data->sblock.s_uuid[9],
  914. data->sblock.s_uuid[10], data->sblock.s_uuid[11],
  915. data->sblock.s_uuid[12], data->sblock.s_uuid[13],
  916. data->sblock.s_uuid[14], data->sblock.s_uuid[15]);
  917. }
  918. else
  919. *uuid = NULL;
  920. grub_dl_unref (my_mod);
  921. grub_free (data);
  922. return grub_errno;
  923. }
  924. /* Get mtime. */
  925. static grub_err_t
  926. grub_nilfs2_mtime (grub_device_t device, grub_int32_t * tm)
  927. {
  928. struct grub_nilfs2_data *data;
  929. grub_disk_t disk = device->disk;
  930. grub_dl_ref (my_mod);
  931. data = grub_nilfs2_mount (disk);
  932. if (!data)
  933. *tm = 0;
  934. else
  935. *tm = (grub_int32_t) grub_le_to_cpu64 (data->sblock.s_mtime);
  936. grub_dl_unref (my_mod);
  937. grub_free (data);
  938. return grub_errno;
  939. }
  940. static struct grub_fs grub_nilfs2_fs = {
  941. .name = "nilfs2",
  942. .dir = grub_nilfs2_dir,
  943. .open = grub_nilfs2_open,
  944. .read = grub_nilfs2_read,
  945. .close = grub_nilfs2_close,
  946. .label = grub_nilfs2_label,
  947. .uuid = grub_nilfs2_uuid,
  948. .mtime = grub_nilfs2_mtime,
  949. #ifdef GRUB_UTIL
  950. .reserved_first_sector = 1,
  951. #endif
  952. .next = 0
  953. };
  954. GRUB_MOD_INIT (nilfs2)
  955. {
  956. grub_fs_register (&grub_nilfs2_fs);
  957. my_mod = mod;
  958. }
  959. GRUB_MOD_FINI (nilfs2)
  960. {
  961. grub_fs_unregister (&grub_nilfs2_fs);
  962. }