Whamcloud - gitweb
ChangeLog, Makefile.in, mkjournal.c:
[tools/e2fsprogs.git] / lib / ext2fs / mkjournal.c
1 /*
2  * mkjournal.c --- make a journal for a filesystem
3  *
4  * Copyright (C) 2000 Theodore Ts'o.
5  * 
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
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_NETINET_IN_H
29 #include <netinet/in.h>
30 #endif
31
32 #if EXT2_FLAT_INCLUDES
33 #include "ext2_fs.h"
34 #else
35 #include <linux/ext2_fs.h>
36 #endif
37
38 #include "ext2fs.h"
39 #include "jfs_user.h"
40
41 static void init_journal_superblock(journal_superblock_t *jsb,
42                                     __u32 blocksize, __u32 size, int flags)
43 {
44         memset (jsb, 0, sizeof(*jsb));
45
46         jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
47         if (flags & EXT2_MKJOURNAL_V1_SUPER)
48                 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
49         else
50                 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
51         jsb->s_blocksize = htonl(blocksize);
52         jsb->s_maxlen = htonl(size);
53         jsb->s_first = htonl(1);
54         jsb->s_sequence = htonl(1);
55 }
56
57 /*
58  * This function writes a journal using POSIX routines.  It is used
59  * for creating external journals and creating journals on live
60  * filesystems.
61  */
62 static errcode_t write_journal_file(ext2_filsys fs, char *device,
63                                     blk_t size, int flags)
64 {
65         errcode_t       retval;
66         char            *buf = 0;
67         journal_superblock_t    jsb;
68         int             i, fd, ret_size;
69
70         init_journal_superblock(&jsb, fs->blocksize, size, flags);
71
72         /* Create a block buffer */
73         buf = malloc(fs->blocksize);
74         if (!buf)
75                 return ENOMEM;
76
77         /* Open the device */
78         if ((fd = open(device, O_WRONLY)) < 0) {
79                 retval = errno;
80                 goto errout;
81         }
82
83         /* Write the superblock out */
84         memset(buf, 0, fs->blocksize);
85         memcpy(buf, &jsb, sizeof(jsb));
86         retval = EXT2_ET_SHORT_WRITE;
87         ret_size = write(fd, buf, fs->blocksize);
88         if (ret_size < 0) {
89                 errno = retval;
90                 goto errout;
91         }
92         if (ret_size != fs->blocksize)
93                 goto errout;
94         memset(buf, 0, fs->blocksize);
95
96         for (i = 1; i < size; i++) {
97                 ret_size = write(fd, buf, fs->blocksize);
98                 if (ret_size < 0) {
99                         retval = errno;
100                         goto errout;
101                 }
102                 if (ret_size != fs->blocksize)
103                         goto errout;
104         }
105         close(fd);
106
107         retval = 0;
108 errout:
109         free(buf);
110         return retval;
111 }
112
113 /*
114  * Helper function for creating the journal using direct I/O routines
115  */
116 struct mkjournal_struct {
117         int             num_blocks;
118         int             newblocks;
119         char            *buf;
120         errcode_t       err;
121 };
122
123 static int mkjournal_proc(ext2_filsys           fs,
124                            blk_t                *blocknr,
125                            e2_blkcnt_t          blockcnt,
126                            blk_t                ref_block,
127                            int                  ref_offset,
128                            void                 *priv_data)
129 {
130         struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
131         blk_t   new_blk;
132         static blk_t    last_blk = 0;
133         char            *block;
134         errcode_t       retval;
135         int             group;
136         
137         if (*blocknr) {
138                 last_blk = *blocknr;
139                 return 0;
140         }
141         retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
142         if (retval) {
143                 es->err = retval;
144                 return BLOCK_ABORT;
145         }
146         if (blockcnt > 0)
147                 es->num_blocks--;
148
149         es->newblocks++;
150         retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
151
152         if (blockcnt == 0)
153                 memset(es->buf, 0, fs->blocksize);
154
155         if (retval) {
156                 es->err = retval;
157                 return BLOCK_ABORT;
158         }
159         *blocknr = new_blk;
160         ext2fs_mark_block_bitmap(fs->block_map, new_blk);
161         ext2fs_mark_bb_dirty(fs);
162         group = ext2fs_group_of_blk(fs, new_blk);
163         fs->group_desc[group].bg_free_blocks_count--;
164         fs->super->s_free_blocks_count--;
165         ext2fs_mark_super_dirty(fs);
166
167         if (es->num_blocks == 0)
168                 return (BLOCK_CHANGED | BLOCK_ABORT);
169         else
170                 return BLOCK_CHANGED;
171         
172 }
173
174 /*
175  * This function creates a journal using direct I/O routines.
176  */
177 static errcode_t write_journal_inode(ext2_filsys fs, ino_t journal_ino,
178                                      blk_t size, int flags)
179 {
180         journal_superblock_t    jsb;
181         errcode_t               retval;
182         struct ext2_inode       inode;
183         struct mkjournal_struct es;
184         char                    *buf;
185
186         init_journal_superblock(&jsb, fs->blocksize, size, flags);
187
188         if ((retval = ext2fs_read_bitmaps(fs)))
189                 return retval;
190
191         if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
192                 return retval;
193
194         if (inode.i_blocks > 0)
195                 return EEXIST;
196
197         /* Create the block buffer */
198         buf = malloc(fs->blocksize);
199         if (!buf)
200                 return ENOMEM;
201
202         memset(buf, 0, fs->blocksize);
203         memcpy(buf, &jsb, sizeof(jsb));
204
205         es.num_blocks = size;
206         es.newblocks = 0;
207         es.buf = buf;
208         es.err = 0;
209
210         retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
211                                        0, mkjournal_proc, &es);
212         free(buf);
213         if (es.err)
214                 return es.err;
215
216         if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
217                 return retval;
218
219         inode.i_size += fs->blocksize * size;
220         inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
221         inode.i_mtime = inode.i_ctime = time(0);
222         inode.i_links_count = 1;
223         inode.i_mode = LINUX_S_IFREG | 0600;
224
225         if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
226                 return retval;
227
228         return 0;
229 }
230
231 /*
232  * This function adds a journal device to a filesystem
233  */
234 errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device,
235                                     blk_t size, int flags)
236 {
237         struct stat     st;
238         errcode_t       retval;
239         blk_t           dev_size;
240
241         /* Make sure the device exists and is a block device */
242         if (stat(device, &st) < 0)
243                 return errno;
244         if (!S_ISBLK(st.st_mode))
245                 return EXT2_JOURNAL_NOT_BLOCK;  /* Must be a block device */
246
247         /* Get the size of the device */
248         if ((retval = ext2fs_get_device_size(device, fs->blocksize,
249                                              &dev_size)))
250                 return retval;
251
252         if (!size)
253                 size = dev_size; /* Default to the size of the device */
254         else if (size > dev_size)
255                 return EINVAL;  /* Requested size bigger than device */
256
257         retval = write_journal_file(fs, device, size, flags);
258         if (retval)
259                 return retval;
260         
261         fs->super->s_journal_inum = 0;
262         fs->super->s_journal_dev = st.st_rdev;
263         memset(fs->super->s_journal_uuid, 0,
264                sizeof(fs->super->s_journal_uuid));
265         fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
266         ext2fs_mark_super_dirty(fs);
267 }
268
269 /*
270  * This function adds a journal inode to a filesystem, using either
271  * POSIX routines if the filesystem is mounted, or using direct I/O
272  * functions if it is not.
273  */
274 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
275 {
276         errcode_t               retval;
277         ino_t                   journal_ino;
278         struct stat             st;
279         char                    jfile[1024];
280         int                     fd, mount_flags;
281
282         if (retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
283                                               jfile, sizeof(jfile)-10))
284                 return retval;
285
286         if (mount_flags & EXT2_MF_MOUNTED) {
287                 strcat(jfile, "/.journal");
288
289                 /* Create the journal file */
290                 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
291                         return errno;
292                 close(fd);
293
294                 if ((retval = write_journal_file(fs, jfile, size, flags)))
295                         return retval;
296
297                 /* Get inode number of the journal file */
298                 if (stat(jfile, &st) < 0)
299                         return errno;
300
301                 if ((retval = fsetflags(jfile,
302                                         EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL)))
303                         return retval;
304                 
305                 journal_ino = st.st_ino;
306         } else {
307                 journal_ino = EXT2_JOURNAL_INO;
308                 if ((retval = write_journal_inode(fs, journal_ino,
309                                                   size, flags)))
310                         return retval;
311         }
312         
313         fs->super->s_journal_inum = journal_ino;
314         fs->super->s_journal_dev = 0;
315         memset(fs->super->s_journal_uuid, 0,
316                sizeof(fs->super->s_journal_uuid));
317         fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
318
319         ext2fs_mark_super_dirty(fs);
320         return 0;
321 }
322
323 #ifdef DEBUG
324 main(int argc, char **argv)
325 {
326         errcode_t       retval;
327         char            *device_name;
328         ext2_filsys     fs;
329
330         if (argc < 2) {
331                 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
332                 exit(1);
333         }
334         device_name = argv[1];
335         
336         retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
337                               unix_io_manager, &fs);
338         if (retval) {
339                 com_err(argv[0], retval, "while opening %s", device_name);
340                 exit(1);
341         }
342
343         retval = ext2fs_add_journal_inode(fs, 1024);
344         if (retval) {
345                 com_err(argv[0], retval, "while adding journal to %s",
346                         device_name);
347                 exit(1);
348         }
349         retval = ext2fs_flush(fs);
350         if (retval) {
351                 printf("Warning, had trouble writing out superblocks.\n");
352         }
353         ext2fs_close(fs);
354         exit(0);
355         
356 }
357 #endif