Commit | Line | Data |
---|---|---|
7168b5c1 | 1 | /*- |
ad0f93d2 KB |
2 | * Copyright (c) 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
7168b5c1 KB |
4 | * |
5 | * %sccs.include.redist.c% | |
6 | * | |
89e2bb79 | 7 | * @(#)lfs.h 8.8 (Berkeley) %G% |
7168b5c1 KB |
8 | */ |
9 | ||
b6a5a267 KB |
10 | #define LFS_LABELPAD 8192 /* LFS label size */ |
11 | #define LFS_SBPAD 8192 /* LFS superblock size */ | |
7168b5c1 | 12 | |
c4379551 KB |
13 | /* |
14 | * XXX | |
15 | * This is a kluge and NEEDS to go away. | |
16 | * | |
17 | * Right now, ufs code handles most of the calls for directory operations | |
18 | * such as create, mkdir, link, etc. As a result VOP_UPDATE is being | |
19 | * called with waitfor set (since ffs does these things synchronously). | |
20 | * Since LFS does not want to do these synchronously, we treat the last | |
21 | * argument to lfs_update as a set of flags. If LFS_SYNC is set, then | |
22 | * the update should be synchronous, if not, do it asynchronously. | |
23 | * Unfortunately, this means that LFS won't work with NFS yet because | |
24 | * NFS goes through paths that will make normal calls to ufs which will | |
25 | * call lfs with a last argument of 1. | |
26 | */ | |
27 | #define LFS_SYNC 0x02 | |
28 | ||
0b4d6502 | 29 | /* On-disk and in-memory checkpoint segment usage structure. */ |
d5075120 KB |
30 | typedef struct segusage SEGUSE; |
31 | struct segusage { | |
993707aa KM |
32 | u_int32_t su_nbytes; /* number of live bytes */ |
33 | u_int32_t su_lastmod; /* SEGUSE last modified timestamp */ | |
34 | u_int16_t su_nsums; /* number of summaries in segment */ | |
35 | u_int16_t su_ninos; /* number of inode blocks in seg */ | |
36 | ||
37 | #define SEGUSE_ACTIVE 0x01 /* segment is currently being written */ | |
38 | #define SEGUSE_DIRTY 0x02 /* segment has data in it */ | |
39 | #define SEGUSE_SUPERBLOCK 0x04 /* segment contains a superblock */ | |
40 | u_int32_t su_flags; | |
d5075120 KB |
41 | }; |
42 | ||
2f387230 | 43 | #define SEGUPB(fs) (1 << (fs)->lfs_sushift) |
cf5ef508 | 44 | #define SEGTABSIZE_SU(fs) \ |
2f387230 | 45 | (((fs)->lfs_nseg + SEGUPB(fs) - 1) >> (fs)->lfs_sushift) |
0c67132e | 46 | |
d5075120 KB |
47 | /* On-disk file information. One per file with data blocks in the segment. */ |
48 | typedef struct finfo FINFO; | |
49 | struct finfo { | |
993707aa KM |
50 | u_int32_t fi_nblocks; /* number of blocks */ |
51 | u_int32_t fi_version; /* version number */ | |
52 | u_int32_t fi_ino; /* inode number */ | |
89e2bb79 | 53 | ufs_daddr_t fi_blocks[1]; /* array of logical block numbers */ |
d5075120 KB |
54 | }; |
55 | ||
0b4d6502 | 56 | /* On-disk and in-memory super block. */ |
d5075120 | 57 | struct lfs { |
113e98ad | 58 | #define LFS_MAGIC 0x070162 |
993707aa | 59 | u_int32_t lfs_magic; /* magic number */ |
b6a5a267 | 60 | #define LFS_VERSION 1 |
993707aa | 61 | u_int32_t lfs_version; /* version number */ |
7168b5c1 | 62 | |
993707aa KM |
63 | u_int32_t lfs_size; /* number of blocks in fs */ |
64 | u_int32_t lfs_ssize; /* number of blocks per segment */ | |
65 | u_int32_t lfs_dsize; /* number of disk blocks in fs */ | |
66 | u_int32_t lfs_bsize; /* file system block size */ | |
67 | u_int32_t lfs_fsize; /* size of frag blocks in fs */ | |
68 | u_int32_t lfs_frag; /* number of frags in a block in fs */ | |
7168b5c1 KB |
69 | |
70 | /* Checkpoint region. */ | |
993707aa KM |
71 | ino_t lfs_free; /* start of the free list */ |
72 | u_int32_t lfs_bfree; /* number of free disk blocks */ | |
73 | u_int32_t lfs_nfiles; /* number of allocated inodes */ | |
74 | int32_t lfs_avail; /* blocks available for writing */ | |
75 | u_int32_t lfs_uinodes; /* inodes in cache not yet on disk */ | |
89e2bb79 | 76 | ufs_daddr_t lfs_idaddr; /* inode file disk address */ |
993707aa | 77 | ino_t lfs_ifile; /* inode file inode number */ |
89e2bb79 KM |
78 | ufs_daddr_t lfs_lastseg; /* address of last segment written */ |
79 | ufs_daddr_t lfs_nextseg; /* address of next segment to write */ | |
80 | ufs_daddr_t lfs_curseg; /* current segment being written */ | |
81 | ufs_daddr_t lfs_offset; /* offset in curseg for next partial */ | |
82 | ufs_daddr_t lfs_lastpseg; /* address of last partial written */ | |
993707aa | 83 | u_int32_t lfs_tstamp; /* time stamp */ |
7168b5c1 KB |
84 | |
85 | /* These are configuration parameters. */ | |
993707aa | 86 | u_int32_t lfs_minfree; /* minimum percentage of free blocks */ |
7168b5c1 KB |
87 | |
88 | /* These fields can be computed from the others. */ | |
a63e2cc2 | 89 | u_int64_t lfs_maxfilesize; /* maximum representable file size */ |
993707aa KM |
90 | u_int32_t lfs_dbpseg; /* disk blocks per segment */ |
91 | u_int32_t lfs_inopb; /* inodes per block */ | |
92 | u_int32_t lfs_ifpb; /* IFILE entries per block */ | |
93 | u_int32_t lfs_sepb; /* SEGUSE entries per block */ | |
94 | u_int32_t lfs_nindir; /* indirect pointers per block */ | |
95 | u_int32_t lfs_nseg; /* number of segments */ | |
96 | u_int32_t lfs_nspf; /* number of sectors per fragment */ | |
97 | u_int32_t lfs_cleansz; /* cleaner info size in blocks */ | |
98 | u_int32_t lfs_segtabsz; /* segment table size in blocks */ | |
99 | ||
100 | u_int32_t lfs_segmask; /* calculate offset within a segment */ | |
101 | u_int32_t lfs_segshift; /* fast mult/div for segments */ | |
102 | u_int32_t lfs_bmask; /* calc block offset from file offset */ | |
103 | u_int32_t lfs_bshift; /* calc block number from file offset */ | |
104 | u_int32_t lfs_ffmask; /* calc frag offset from file offset */ | |
105 | u_int32_t lfs_ffshift; /* fast mult/div for frag from file */ | |
106 | u_int32_t lfs_fbmask; /* calc frag offset from block offset */ | |
107 | u_int32_t lfs_fbshift; /* fast mult/div for frag from block */ | |
108 | u_int32_t lfs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ | |
109 | u_int32_t lfs_sushift; /* fast mult/div for segusage table */ | |
110 | ||
111 | int32_t lfs_maxsymlinklen; /* max length of an internal symlink */ | |
7168b5c1 | 112 | |
0b4d6502 KB |
113 | #define LFS_MIN_SBINTERVAL 5 /* minimum superblock segment spacing */ |
114 | #define LFS_MAXNUMSB 10 /* superblock disk offsets */ | |
89e2bb79 | 115 | ufs_daddr_t lfs_sboffs[LFS_MAXNUMSB]; |
993707aa KM |
116 | |
117 | /* Checksum -- last valid disk field. */ | |
118 | u_int32_t lfs_cksum; /* checksum for superblock checking */ | |
0b4d6502 KB |
119 | |
120 | /* These fields are set at mount time and are meaningless on disk. */ | |
993707aa KM |
121 | struct segment *lfs_sp; /* current segment being written */ |
122 | struct vnode *lfs_ivnode; /* vnode for the ifile */ | |
123 | u_long lfs_seglock; /* single-thread the segment writer */ | |
124 | pid_t lfs_lockpid; /* pid of lock holder */ | |
125 | u_long lfs_iocount; /* number of ios pending */ | |
126 | u_long lfs_writer; /* don't allow any dirops to start */ | |
127 | u_long lfs_dirops; /* count of active directory ops */ | |
128 | u_long lfs_doifile; /* Write ifile blocks on next write */ | |
129 | u_long lfs_nactive; /* Number of segments since last ckp */ | |
130 | int8_t lfs_fmod; /* super block modified flag */ | |
131 | int8_t lfs_clean; /* file system is clean flag */ | |
132 | int8_t lfs_ronly; /* mounted read-only flag */ | |
133 | int8_t lfs_flags; /* currently unused flag */ | |
134 | u_char lfs_fsmnt[MNAMELEN]; /* name mounted on */ | |
d243d92d KM |
135 | |
136 | int32_t lfs_pad[40]; /* round to 512 bytes */ | |
d5075120 | 137 | }; |
7168b5c1 | 138 | |
0b4d6502 | 139 | /* |
993707aa KM |
140 | * Inode 0: out-of-band inode number |
141 | * Inode 1: IFILE inode number | |
142 | * Inode 2: root inode | |
143 | * Inode 3: lost+found inode number | |
0b4d6502 | 144 | */ |
0c90e94d | 145 | #define LFS_UNUSED_INUM 0 /* out of band inode number */ |
0d70dc17 KB |
146 | #define LFS_IFILE_INUM 1 /* IFILE inode number */ |
147 | #define LOSTFOUNDINO 3 /* lost+found inode number */ | |
148 | #define LFS_FIRST_INUM 4 /* first free inode number */ | |
b6a5a267 | 149 | |
0c67132e KB |
150 | /* Address calculations for metadata located in the inode */ |
151 | #define S_INDIR(fs) -NDADDR | |
5c4e1af0 CS |
152 | #define D_INDIR(fs) (S_INDIR(fs) - NINDIR(fs) - 1) |
153 | #define T_INDIR(fs) (D_INDIR(fs) - NINDIR(fs) * NINDIR(fs) - 1) | |
0c67132e | 154 | |
39cabb59 KB |
155 | /* Unassigned disk address. */ |
156 | #define UNASSIGNED -1 | |
157 | ||
cb87447c KB |
158 | /* Unused logical block number */ |
159 | #define LFS_UNUSED_LBN -1 | |
160 | ||
d5075120 KB |
161 | typedef struct ifile IFILE; |
162 | struct ifile { | |
993707aa | 163 | u_int32_t if_version; /* inode version number */ |
0b4d6502 | 164 | #define LFS_UNUSED_DADDR 0 /* out-of-band daddr */ |
89e2bb79 | 165 | ufs_daddr_t if_daddr; /* inode disk address */ |
993707aa | 166 | ino_t if_nextfree; /* next-unallocated inode */ |
d5075120 | 167 | }; |
7168b5c1 | 168 | |
0c67132e KB |
169 | /* |
170 | * Cleaner information structure. This resides in the ifile and is used | |
171 | * to pass information between the cleaner and the kernel. | |
172 | */ | |
173 | typedef struct _cleanerinfo { | |
993707aa KM |
174 | u_int32_t clean; /* K: number of clean segments */ |
175 | u_int32_t dirty; /* K: number of dirty segments */ | |
0c67132e | 176 | } CLEANERINFO; |
7168b5c1 | 177 | |
cf5ef508 | 178 | #define CLEANSIZE_SU(fs) \ |
0c67132e | 179 | ((sizeof(CLEANERINFO) + (fs)->lfs_bsize - 1) >> (fs)->lfs_bshift) |
b6a5a267 | 180 | |
b6a5a267 KB |
181 | /* |
182 | * All summary blocks are the same size, so we can always read a summary | |
0c90e94d | 183 | * block easily from a segment. |
b6a5a267 KB |
184 | */ |
185 | #define LFS_SUMMARY_SIZE 512 | |
186 | ||
7168b5c1 | 187 | /* On-disk segment summary information */ |
d5075120 KB |
188 | typedef struct segsum SEGSUM; |
189 | struct segsum { | |
993707aa KM |
190 | u_int32_t ss_sumsum; /* check sum of summary block */ |
191 | u_int32_t ss_datasum; /* check sum of data */ | |
89e2bb79 | 192 | ufs_daddr_t ss_next; /* next segment */ |
993707aa KM |
193 | u_int32_t ss_create; /* creation time stamp */ |
194 | u_int16_t ss_nfinfo; /* number of file info structures */ | |
195 | u_int16_t ss_ninos; /* number of inodes in summary */ | |
196 | ||
3ce71481 KB |
197 | #define SS_DIROP 0x01 /* segment begins a dirop */ |
198 | #define SS_CONT 0x02 /* more partials to finish this write*/ | |
993707aa KM |
199 | u_int16_t ss_flags; /* used for directory operations */ |
200 | u_int16_t ss_pad; /* extra space */ | |
d3b72332 | 201 | /* FINFO's and inode daddr's... */ |
d5075120 | 202 | }; |
7168b5c1 | 203 | |
0b4d6502 KB |
204 | /* NINDIR is the number of indirects in a file system block. */ |
205 | #define NINDIR(fs) ((fs)->lfs_nindir) | |
206 | ||
207 | /* INOPB is the number of inodes in a secondary storage block. */ | |
208 | #define INOPB(fs) ((fs)->lfs_inopb) | |
209 | ||
0b4d6502 KB |
210 | #define blksize(fs) ((fs)->lfs_bsize) |
211 | #define blkoff(fs, loc) ((loc) & (fs)->lfs_bmask) | |
212 | #define fsbtodb(fs, b) ((b) << (fs)->lfs_fsbtodb) | |
d9839b30 | 213 | #define dbtofsb(fs, b) ((b) >> (fs)->lfs_fsbtodb) |
0b4d6502 KB |
214 | #define lblkno(fs, loc) ((loc) >> (fs)->lfs_bshift) |
215 | #define lblktosize(fs, blk) ((blk) << (fs)->lfs_bshift) | |
cf5ef508 | 216 | #define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ |
d5075120 | 217 | ((loc) >> (fs)->lfs_bshift) |
39cabb59 | 218 | |
cf5ef508 | 219 | #define datosn(fs, daddr) /* disk address to segment number */ \ |
0d70dc17 | 220 | (((daddr) - (fs)->lfs_sboffs[0]) / fsbtodb((fs), (fs)->lfs_ssize)) |
cf5ef508 | 221 | #define sntoda(fs, sn) /* segment number to disk address */ \ |
89e2bb79 | 222 | ((ufs_daddr_t)((sn) * ((fs)->lfs_ssize << (fs)->lfs_fsbtodb) + \ |
0d70dc17 KB |
223 | (fs)->lfs_sboffs[0])) |
224 | ||
59526076 | 225 | /* Read in the block with the cleaner info from the ifile. */ |
cf5ef508 KB |
226 | #define LFS_CLEANERINFO(CP, F, BP) { \ |
227 | VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \ | |
228 | if (bread((F)->lfs_ivnode, \ | |
89e2bb79 | 229 | (ufs_daddr_t)0, (F)->lfs_bsize, NOCRED, &(BP))) \ |
cf5ef508 KB |
230 | panic("lfs: ifile read"); \ |
231 | (CP) = (CLEANERINFO *)(BP)->b_data; \ | |
59526076 KB |
232 | } |
233 | ||
0c67132e | 234 | /* Read in the block with a specific inode from the ifile. */ |
cf5ef508 KB |
235 | #define LFS_IENTRY(IP, F, IN, BP) { \ |
236 | int _e; \ | |
237 | VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \ | |
238 | if (_e = bread((F)->lfs_ivnode, \ | |
239 | (IN) / (F)->lfs_ifpb + (F)->lfs_cleansz + (F)->lfs_segtabsz,\ | |
240 | (F)->lfs_bsize, NOCRED, &(BP))) \ | |
241 | panic("lfs: ifile read %d", _e); \ | |
242 | (IP) = (IFILE *)(BP)->b_data + (IN) % (F)->lfs_ifpb; \ | |
a9322048 KB |
243 | } |
244 | ||
0c67132e | 245 | /* Read in the block with a specific segment usage entry from the ifile. */ |
cf5ef508 KB |
246 | #define LFS_SEGENTRY(SP, F, IN, BP) { \ |
247 | int _e; \ | |
248 | VTOI((F)->lfs_ivnode)->i_flag |= IN_ACCESS; \ | |
249 | if (_e = bread((F)->lfs_ivnode, \ | |
250 | ((IN) >> (F)->lfs_sushift) + (F)->lfs_cleansz, \ | |
251 | (F)->lfs_bsize, NOCRED, &(BP))) \ | |
252 | panic("lfs: ifile read: %d", _e); \ | |
253 | (SP) = (SEGUSE *)(BP)->b_data + ((IN) & (F)->lfs_sepb - 1); \ | |
0c67132e KB |
254 | } |
255 | ||
cb87447c KB |
256 | /* |
257 | * Determine if there is enough room currently available to write db | |
258 | * disk blocks. We need enough blocks for the new blocks, the current, | |
259 | * inode blocks, a summary block, plus potentially the ifile inode and | |
260 | * the segment usage table, plus an ifile page. | |
261 | */ | |
262 | #define LFS_FITS(fs, db) \ | |
993707aa KM |
263 | ((int32_t)((db + ((fs)->lfs_uinodes + INOPB((fs))) / \ |
264 | INOPB((fs)) + fsbtodb(fs, 1) + LFS_SUMMARY_SIZE / DEV_BSIZE + \ | |
cf5ef508 | 265 | (fs)->lfs_segtabsz)) < (fs)->lfs_avail) |
5ec8c51e | 266 | |
cb87447c KB |
267 | /* Determine if a buffer belongs to the ifile */ |
268 | #define IS_IFILE(bp) (VTOI(bp->b_vp)->i_number == LFS_IFILE_INUM) | |
cf5ef508 | 269 | |
0c67132e KB |
270 | /* |
271 | * Structures used by lfs_bmapv and lfs_markv to communicate information | |
272 | * about inodes and data blocks. | |
273 | */ | |
274 | typedef struct block_info { | |
275 | ino_t bi_inode; /* inode # */ | |
89e2bb79 KM |
276 | ufs_daddr_t bi_lbn; /* logical block w/in file */ |
277 | ufs_daddr_t bi_daddr; /* disk address of block */ | |
0c67132e | 278 | time_t bi_segcreate; /* origin segment create time */ |
0408cf24 | 279 | int bi_version; /* file version number */ |
0c67132e KB |
280 | void *bi_bp; /* data buffer */ |
281 | } BLOCK_INFO; | |
282 | ||
cb87447c KB |
283 | /* In-memory description of a segment about to be written. */ |
284 | struct segment { | |
993707aa | 285 | struct lfs *fs; /* file system pointer */ |
cb87447c KB |
286 | struct buf **bpp; /* pointer to buffer array */ |
287 | struct buf **cbpp; /* pointer to next available bp */ | |
288 | struct buf **start_bpp; /* pointer to first bp in this set */ | |
993707aa KM |
289 | struct buf *ibp; /* buffer pointer to inode page */ |
290 | struct finfo *fip; /* current fileinfo pointer */ | |
291 | struct vnode *vp; /* vnode being gathered */ | |
292 | void *segsum; /* segment summary info */ | |
293 | u_int32_t ninodes; /* number of inodes in this segment */ | |
294 | u_int32_t seg_bytes_left; /* bytes left in segment */ | |
295 | u_int32_t sum_bytes_left; /* bytes left in summary block */ | |
296 | u_int32_t seg_number; /* number of this segment */ | |
89e2bb79 | 297 | ufs_daddr_t *start_lbp; /* beginning lbn for this set */ |
993707aa | 298 | |
cb87447c KB |
299 | #define SEGM_CKP 0x01 /* doing a checkpoint */ |
300 | #define SEGM_CLEAN 0x02 /* cleaner call; don't sort */ | |
2a04b8fe | 301 | #define SEGM_SYNC 0x04 /* wait for segment */ |
993707aa | 302 | u_int16_t seg_flags; /* run-time flags for this segment */ |
cb87447c | 303 | }; |
17ed88a2 | 304 | |
cf5ef508 KB |
305 | #define ISSPACE(F, BB, C) \ |
306 | (((C)->cr_uid == 0 && (F)->lfs_bfree >= (BB)) || \ | |
17ed88a2 MS |
307 | ((C)->cr_uid != 0 && IS_FREESPACE(F, BB))) |
308 | ||
cf5ef508 | 309 | #define IS_FREESPACE(F, BB) \ |
17ed88a2 MS |
310 | ((F)->lfs_bfree > ((F)->lfs_dsize * (F)->lfs_minfree / 100 + (BB))) |
311 | ||
cf5ef508 | 312 | #define ISSPACE_XXX(F, BB) \ |
17ed88a2 MS |
313 | ((F)->lfs_bfree >= (BB)) |
314 | ||
2a04b8fe MS |
315 | #define DOSTATS |
316 | #ifdef DOSTATS | |
317 | /* Statistics Counters */ | |
318 | struct lfs_stats { | |
993707aa KM |
319 | u_int segsused; |
320 | u_int psegwrites; | |
321 | u_int psyncwrites; | |
322 | u_int pcleanwrites; | |
323 | u_int blocktot; | |
324 | u_int cleanblocks; | |
325 | u_int ncheckpoints; | |
326 | u_int nwrites; | |
327 | u_int nsync_writes; | |
328 | u_int wait_exceeded; | |
329 | u_int write_exceeded; | |
330 | u_int flush_invoked; | |
2a04b8fe MS |
331 | }; |
332 | extern struct lfs_stats lfs_stats; | |
333 | #endif |