xref: /netbsd-src/sbin/fsck_ffs/wapbl.c (revision 3ad018779fd76a37c0e37dd98f0138f0f8e493ac)
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