1*3ad01877Sdholland /* $NetBSD: wapbl.c,v 1.6 2022/07/25 05:15:08 dholland Exp $ */
236d65f11Ssimonb
336d65f11Ssimonb /*-
436d65f11Ssimonb * Copyright (c) 2005,2008 The NetBSD Foundation, Inc.
536d65f11Ssimonb * All rights reserved.
636d65f11Ssimonb *
736d65f11Ssimonb * This code is derived from software contributed to The NetBSD Foundation
836d65f11Ssimonb * by Wasabi Systems, Inc.
936d65f11Ssimonb *
1036d65f11Ssimonb * Redistribution and use in source and binary forms, with or without
1136d65f11Ssimonb * modification, are permitted provided that the following conditions
1236d65f11Ssimonb * are met:
1336d65f11Ssimonb * 1. Redistributions of source code must retain the above copyright
1436d65f11Ssimonb * notice, this list of conditions and the following disclaimer.
1536d65f11Ssimonb * 2. Redistributions in binary form must reproduce the above copyright
1636d65f11Ssimonb * notice, this list of conditions and the following disclaimer in the
1736d65f11Ssimonb * documentation and/or other materials provided with the distribution.
1836d65f11Ssimonb *
1936d65f11Ssimonb * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2036d65f11Ssimonb * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2136d65f11Ssimonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2236d65f11Ssimonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2336d65f11Ssimonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2436d65f11Ssimonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2536d65f11Ssimonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2636d65f11Ssimonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2736d65f11Ssimonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2836d65f11Ssimonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2936d65f11Ssimonb * POSSIBILITY OF SUCH DAMAGE.
3036d65f11Ssimonb */
3136d65f11Ssimonb
3236d65f11Ssimonb /* This file contains fsck support for wapbl
3336d65f11Ssimonb */
343fbdfc8aSjoerg #define WAPBL_INTERNAL
3536d65f11Ssimonb
3636d65f11Ssimonb #include <sys/cdefs.h>
37*3ad01877Sdholland __KERNEL_RCSID(0, "$NetBSD: wapbl.c,v 1.6 2022/07/25 05:15:08 dholland Exp $");
3836d65f11Ssimonb
3936d65f11Ssimonb #include <sys/stat.h>
4036d65f11Ssimonb #include <sys/time.h>
4136d65f11Ssimonb #include <sys/uio.h>
4236d65f11Ssimonb
4336d65f11Ssimonb #include <assert.h>
4436d65f11Ssimonb #include <errno.h>
4536d65f11Ssimonb #include <inttypes.h>
4636d65f11Ssimonb #include <stdio.h>
4736d65f11Ssimonb #include <stdbool.h>
4836d65f11Ssimonb #include <stdlib.h>
4936d65f11Ssimonb #include <string.h>
5036d65f11Ssimonb #include <unistd.h>
5136d65f11Ssimonb
5236d65f11Ssimonb #include <ufs/ufs/dinode.h>
5336d65f11Ssimonb #include <ufs/ufs/dir.h>
5436d65f11Ssimonb #include <ufs/ufs/ufs_bswap.h>
5536d65f11Ssimonb #include <ufs/ufs/ufs_wapbl.h>
5636d65f11Ssimonb #include <ufs/ffs/fs.h>
5736d65f11Ssimonb #include <ufs/ffs/ffs_extern.h>
5836d65f11Ssimonb
5936d65f11Ssimonb #include <sys/wapbl.h>
6036d65f11Ssimonb
6136d65f11Ssimonb #include "fsck.h"
6236d65f11Ssimonb #include "fsutil.h"
6336d65f11Ssimonb #include "extern.h"
6436d65f11Ssimonb #include "exitvalues.h"
6536d65f11Ssimonb
6636d65f11Ssimonb int
wapbl_write(void * data,size_t len,struct vnode * devvp,daddr_t pbn)6736d65f11Ssimonb wapbl_write(void *data, size_t len, struct vnode *devvp, daddr_t pbn)
6836d65f11Ssimonb {
6936d65f11Ssimonb
7036d65f11Ssimonb WAPBL_PRINTF(WAPBL_PRINT_IO,
7136d65f11Ssimonb ("wapbl_write: %zd bytes at block %"PRId64" on fd 0x%x\n",
7236d65f11Ssimonb len, pbn, fswritefd));
7336d65f11Ssimonb bwrite(fswritefd, data, pbn, len);
7436d65f11Ssimonb return 0;
7536d65f11Ssimonb }
7636d65f11Ssimonb
7736d65f11Ssimonb int
wapbl_read(void * data,size_t len,struct vnode * devvp,daddr_t pbn)7836d65f11Ssimonb wapbl_read(void *data, size_t len, struct vnode *devvp, daddr_t pbn)
7936d65f11Ssimonb {
8036d65f11Ssimonb
8136d65f11Ssimonb WAPBL_PRINTF(WAPBL_PRINT_IO,
8236d65f11Ssimonb ("wapbl_read: %zd bytes at block %"PRId64" on fd 0x%x\n",
8336d65f11Ssimonb len, pbn, fsreadfd));
8436d65f11Ssimonb bread(fsreadfd, data, pbn, len);
8536d65f11Ssimonb return 0;
8636d65f11Ssimonb }
8736d65f11Ssimonb
8836d65f11Ssimonb struct wapbl_replay *wapbl_replay;
8936d65f11Ssimonb
9036d65f11Ssimonb void
replay_wapbl(void)9136d65f11Ssimonb replay_wapbl(void)
9236d65f11Ssimonb {
9336d65f11Ssimonb int error;
9436d65f11Ssimonb
95*3ad01877Sdholland if (nflag) {
96*3ad01877Sdholland /*
97*3ad01877Sdholland * XXX: we ought to have a mode where we can replay
98*3ad01877Sdholland * the journal to memory, similar to what happens in
99*3ad01877Sdholland * the kernel with a readonly mount. For now though
100*3ad01877Sdholland * just print that we aren't doing it so as to avoid
101*3ad01877Sdholland * lying to the user.
102*3ad01877Sdholland */
103*3ad01877Sdholland pwarn("CANNOT REPLAY JOURNAL IN -n MODE; continuing anyway\n");
104*3ad01877Sdholland } else {
10536d65f11Ssimonb error = wapbl_replay_write(wapbl_replay, 0);
10636d65f11Ssimonb if (error) {
10736d65f11Ssimonb pfatal("UNABLE TO REPLAY JOURNAL BLOCKS");
10836d65f11Ssimonb if (reply("CONTINUE") == 0) {
10936d65f11Ssimonb exit(FSCK_EXIT_CHECK_FAILED);
11036d65f11Ssimonb }
11136d65f11Ssimonb } else {
11236d65f11Ssimonb wapbl_replay_stop(wapbl_replay);
11336d65f11Ssimonb }
11436d65f11Ssimonb }
11536d65f11Ssimonb {
11636d65f11Ssimonb int i;
11736d65f11Ssimonb for (i = 0; i < wapbl_replay->wr_inodescnt; i++) {
11836d65f11Ssimonb WAPBL_PRINTF(WAPBL_PRINT_REPLAY,("wapbl_replay: "
11936d65f11Ssimonb "not cleaning inode %"PRIu32" mode %"PRIo32"\n",
12036d65f11Ssimonb wapbl_replay->wr_inodes[i].wr_inumber,
12136d65f11Ssimonb wapbl_replay->wr_inodes[i].wr_imode));
12236d65f11Ssimonb }
12336d65f11Ssimonb }
12436d65f11Ssimonb }
12536d65f11Ssimonb
12636d65f11Ssimonb void
cleanup_wapbl(void)12736d65f11Ssimonb cleanup_wapbl(void)
12836d65f11Ssimonb {
12936d65f11Ssimonb
13036d65f11Ssimonb if (wapbl_replay) {
13136d65f11Ssimonb if (wapbl_replay_isopen(wapbl_replay))
13236d65f11Ssimonb wapbl_replay_stop(wapbl_replay);
13336d65f11Ssimonb wapbl_replay_free(wapbl_replay);
13436d65f11Ssimonb wapbl_replay = 0;
13536d65f11Ssimonb }
13636d65f11Ssimonb }
13736d65f11Ssimonb
13836d65f11Ssimonb int
read_wapbl(char * buf,long size,daddr_t blk)13936d65f11Ssimonb read_wapbl(char *buf, long size, daddr_t blk)
14036d65f11Ssimonb {
14136d65f11Ssimonb
14236d65f11Ssimonb if (!wapbl_replay || !wapbl_replay_isopen(wapbl_replay))
14336d65f11Ssimonb return 0;
14436d65f11Ssimonb return wapbl_replay_read(wapbl_replay, buf, blk, size);
14536d65f11Ssimonb }
14636d65f11Ssimonb
14736d65f11Ssimonb int
is_journal_inode(ino_t ino)14836d65f11Ssimonb is_journal_inode(ino_t ino)
14936d65f11Ssimonb {
15036d65f11Ssimonb union dinode *dp;
15136d65f11Ssimonb
15236d65f11Ssimonb dp = ginode(ino);
15336d65f11Ssimonb if ((iswap32(DIP(dp, flags)) & SF_LOG) != 0 &&
15436d65f11Ssimonb sblock->fs_journal_version == UFS_WAPBL_VERSION &&
15536d65f11Ssimonb sblock->fs_journal_location == UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM &&
15636d65f11Ssimonb sblock->fs_journallocs[UFS_WAPBL_INFS_INO] == ino)
15736d65f11Ssimonb return 1;
15836d65f11Ssimonb
15936d65f11Ssimonb return 0;
16036d65f11Ssimonb }
161cab6cd67Sbouyer
162cab6cd67Sbouyer int
check_wapbl(void)163cab6cd67Sbouyer check_wapbl(void)
164cab6cd67Sbouyer {
165cab6cd67Sbouyer uint64_t addr = 0, count = 0, blksize = 0;
166cab6cd67Sbouyer int error;
167cab6cd67Sbouyer int ret = 0;
168cab6cd67Sbouyer if (debug)
169cab6cd67Sbouyer wapbl_debug_print = WAPBL_PRINT_ERROR | WAPBL_PRINT_REPLAY;
170cab6cd67Sbouyer if (debug > 1)
171cab6cd67Sbouyer wapbl_debug_print |= WAPBL_PRINT_IO;
172cab6cd67Sbouyer
173cab6cd67Sbouyer if (sblock->fs_flags & FS_DOWAPBL) {
174cab6cd67Sbouyer if (sblock->fs_journal_version != UFS_WAPBL_VERSION) {
175cab6cd67Sbouyer pfatal("INVALID JOURNAL VERSION %d",
176cab6cd67Sbouyer sblock->fs_journal_version);
177cab6cd67Sbouyer if (reply("CONTINUE") == 0) {
178cab6cd67Sbouyer exit(FSCK_EXIT_CHECK_FAILED);
179cab6cd67Sbouyer }
180cab6cd67Sbouyer pwarn("CLEARING EXISTING JOURNAL\n");
181cab6cd67Sbouyer sblock->fs_flags &= ~FS_DOWAPBL;
182bc76b1d5Smlelstv sblock->fs_journal_flags = UFS_WAPBL_FLAGS_CLEAR_LOG;
183cab6cd67Sbouyer sbdirty();
184cab6cd67Sbouyer ret = FSCK_EXIT_CHECK_FAILED;
185cab6cd67Sbouyer } else {
186cab6cd67Sbouyer switch(sblock->fs_journal_location) {
187cab6cd67Sbouyer case UFS_WAPBL_JOURNALLOC_END_PARTITION:
188cab6cd67Sbouyer addr =
189cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_EPART_ADDR];
190cab6cd67Sbouyer count =
191cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_EPART_COUNT];
192cab6cd67Sbouyer blksize =
193cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
194cab6cd67Sbouyer break;
195cab6cd67Sbouyer case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
196cab6cd67Sbouyer addr =
197cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_INFS_ADDR];
198cab6cd67Sbouyer count =
199cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_INFS_COUNT];
200cab6cd67Sbouyer blksize =
201cab6cd67Sbouyer sblock->fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
202cab6cd67Sbouyer break;
203cab6cd67Sbouyer default:
204cab6cd67Sbouyer pfatal("INVALID JOURNAL LOCATION %d",
205cab6cd67Sbouyer sblock->fs_journal_location);
206cab6cd67Sbouyer if (reply("CONTINUE") == 0) {
207cab6cd67Sbouyer exit(FSCK_EXIT_CHECK_FAILED);
208cab6cd67Sbouyer }
209cab6cd67Sbouyer pwarn("CLEARING EXISTING JOURNAL\n");
210cab6cd67Sbouyer sblock->fs_flags &= ~FS_DOWAPBL;
211bc76b1d5Smlelstv sblock->fs_journal_flags = UFS_WAPBL_FLAGS_CLEAR_LOG;
212cab6cd67Sbouyer sblock->fs_journal_location =
213cab6cd67Sbouyer UFS_WAPBL_JOURNALLOC_NONE;
214cab6cd67Sbouyer sbdirty();
215cab6cd67Sbouyer ret = FSCK_EXIT_CHECK_FAILED;
216cab6cd67Sbouyer break;
217cab6cd67Sbouyer }
218cab6cd67Sbouyer if (sblock->fs_flags & FS_DOWAPBL) {
219cab6cd67Sbouyer error = wapbl_replay_start(
220cab6cd67Sbouyer &wapbl_replay, 0, addr, count, blksize);
221cab6cd67Sbouyer if (error) {
222cab6cd67Sbouyer pfatal(
223cab6cd67Sbouyer "UNABLE TO READ JOURNAL FOR REPLAY");
224cab6cd67Sbouyer if (reply("CONTINUE") == 0) {
225cab6cd67Sbouyer exit(FSCK_EXIT_CHECK_FAILED);
226cab6cd67Sbouyer }
227cab6cd67Sbouyer pwarn("CLEARING EXISTING JOURNAL\n");
228cab6cd67Sbouyer sblock->fs_flags &= ~FS_DOWAPBL;
229bc76b1d5Smlelstv sblock->fs_journal_flags = UFS_WAPBL_FLAGS_CLEAR_LOG;
230cab6cd67Sbouyer sbdirty();
231cab6cd67Sbouyer ret = FSCK_EXIT_CHECK_FAILED;
232cab6cd67Sbouyer }
233cab6cd67Sbouyer }
234cab6cd67Sbouyer }
235cab6cd67Sbouyer }
236cab6cd67Sbouyer /*
237cab6cd67Sbouyer * at this time fs_journal_flags can only be 0,
238cab6cd67Sbouyer * UFS_WAPBL_FLAGS_CREATE_LOG or UFS_WAPBL_FLAGS_CLEAR_LOG.
239cab6cd67Sbouyer * We can't have both flags at the same time.
240cab6cd67Sbouyer */
241cab6cd67Sbouyer switch (sblock->fs_journal_flags) {
242cab6cd67Sbouyer case 0:
243cab6cd67Sbouyer break;
244cab6cd67Sbouyer case UFS_WAPBL_FLAGS_CREATE_LOG:
245cab6cd67Sbouyer case UFS_WAPBL_FLAGS_CLEAR_LOG:
246cab6cd67Sbouyer switch(sblock->fs_journal_location) {
247cab6cd67Sbouyer case UFS_WAPBL_JOURNALLOC_END_PARTITION:
248cab6cd67Sbouyer case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
249cab6cd67Sbouyer break;
250cab6cd67Sbouyer case UFS_WAPBL_JOURNALLOC_NONE:
251cab6cd67Sbouyer if (sblock->fs_journal_flags ==
252cab6cd67Sbouyer UFS_WAPBL_FLAGS_CLEAR_LOG)
253cab6cd67Sbouyer break;
254cab6cd67Sbouyer /* FALLTHROUGH */
255cab6cd67Sbouyer default:
256cab6cd67Sbouyer pfatal("INVALID JOURNAL LOCATION %d",
257cab6cd67Sbouyer sblock->fs_journal_location);
258cab6cd67Sbouyer if (reply("CONTINUE") == 0) {
259cab6cd67Sbouyer exit(FSCK_EXIT_CHECK_FAILED);
260cab6cd67Sbouyer }
261cab6cd67Sbouyer pwarn("CLEARING JOURNAL FLAGS\n");
262cab6cd67Sbouyer sblock->fs_journal_flags = 0;
263cab6cd67Sbouyer sblock->fs_journal_location =
264cab6cd67Sbouyer UFS_WAPBL_JOURNALLOC_NONE;
265cab6cd67Sbouyer sbdirty();
266cab6cd67Sbouyer ret = FSCK_EXIT_CHECK_FAILED;
267cab6cd67Sbouyer break;
268cab6cd67Sbouyer }
269cab6cd67Sbouyer break;
270cab6cd67Sbouyer default:
271cab6cd67Sbouyer pfatal("INVALID JOURNAL FLAGS %d",
272cab6cd67Sbouyer sblock->fs_journal_flags);
273cab6cd67Sbouyer if (reply("CONTINUE") == 0) {
274cab6cd67Sbouyer exit(FSCK_EXIT_CHECK_FAILED);
275cab6cd67Sbouyer }
276cab6cd67Sbouyer pwarn("CLEARING JOURNAL FLAGS\n");
277cab6cd67Sbouyer sblock->fs_journal_flags = 0;
278cab6cd67Sbouyer sblock->fs_journal_location =
279cab6cd67Sbouyer UFS_WAPBL_JOURNALLOC_NONE;
280cab6cd67Sbouyer sbdirty();
281cab6cd67Sbouyer ret = FSCK_EXIT_CHECK_FAILED;
282cab6cd67Sbouyer break;
283cab6cd67Sbouyer }
284cab6cd67Sbouyer return ret;
285cab6cd67Sbouyer }
286