mkjournal.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * mkjournal.c --- make a journal for a filesystem
  4. *
  5. * Copyright (C) 2000 Theodore Ts'o.
  6. *
  7. * %Begin-Header%
  8. * This file may be redistributed under the terms of the GNU Public
  9. * License.
  10. * %End-Header%
  11. */
  12. #include <stdio.h>
  13. #include <string.h>
  14. #if HAVE_UNISTD_H
  15. #include <unistd.h>
  16. #endif
  17. #if HAVE_ERRNO_H
  18. #include <errno.h>
  19. #endif
  20. #include <fcntl.h>
  21. #include <time.h>
  22. #if HAVE_SYS_STAT_H
  23. #include <sys/stat.h>
  24. #endif
  25. #if HAVE_SYS_TYPES_H
  26. #include <sys/types.h>
  27. #endif
  28. #if HAVE_SYS_IOCTL_H
  29. #include <sys/ioctl.h>
  30. #endif
  31. #if HAVE_NETINET_IN_H
  32. #include <netinet/in.h>
  33. #endif
  34. #include "ext2_fs.h"
  35. #include "../e2p/e2p.h"
  36. #include "../e2fsck.h"
  37. #include "ext2fs.h"
  38. #include "kernel-jbd.h"
  39. /*
  40. * This function automatically sets up the journal superblock and
  41. * returns it as an allocated block.
  42. */
  43. errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
  44. __u32 size, int flags,
  45. char **ret_jsb)
  46. {
  47. errcode_t retval;
  48. journal_superblock_t *jsb;
  49. if (size < 1024)
  50. return EXT2_ET_JOURNAL_TOO_SMALL;
  51. if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
  52. return retval;
  53. memset (jsb, 0, fs->blocksize);
  54. jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
  55. if (flags & EXT2_MKJOURNAL_V1_SUPER)
  56. jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
  57. else
  58. jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
  59. jsb->s_blocksize = htonl(fs->blocksize);
  60. jsb->s_maxlen = htonl(size);
  61. jsb->s_nr_users = htonl(1);
  62. jsb->s_first = htonl(1);
  63. jsb->s_sequence = htonl(1);
  64. memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
  65. /*
  66. * If we're creating an external journal device, we need to
  67. * adjust these fields.
  68. */
  69. if (fs->super->s_feature_incompat &
  70. EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
  71. jsb->s_nr_users = 0;
  72. if (fs->blocksize == 1024)
  73. jsb->s_first = htonl(3);
  74. else
  75. jsb->s_first = htonl(2);
  76. }
  77. *ret_jsb = (char *) jsb;
  78. return 0;
  79. }
  80. /*
  81. * This function writes a journal using POSIX routines. It is used
  82. * for creating external journals and creating journals on live
  83. * filesystems.
  84. */
  85. static errcode_t write_journal_file(ext2_filsys fs, char *filename,
  86. blk_t size, int flags)
  87. {
  88. errcode_t retval;
  89. char *buf = NULL;
  90. int fd, ret_size;
  91. blk_t i;
  92. if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
  93. return retval;
  94. /* Open the device or journal file */
  95. if ((fd = open(filename, O_WRONLY)) < 0) {
  96. retval = errno;
  97. goto errout;
  98. }
  99. /* Write the superblock out */
  100. retval = EXT2_ET_SHORT_WRITE;
  101. ret_size = write(fd, buf, fs->blocksize);
  102. if (ret_size < 0) {
  103. retval = errno;
  104. goto errout;
  105. }
  106. if (ret_size != (int) fs->blocksize)
  107. goto errout;
  108. memset(buf, 0, fs->blocksize);
  109. for (i = 1; i < size; i++) {
  110. ret_size = write(fd, buf, fs->blocksize);
  111. if (ret_size < 0) {
  112. retval = errno;
  113. goto errout;
  114. }
  115. if (ret_size != (int) fs->blocksize)
  116. goto errout;
  117. }
  118. close(fd);
  119. retval = 0;
  120. errout:
  121. ext2fs_free_mem(&buf);
  122. return retval;
  123. }
  124. /*
  125. * Helper function for creating the journal using direct I/O routines
  126. */
  127. struct mkjournal_struct {
  128. int num_blocks;
  129. int newblocks;
  130. char *buf;
  131. errcode_t err;
  132. };
  133. static int mkjournal_proc(ext2_filsys fs,
  134. blk_t *blocknr,
  135. e2_blkcnt_t blockcnt,
  136. blk_t ref_block EXT2FS_ATTR((unused)),
  137. int ref_offset EXT2FS_ATTR((unused)),
  138. void *priv_data)
  139. {
  140. struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
  141. blk_t new_blk;
  142. static blk_t last_blk = 0;
  143. errcode_t retval;
  144. if (*blocknr) {
  145. last_blk = *blocknr;
  146. return 0;
  147. }
  148. retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
  149. if (retval) {
  150. es->err = retval;
  151. return BLOCK_ABORT;
  152. }
  153. if (blockcnt > 0)
  154. es->num_blocks--;
  155. es->newblocks++;
  156. retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
  157. if (blockcnt == 0)
  158. memset(es->buf, 0, fs->blocksize);
  159. if (retval) {
  160. es->err = retval;
  161. return BLOCK_ABORT;
  162. }
  163. *blocknr = new_blk;
  164. last_blk = new_blk;
  165. ext2fs_block_alloc_stats(fs, new_blk, +1);
  166. if (es->num_blocks == 0)
  167. return (BLOCK_CHANGED | BLOCK_ABORT);
  168. else
  169. return BLOCK_CHANGED;
  170. }
  171. /*
  172. * This function creates a journal using direct I/O routines.
  173. */
  174. static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
  175. blk_t size, int flags)
  176. {
  177. char *buf;
  178. errcode_t retval;
  179. struct ext2_inode inode;
  180. struct mkjournal_struct es;
  181. if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
  182. return retval;
  183. if ((retval = ext2fs_read_bitmaps(fs)))
  184. return retval;
  185. if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
  186. return retval;
  187. if (inode.i_blocks > 0)
  188. return EEXIST;
  189. es.num_blocks = size;
  190. es.newblocks = 0;
  191. es.buf = buf;
  192. es.err = 0;
  193. retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
  194. 0, mkjournal_proc, &es);
  195. if (es.err) {
  196. retval = es.err;
  197. goto errout;
  198. }
  199. if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
  200. goto errout;
  201. inode.i_size += fs->blocksize * size;
  202. inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
  203. inode.i_mtime = inode.i_ctime = time(NULL);
  204. inode.i_links_count = 1;
  205. inode.i_mode = LINUX_S_IFREG | 0600;
  206. if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
  207. goto errout;
  208. retval = 0;
  209. memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
  210. fs->super->s_jnl_blocks[16] = inode.i_size;
  211. fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
  212. ext2fs_mark_super_dirty(fs);
  213. errout:
  214. ext2fs_free_mem(&buf);
  215. return retval;
  216. }
  217. /*
  218. * This function adds a journal device to a filesystem
  219. */
  220. errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
  221. {
  222. struct stat st;
  223. errcode_t retval;
  224. char buf[1024];
  225. journal_superblock_t *jsb;
  226. int start;
  227. __u32 i, nr_users;
  228. /* Make sure the device exists and is a block device */
  229. if (stat(journal_dev->device_name, &st) < 0)
  230. return errno;
  231. if (!S_ISBLK(st.st_mode))
  232. return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
  233. /* Get the journal superblock */
  234. start = 1;
  235. if (journal_dev->blocksize == 1024)
  236. start++;
  237. if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
  238. return retval;
  239. jsb = (journal_superblock_t *) buf;
  240. if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
  241. (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
  242. return EXT2_ET_NO_JOURNAL_SB;
  243. if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
  244. return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
  245. /* Check and see if this filesystem has already been added */
  246. nr_users = ntohl(jsb->s_nr_users);
  247. for (i=0; i < nr_users; i++) {
  248. if (memcmp(fs->super->s_uuid,
  249. &jsb->s_users[i*16], 16) == 0)
  250. break;
  251. }
  252. if (i >= nr_users) {
  253. memcpy(&jsb->s_users[nr_users*16],
  254. fs->super->s_uuid, 16);
  255. jsb->s_nr_users = htonl(nr_users+1);
  256. }
  257. /* Writeback the journal superblock */
  258. if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
  259. return retval;
  260. fs->super->s_journal_inum = 0;
  261. fs->super->s_journal_dev = st.st_rdev;
  262. memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
  263. sizeof(fs->super->s_journal_uuid));
  264. fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
  265. ext2fs_mark_super_dirty(fs);
  266. return 0;
  267. }
  268. /*
  269. * This function adds a journal inode to a filesystem, using either
  270. * POSIX routines if the filesystem is mounted, or using direct I/O
  271. * functions if it is not.
  272. */
  273. errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
  274. {
  275. errcode_t retval;
  276. ext2_ino_t journal_ino;
  277. struct stat st;
  278. char jfile[1024];
  279. int fd, mount_flags, f;
  280. retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
  281. jfile, sizeof(jfile)-10);
  282. if (retval)
  283. return retval;
  284. if (mount_flags & EXT2_MF_MOUNTED) {
  285. strcat(jfile, "/.journal");
  286. /*
  287. * If .../.journal already exists, make sure any
  288. * immutable or append-only flags are cleared.
  289. */
  290. #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
  291. (void) chflags (jfile, 0);
  292. #else
  293. #if HAVE_EXT2_IOCTLS
  294. fd = open(jfile, O_RDONLY);
  295. if (fd >= 0) {
  296. f = 0;
  297. ioctl(fd, EXT2_IOC_SETFLAGS, &f);
  298. close(fd);
  299. }
  300. #endif
  301. #endif
  302. /* Create the journal file */
  303. if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
  304. return errno;
  305. if ((retval = write_journal_file(fs, jfile, size, flags)))
  306. goto errout;
  307. /* Get inode number of the journal file */
  308. if (fstat(fd, &st) < 0)
  309. goto errout;
  310. #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
  311. retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
  312. #else
  313. #if HAVE_EXT2_IOCTLS
  314. f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
  315. retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
  316. #endif
  317. #endif
  318. if (retval)
  319. goto errout;
  320. close(fd);
  321. journal_ino = st.st_ino;
  322. } else {
  323. journal_ino = EXT2_JOURNAL_INO;
  324. if ((retval = write_journal_inode(fs, journal_ino,
  325. size, flags)))
  326. return retval;
  327. }
  328. fs->super->s_journal_inum = journal_ino;
  329. fs->super->s_journal_dev = 0;
  330. memset(fs->super->s_journal_uuid, 0,
  331. sizeof(fs->super->s_journal_uuid));
  332. fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
  333. ext2fs_mark_super_dirty(fs);
  334. return 0;
  335. errout:
  336. close(fd);
  337. return retval;
  338. }
  339. #ifdef DEBUG
  340. main(int argc, char **argv)
  341. {
  342. errcode_t retval;
  343. char *device_name;
  344. ext2_filsys fs;
  345. if (argc < 2) {
  346. fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
  347. exit(1);
  348. }
  349. device_name = argv[1];
  350. retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
  351. unix_io_manager, &fs);
  352. if (retval) {
  353. com_err(argv[0], retval, "while opening %s", device_name);
  354. exit(1);
  355. }
  356. retval = ext2fs_add_journal_inode(fs, 1024);
  357. if (retval) {
  358. com_err(argv[0], retval, "while adding journal to %s",
  359. device_name);
  360. exit(1);
  361. }
  362. retval = ext2fs_flush(fs);
  363. if (retval) {
  364. printf("Warning, had trouble writing out superblocks.\n");
  365. }
  366. ext2fs_close(fs);
  367. exit(0);
  368. }
  369. #endif