Whamcloud - gitweb
Avoid some potential inode cache coherency problem caused by using the
[tools/e2fsprogs.git] / e2fsck / swapfs.c
1 /*
2  * swapfs.c --- byte-swap an ext2 filesystem
3  *
4  * Copyright 1996, 1997 by 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
13 #ifdef HAVE_ERRNO_H
14 #include <errno.h>
15 #endif
16 #include <et/com_err.h>
17 #include "e2fsck.h"
18
19 #ifdef ENABLE_SWAPFS
20
21 struct swap_block_struct {
22         ext2_ino_t      ino;
23         int             isdir;
24         errcode_t       errcode;
25         char            *dir_buf;
26         struct ext2_inode *inode;
27 };
28
29 /*
30  * This is a helper function for block_iterate.  We mark all of the
31  * indirect and direct blocks as changed, so that block_iterate will
32  * write them out.
33  */
34 static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
35                       void *priv_data)
36 {
37         errcode_t       retval;
38         
39         struct swap_block_struct *sb = (struct swap_block_struct *) priv_data;
40
41         if (sb->isdir && (blockcnt >= 0) && *block_nr) {
42                 retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
43                 if (retval) {
44                         sb->errcode = retval;
45                         return BLOCK_ABORT;
46                 }
47                 retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
48                 if (retval) {
49                         sb->errcode = retval;
50                         return BLOCK_ABORT;
51                 }
52         }
53         if (blockcnt >= 0) {
54                 if (blockcnt < EXT2_NDIR_BLOCKS)
55                         return 0;
56                 return BLOCK_CHANGED;
57         }
58         if (blockcnt == BLOCK_COUNT_IND) {
59                 if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
60                         return 0;
61                 return BLOCK_CHANGED;
62         }
63         if (blockcnt == BLOCK_COUNT_DIND) {
64                 if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
65                         return 0;
66                 return BLOCK_CHANGED;
67         }
68         if (blockcnt == BLOCK_COUNT_TIND) {
69                 if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
70                         return 0;
71                 return BLOCK_CHANGED;
72         }
73         return BLOCK_CHANGED;
74 }
75
76 /*
77  * This function is responsible for byte-swapping all of the indirect,
78  * block pointers.  It is also responsible for byte-swapping directories.
79  */
80 static void swap_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, char *block_buf,
81                               struct ext2_inode *inode)
82 {
83         errcode_t                       retval;
84         struct swap_block_struct        sb;
85
86         sb.ino = ino;
87         sb.inode = inode;
88         sb.dir_buf = block_buf + ctx->fs->blocksize*3;
89         sb.errcode = 0;
90         sb.isdir = 0;
91         if (LINUX_S_ISDIR(inode->i_mode))
92                 sb.isdir = 1;
93
94         retval = ext2fs_block_iterate(ctx->fs, ino, 0, block_buf,
95                                       swap_block, &sb);
96         if (retval) {
97                 com_err("swap_inode_blocks", retval,
98                         _("while calling ext2fs_block_iterate"));
99                 ctx->flags |= E2F_FLAG_ABORT;
100                 return;
101         }
102         if (sb.errcode) {
103                 com_err("swap_inode_blocks", sb.errcode,
104                         _("while calling iterator function"));
105                 ctx->flags |= E2F_FLAG_ABORT;
106                 return;
107         }
108 }
109
110 static void swap_inodes(e2fsck_t ctx)
111 {
112         ext2_filsys fs = ctx->fs;
113         dgrp_t                  group;
114         unsigned int            i;
115         ext2_ino_t              ino = 1;
116         char                    *buf, *block_buf;
117         errcode_t               retval;
118         struct ext2_inode *     inode;
119
120         e2fsck_use_inode_shortcuts(ctx, 1);
121         
122         retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group,
123                                 &buf);
124         if (retval) {
125                 com_err("swap_inodes", retval,
126                         _("while allocating inode buffer"));
127                 ctx->flags |= E2F_FLAG_ABORT;
128                 return;
129         }
130         block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
131                                                     "block interate buffer");
132         for (group = 0; group < fs->group_desc_count; group++) {
133                 retval = io_channel_read_blk(fs->io,
134                       fs->group_desc[group].bg_inode_table,
135                       fs->inode_blocks_per_group, buf);
136                 if (retval) {
137                         com_err("swap_inodes", retval,
138                                 _("while reading inode table (group %d)"),
139                                 group);
140                         ctx->flags |= E2F_FLAG_ABORT;
141                         return;
142                 }
143                 inode = (struct ext2_inode *) buf;
144                 for (i=0; i < fs->super->s_inodes_per_group;
145                      i++, ino++, inode++) {
146                         ctx->stashed_ino = ino;
147                         ctx->stashed_inode = inode;
148                         
149                         if (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)
150                                 ext2fs_swap_inode(fs, inode, inode, 0);
151                         
152                         /*
153                          * Skip deleted files.
154                          */
155                         if (inode->i_links_count == 0)
156                                 continue;
157                         
158                         if (LINUX_S_ISDIR(inode->i_mode) ||
159                             ((inode->i_block[EXT2_IND_BLOCK] ||
160                               inode->i_block[EXT2_DIND_BLOCK] ||
161                               inode->i_block[EXT2_TIND_BLOCK]) &&
162                              ext2fs_inode_has_valid_blocks(inode)))
163                                 swap_inode_blocks(ctx, ino, block_buf, inode);
164
165                         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
166                                 return;
167                         
168                         if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
169                                 ext2fs_swap_inode(fs, inode, inode, 1);
170                 }
171                 retval = io_channel_write_blk(fs->io,
172                       fs->group_desc[group].bg_inode_table,
173                       fs->inode_blocks_per_group, buf);
174                 if (retval) {
175                         com_err("swap_inodes", retval,
176                                 _("while writing inode table (group %d)"),
177                                 group);
178                         ctx->flags |= E2F_FLAG_ABORT;
179                         return;
180                 }
181         }
182         ext2fs_free_mem(&buf);
183         ext2fs_free_mem(&block_buf);
184         e2fsck_use_inode_shortcuts(ctx, 0);
185         ext2fs_flush_icache(fs);
186 }
187
188 #if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
189 /*
190  * On the PowerPC, the big-endian variant of the ext2 filesystem
191  * has its bitmaps stored as 32-bit words with bit 0 as the LSB
192  * of each word.  Thus a bitmap with only bit 0 set would be, as
193  * a string of bytes, 00 00 00 01 00 ...
194  * To cope with this, we byte-reverse each word of a bitmap if
195  * we have a big-endian filesystem, that is, if we are *not*
196  * byte-swapping other word-sized numbers.
197  */
198 #define EXT2_BIG_ENDIAN_BITMAPS
199 #endif
200
201 #ifdef EXT2_BIG_ENDIAN_BITMAPS
202 static void ext2fs_swap_bitmap(ext2fs_generic_bitmap bmap)
203 {
204         __u32 *p = (__u32 *) bmap->bitmap;
205         int n, nbytes = (bmap->end - bmap->start + 7) / 8;
206                 
207         for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
208                 *p = ext2fs_swab32(*p);
209 }
210 #endif
211
212
213 void swap_filesys(e2fsck_t ctx)
214 {
215         ext2_filsys fs = ctx->fs;
216 #ifdef RESOURCE_TRACK
217         struct resource_track   rtrack;
218
219         init_resource_track(&rtrack);
220 #endif
221
222         if (!(ctx->options & E2F_OPT_PREEN))
223                 printf(_("Pass 0: Doing byte-swap of filesystem\n"));
224         
225 #ifdef MTRACE
226         mtrace_print("Byte swap");
227 #endif
228
229         if (fs->super->s_mnt_count) {
230                 fprintf(stderr, _("%s: the filesystem must be freshly "
231                         "checked using fsck\n"
232                         "and not mounted before trying to "
233                         "byte-swap it.\n"), ctx->device_name);
234                 ctx->flags |= E2F_FLAG_ABORT;
235                 return;
236         }
237         if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
238                 fs->flags &= ~(EXT2_FLAG_SWAP_BYTES|
239                                EXT2_FLAG_SWAP_BYTES_WRITE);
240                 fs->flags |= EXT2_FLAG_SWAP_BYTES_READ;
241         } else {
242                 fs->flags &= ~EXT2_FLAG_SWAP_BYTES_READ;
243                 fs->flags |= EXT2_FLAG_SWAP_BYTES_WRITE;
244         }
245         swap_inodes(ctx);
246         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
247                 return;
248         if (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)
249                 fs->flags |= EXT2_FLAG_SWAP_BYTES;
250         fs->flags &= ~(EXT2_FLAG_SWAP_BYTES_READ|
251                        EXT2_FLAG_SWAP_BYTES_WRITE);
252
253 #ifdef EXT2_BIG_ENDIAN_BITMAPS
254         e2fsck_read_bitmaps(ctx);
255         ext2fs_swap_bitmap(fs->inode_map);
256         ext2fs_swap_bitmap(fs->block_map);
257         fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
258 #endif
259         fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
260         ext2fs_flush(fs);
261         fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
262         
263 #ifdef RESOURCE_TRACK
264         if (ctx->options & E2F_OPT_TIME2)
265                 print_resource_track(_("Byte swap"), &rtrack);
266 #endif
267 }
268
269 #endif