1 /* $NetBSD: lfs_inode.c,v 1.13 2006/09/28 23:23:01 perseant Exp $ */
4 * Copyright (c) 1980, 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)main.c 8.6 (Berkeley) 5/1/95";
42 __RCSID("$NetBSD: lfs_inode.c,v 1.13 2006/09/28 23:23:01 perseant Exp $");
46 #include <sys/param.h>
49 #include <ufs/ufs/dir.h>
50 #include <ufs/ufs/dinode.h>
51 #include <sys/mount.h>
52 #include <ufs/lfs/lfs.h>
54 #include <protocols/dumprestore.h>
66 #define MAXIFPB (MAXBSIZE / sizeof(IFILE))
68 #define HASDUMPEDFILE 0x1
69 #define HASSUBDIRS 0x2
76 * Read the superblock from disk, and check its magic number.
77 * Determine whether byte-swapping needs to be done on this filesystem.
80 fs_read_sblock(char *superblock
)
84 off_t sboff
= LFS_LABELPAD
;
86 sblock
= (struct lfs
*)superblock
;
88 rawread(sboff
, (char *) sblock
, LFS_SBPAD
);
89 if (sblock
->lfs_magic
!= LFS_MAGIC
) {
91 if (sblock
->lfs_magic
== bswap32(LFS_MAGIC
)) {
92 lfs_sb_swap(sblock
, sblock
, 0);
96 quit("bad sblock magic number\n");
98 if (fsbtob(sblock
, (off_t
)sblock
->lfs_sboffs
[0]) != sboff
) {
99 sboff
= fsbtob(sblock
, (off_t
)sblock
->lfs_sboffs
[0]);
106 * Read the secondary and take the older of the two
108 rawread(fsbtob(sblock
, (off_t
)sblock
->lfs_sboffs
[1]), tbuf
, LFS_SBPAD
);
111 lfs_sb_swap(tbuf
, tbuf
, 0);
113 if (((struct lfs
*)tbuf
)->lfs_magic
!= LFS_MAGIC
) {
114 msg("Warning: secondary superblock at 0x%" PRIx64
" bad magic\n",
115 fsbtodb(sblock
, (off_t
)sblock
->lfs_sboffs
[1]));
117 if (sblock
->lfs_version
> 1) {
118 if (((struct lfs
*)tbuf
)->lfs_serial
< sblock
->lfs_serial
) {
119 memcpy(sblock
, tbuf
, LFS_SBPAD
);
120 sboff
= fsbtob(sblock
, (off_t
)sblock
->lfs_sboffs
[1]);
123 if (((struct lfs
*)tbuf
)->lfs_otstamp
< sblock
->lfs_otstamp
) {
124 memcpy(sblock
, tbuf
, LFS_SBPAD
);
125 sboff
= fsbtob(sblock
, (off_t
)sblock
->lfs_sboffs
[1]);
129 if (sboff
!= LFS_SBPAD
) {
130 msg("Using superblock at alternate location 0x%lx\n",
131 (unsigned long)(btodb(sboff
)));
138 * Fill in the ufsi struct, as well as the maxino and dev_bsize global
144 static struct ufsi ufsi
;
146 spcl
.c_flags
= iswap32(iswap32(spcl
.c_flags
) | DR_NEWINODEFMT
);
148 ufsi
.ufs_dsize
= fsbtodb(sblock
,sblock
->lfs_size
);
149 if (sblock
->lfs_version
== 1)
150 ufsi
.ufs_dsize
= sblock
->lfs_size
>> sblock
->lfs_blktodb
;
151 ufsi
.ufs_bsize
= sblock
->lfs_bsize
;
152 ufsi
.ufs_bshift
= sblock
->lfs_bshift
;
153 ufsi
.ufs_fsize
= sblock
->lfs_fsize
;
154 ufsi
.ufs_frag
= sblock
->lfs_frag
;
155 ufsi
.ufs_fsatoda
= sblock
->lfs_fsbtodb
;
156 if (sblock
->lfs_version
== 1)
157 ufsi
.ufs_fsatoda
= 0;
158 ufsi
.ufs_nindir
= sblock
->lfs_nindir
;
159 ufsi
.ufs_inopb
= sblock
->lfs_inopb
;
160 ufsi
.ufs_maxsymlinklen
= sblock
->lfs_maxsymlinklen
;
161 ufsi
.ufs_bmask
= ~(sblock
->lfs_bmask
);
162 ufsi
.ufs_qbmask
= sblock
->lfs_bmask
;
163 ufsi
.ufs_fmask
= ~(sblock
->lfs_ffmask
);
164 ufsi
.ufs_qfmask
= sblock
->lfs_ffmask
;
166 dev_bsize
= sblock
->lfs_bsize
>> sblock
->lfs_blktodb
;
174 return ((getino(sblock
->lfs_ifile
)->dp1
.di_size
175 - (sblock
->lfs_cleansz
+ sblock
->lfs_segtabsz
)
177 / sblock
->lfs_bsize
) * sblock
->lfs_ifpb
- 1;
181 fs_mapinodes(ino_t maxino
, u_int64_t
*tapesz
, int *anydirskipped
)
185 for (ino
= ROOTINO
; ino
< maxino
; ino
++)
186 mapfileino(ino
, tapesz
, anydirskipped
);
190 * XXX KS - I know there's a better way to do this.
192 #define BASE_SINDIR (NDADDR)
193 #define BASE_DINDIR (NDADDR+NINDIR(fs))
194 #define BASE_TINDIR (NDADDR+NINDIR(fs)+NINDIR(fs)*NINDIR(fs))
196 #define D_UNITS (NINDIR(fs))
197 #define T_UNITS (NINDIR(fs)*NINDIR(fs))
200 lfs_bmap(struct lfs
*fs
, struct ufs1_dinode
*idinode
, daddr_t lbn
)
206 up
= UNASSIGNED
; /* XXXGCC -Wunitialized [sh3] */
208 if(lbn
> 0 && lbn
> lblkno(fs
, idinode
->di_size
)) {
212 * Indirect blocks: if it is a first-level indirect, pull its
213 * address from the inode; otherwise, call ourselves to find the
214 * address of the parent indirect block, and load that to find
215 * the desired address.
220 /* printf("lbn %d: single indir base\n", -lbn); */
221 return idinode
->di_ib
[0]; /* single indirect */
222 } else if(lbn
== BASE_DINDIR
+1) {
223 /* printf("lbn %d: double indir base\n", -lbn); */
224 return idinode
->di_ib
[1]; /* double indirect */
225 } else if(lbn
== BASE_TINDIR
+2) {
226 /* printf("lbn %d: triple indir base\n", -lbn); */
227 return idinode
->di_ib
[2]; /* triple indirect */
231 * Find the immediate parent. This is essentially finding the
232 * residue of modulus, and then rounding accordingly.
234 residue
= (lbn
-NDADDR
) % NINDIR(fs
);
236 /* Double indirect. Parent is the triple. */
237 up
= idinode
->di_ib
[2];
238 off
= (lbn
-2-BASE_TINDIR
)/(NINDIR(fs
)*NINDIR(fs
));
239 if(up
== UNASSIGNED
|| up
== LFS_UNUSED_DADDR
)
241 /* printf("lbn %d: parent is the triple\n", -lbn); */
242 bread(fsbtodb(sblock
, up
), bp
, sblock
->lfs_bsize
);
244 return (daddr_t
)((int32_t *)bp
)[off
];
245 } else /* residue == 0 */ {
246 /* Single indirect. Two cases. */
247 if(lbn
< BASE_TINDIR
) {
248 /* Parent is the double, simple */
249 up
= -(BASE_DINDIR
) - 1;
250 off
= (lbn
-BASE_DINDIR
) / D_UNITS
;
251 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */
253 /* Ancestor is the triple, more complex */
254 up
= ((lbn
-BASE_TINDIR
) / T_UNITS
)
255 * T_UNITS
+ BASE_TINDIR
+ 1;
256 off
= (lbn
/D_UNITS
) - (up
/D_UNITS
);
258 /* printf("lbn %d: parent is %d/%d\n", -lbn, up,off); */
262 /* Direct block. Its parent must be a single indirect. */
264 return idinode
->di_db
[lbn
];
266 /* Parent is an indirect block. */
267 up
= -(((lbn
-NDADDR
) / D_UNITS
) * D_UNITS
+ NDADDR
);
268 off
= (lbn
-NDADDR
) % D_UNITS
;
269 /* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */
272 up
= lfs_bmap(fs
,idinode
,up
);
273 if(up
== UNASSIGNED
|| up
== LFS_UNUSED_DADDR
)
275 bread(fsbtodb(sblock
, up
), bp
, sblock
->lfs_bsize
);
277 return (daddr_t
)((int32_t *)bp
)[off
];
280 static struct ifile
*
281 lfs_ientry(ino_t ino
)
283 static struct ifile ifileblock
[MAXIFPB
];
284 static daddr_t ifblkno
;
289 lbn
= ino
/sblock
->lfs_ifpb
+ sblock
->lfs_cleansz
+ sblock
->lfs_segtabsz
;
290 dp
= getino(sblock
->lfs_ifile
);
291 blkno
= lfs_bmap(sblock
, &dp
->dp1
,lbn
);
292 if (blkno
!= ifblkno
)
293 bread(fsbtodb(sblock
, blkno
), (char *)ifileblock
,
295 return ifileblock
+ (ino
% sblock
->lfs_ifpb
);
298 /* Search a block for a specific dinode. */
299 static struct ufs1_dinode
*
300 lfs_ifind(struct lfs
*fs
, ino_t ino
, struct ufs1_dinode
*dip
)
304 for(cnt
=0;cnt
<INOPB(fs
);cnt
++)
305 if(dip
[cnt
].di_inumber
== ino
)
313 static daddr_t inoblkno
;
315 static struct ufs1_dinode inoblock
[MAXBSIZE
/ sizeof (struct ufs1_dinode
)];
316 static struct ufs1_dinode ifile_dinode
; /* XXX fill this in */
317 static struct ufs1_dinode empty_dinode
; /* Always stays zeroed */
318 struct ufs1_dinode
*dp
;
320 if(inum
== sblock
->lfs_ifile
) {
321 /* Load the ifile inode if not already */
322 if(ifile_dinode
.di_u
.inumber
== 0) {
323 blkno
= sblock
->lfs_idaddr
;
324 bread(fsbtodb(sblock
, blkno
), (char *)inoblock
,
325 (int)sblock
->lfs_bsize
);
326 dp
= lfs_ifind(sblock
, inum
, inoblock
);
327 ifile_dinode
= *dp
; /* Structure copy */
329 return (union dinode
*)&ifile_dinode
;
333 blkno
= lfs_ientry(inum
)->if_daddr
;
334 if(blkno
== LFS_UNUSED_DADDR
)
335 return (union dinode
*)&empty_dinode
;
337 if(blkno
!= inoblkno
) {
338 bread(fsbtodb(sblock
, blkno
), (char *)inoblock
,
339 (int)sblock
->lfs_bsize
);
342 for (i
= 0; i
< MAXINOPB
; i
++)
343 ffs_dinode_swap(&inoblock
[i
], &inoblock
[i
]);
346 return (union dinode
*)lfs_ifind(sblock
, inum
, inoblock
);
350 * Tell the filesystem not to overwrite any currently dirty segments
351 * until we are finished. (It may still write into clean segments, of course,
352 * since we're not using those.) This is only called when dump_lfs is called
353 * with -X, i.e. we are working on a mounted filesystem.
355 static int root_fd
= -1;
359 lfs_wrap_stop(char *mpname
)
363 root_fd
= open(mpname
, O_RDONLY
, 0);
366 wrap_mpname
= mpname
;
367 fcntl(root_fd
, LFCNREWIND
, -1); /* Ignore return value */
368 if (fcntl(root_fd
, LFCNWRAPSTOP
, &waitfor
) < 0) {
369 perror("LFCNWRAPSTOP");
372 msg("Disabled log wrap on %s\n", mpname
);
377 * Allow the filesystem to continue normal operation.
378 * This would happen anyway when we exit; we do it explicitly here
379 * to show the message, for the user's benefit.
389 fcntl(root_fd
, LFCNWRAPGO
, &waitfor
);
392 msg("Re-enabled log wrap on %s\n", wrap_mpname
);