]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/ufs/ffs/ffs_subr.c
MFV r323530,r323533,r323534: 7431 ZFS Channel Programs, and followups
[FreeBSD/FreeBSD.git] / sys / ufs / ffs / ffs_subr.c
1 /*-
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)ffs_subr.c  8.5 (Berkeley) 3/21/95
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36
37 #ifndef _KERNEL
38 #include <ufs/ufs/dinode.h>
39 #include <ufs/ffs/fs.h>
40 #else
41 #include <sys/systm.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/bio.h>
47 #include <sys/buf.h>
48 #include <sys/ucred.h>
49
50 #include <ufs/ufs/quota.h>
51 #include <ufs/ufs/inode.h>
52 #include <ufs/ufs/extattr.h>
53 #include <ufs/ufs/ufsmount.h>
54 #include <ufs/ufs/ufs_extern.h>
55 #include <ufs/ffs/ffs_extern.h>
56 #include <ufs/ffs/fs.h>
57
58 /*
59  * Return buffer with the contents of block "offset" from the beginning of
60  * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
61  * remaining space in the directory.
62  */
63 int
64 ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
65 {
66         struct inode *ip;
67         struct fs *fs;
68         struct buf *bp;
69         ufs_lbn_t lbn;
70         int bsize, error;
71
72         ip = VTOI(vp);
73         fs = ITOFS(ip);
74         lbn = lblkno(fs, offset);
75         bsize = blksize(fs, ip, lbn);
76
77         *bpp = NULL;
78         error = bread(vp, lbn, bsize, NOCRED, &bp);
79         if (error) {
80                 brelse(bp);
81                 return (error);
82         }
83         if (res)
84                 *res = (char *)bp->b_data + blkoff(fs, offset);
85         *bpp = bp;
86         return (0);
87 }
88
89 /*
90  * Load up the contents of an inode and copy the appropriate pieces
91  * to the incore copy.
92  */
93 void
94 ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
95 {
96
97         if (I_IS_UFS1(ip)) {
98                 *ip->i_din1 =
99                     *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
100                 ip->i_mode = ip->i_din1->di_mode;
101                 ip->i_nlink = ip->i_din1->di_nlink;
102                 ip->i_size = ip->i_din1->di_size;
103                 ip->i_flags = ip->i_din1->di_flags;
104                 ip->i_gen = ip->i_din1->di_gen;
105                 ip->i_uid = ip->i_din1->di_uid;
106                 ip->i_gid = ip->i_din1->di_gid;
107         } else {
108                 *ip->i_din2 =
109                     *((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
110                 ip->i_mode = ip->i_din2->di_mode;
111                 ip->i_nlink = ip->i_din2->di_nlink;
112                 ip->i_size = ip->i_din2->di_size;
113                 ip->i_flags = ip->i_din2->di_flags;
114                 ip->i_gen = ip->i_din2->di_gen;
115                 ip->i_uid = ip->i_din2->di_uid;
116                 ip->i_gid = ip->i_din2->di_gid;
117         }
118 }
119 #endif /* KERNEL */
120
121 /*
122  * Update the frsum fields to reflect addition or deletion
123  * of some frags.
124  */
125 void
126 ffs_fragacct(struct fs *fs, int fragmap, int32_t fraglist[], int cnt)
127 {
128         int inblk;
129         int field, subfield;
130         int siz, pos;
131
132         inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1;
133         fragmap <<= 1;
134         for (siz = 1; siz < fs->fs_frag; siz++) {
135                 if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
136                         continue;
137                 field = around[siz];
138                 subfield = inside[siz];
139                 for (pos = siz; pos <= fs->fs_frag; pos++) {
140                         if ((fragmap & field) == subfield) {
141                                 fraglist[siz] += cnt;
142                                 pos += siz;
143                                 field <<= siz;
144                                 subfield <<= siz;
145                         }
146                         field <<= 1;
147                         subfield <<= 1;
148                 }
149         }
150 }
151
152 /*
153  * block operations
154  *
155  * check if a block is available
156  */
157 int
158 ffs_isblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
159 {
160         unsigned char mask;
161
162         switch ((int)fs->fs_frag) {
163         case 8:
164                 return (cp[h] == 0xff);
165         case 4:
166                 mask = 0x0f << ((h & 0x1) << 2);
167                 return ((cp[h >> 1] & mask) == mask);
168         case 2:
169                 mask = 0x03 << ((h & 0x3) << 1);
170                 return ((cp[h >> 2] & mask) == mask);
171         case 1:
172                 mask = 0x01 << (h & 0x7);
173                 return ((cp[h >> 3] & mask) == mask);
174         default:
175 #ifdef _KERNEL
176                 panic("ffs_isblock");
177 #endif
178                 break;
179         }
180         return (0);
181 }
182
183 /*
184  * check if a block is free
185  */
186 int
187 ffs_isfreeblock(struct fs *fs, u_char *cp, ufs1_daddr_t h)
188 {
189  
190         switch ((int)fs->fs_frag) {
191         case 8:
192                 return (cp[h] == 0);
193         case 4:
194                 return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0);
195         case 2:
196                 return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0);
197         case 1:
198                 return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0);
199         default:
200 #ifdef _KERNEL
201                 panic("ffs_isfreeblock");
202 #endif
203                 break;
204         }
205         return (0);
206 }
207
208 /*
209  * take a block out of the map
210  */
211 void
212 ffs_clrblock(struct fs *fs, u_char *cp, ufs1_daddr_t h)
213 {
214
215         switch ((int)fs->fs_frag) {
216         case 8:
217                 cp[h] = 0;
218                 return;
219         case 4:
220                 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
221                 return;
222         case 2:
223                 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
224                 return;
225         case 1:
226                 cp[h >> 3] &= ~(0x01 << (h & 0x7));
227                 return;
228         default:
229 #ifdef _KERNEL
230                 panic("ffs_clrblock");
231 #endif
232                 break;
233         }
234 }
235
236 /*
237  * put a block into the map
238  */
239 void
240 ffs_setblock(struct fs *fs, unsigned char *cp, ufs1_daddr_t h)
241 {
242
243         switch ((int)fs->fs_frag) {
244
245         case 8:
246                 cp[h] = 0xff;
247                 return;
248         case 4:
249                 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
250                 return;
251         case 2:
252                 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
253                 return;
254         case 1:
255                 cp[h >> 3] |= (0x01 << (h & 0x7));
256                 return;
257         default:
258 #ifdef _KERNEL
259                 panic("ffs_setblock");
260 #endif
261                 break;
262         }
263 }
264
265 /*
266  * Update the cluster map because of an allocation or free.
267  *
268  * Cnt == 1 means free; cnt == -1 means allocating.
269  */
270 void
271 ffs_clusteracct(struct fs *fs, struct cg *cgp, ufs1_daddr_t blkno, int cnt)
272 {
273         int32_t *sump;
274         int32_t *lp;
275         u_char *freemapp, *mapp;
276         int i, start, end, forw, back, map, bit;
277
278         if (fs->fs_contigsumsize <= 0)
279                 return;
280         freemapp = cg_clustersfree(cgp);
281         sump = cg_clustersum(cgp);
282         /*
283          * Allocate or clear the actual block.
284          */
285         if (cnt > 0)
286                 setbit(freemapp, blkno);
287         else
288                 clrbit(freemapp, blkno);
289         /*
290          * Find the size of the cluster going forward.
291          */
292         start = blkno + 1;
293         end = start + fs->fs_contigsumsize;
294         if (end >= cgp->cg_nclusterblks)
295                 end = cgp->cg_nclusterblks;
296         mapp = &freemapp[start / NBBY];
297         map = *mapp++;
298         bit = 1 << (start % NBBY);
299         for (i = start; i < end; i++) {
300                 if ((map & bit) == 0)
301                         break;
302                 if ((i & (NBBY - 1)) != (NBBY - 1)) {
303                         bit <<= 1;
304                 } else {
305                         map = *mapp++;
306                         bit = 1;
307                 }
308         }
309         forw = i - start;
310         /*
311          * Find the size of the cluster going backward.
312          */
313         start = blkno - 1;
314         end = start - fs->fs_contigsumsize;
315         if (end < 0)
316                 end = -1;
317         mapp = &freemapp[start / NBBY];
318         map = *mapp--;
319         bit = 1 << (start % NBBY);
320         for (i = start; i > end; i--) {
321                 if ((map & bit) == 0)
322                         break;
323                 if ((i & (NBBY - 1)) != 0) {
324                         bit >>= 1;
325                 } else {
326                         map = *mapp--;
327                         bit = 1 << (NBBY - 1);
328                 }
329         }
330         back = start - i;
331         /*
332          * Account for old cluster and the possibly new forward and
333          * back clusters.
334          */
335         i = back + forw + 1;
336         if (i > fs->fs_contigsumsize)
337                 i = fs->fs_contigsumsize;
338         sump[i] += cnt;
339         if (back > 0)
340                 sump[back] -= cnt;
341         if (forw > 0)
342                 sump[forw] -= cnt;
343         /*
344          * Update cluster summary information.
345          */
346         lp = &sump[fs->fs_contigsumsize];
347         for (i = fs->fs_contigsumsize; i > 0; i--)
348                 if (*lp-- > 0)
349                         break;
350         fs->fs_maxcluster[cgp->cg_cgx] = i;
351 }